@acorex/components 22.1.0-next.9 → 22.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/fesm2022/acorex-components-alert.mjs +2 -2
  2. package/fesm2022/acorex-components-alert.mjs.map +1 -1
  3. package/fesm2022/acorex-components-audio-wave.mjs +15 -0
  4. package/fesm2022/acorex-components-audio-wave.mjs.map +1 -1
  5. package/fesm2022/acorex-components-calendar.mjs +321 -118
  6. package/fesm2022/acorex-components-calendar.mjs.map +1 -1
  7. package/fesm2022/acorex-components-combo-box.mjs +259 -37
  8. package/fesm2022/acorex-components-combo-box.mjs.map +1 -1
  9. package/fesm2022/acorex-components-conversation-acorex-components-conversation-BtkyQUlh.mjs +16548 -0
  10. package/fesm2022/acorex-components-conversation-acorex-components-conversation-BtkyQUlh.mjs.map +1 -0
  11. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-D4ca9Mvt.mjs +51 -0
  12. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-D4ca9Mvt.mjs.map +1 -0
  13. package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-QVs1XWYf.mjs +85 -0
  14. package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-QVs1XWYf.mjs.map +1 -0
  15. package/fesm2022/{acorex-components-conversation-open-composer-picker-for-files-BuNEjswI.mjs → acorex-components-conversation-open-composer-picker-for-files-BKKO_8x6.mjs} +7 -20
  16. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-BKKO_8x6.mjs.map +1 -0
  17. package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-BNKFb5yO.mjs +65 -0
  18. package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-BNKFb5yO.mjs.map +1 -0
  19. package/fesm2022/acorex-components-conversation.mjs +1 -17608
  20. package/fesm2022/acorex-components-conversation.mjs.map +1 -1
  21. package/fesm2022/acorex-components-data-table.mjs +57 -23
  22. package/fesm2022/acorex-components-data-table.mjs.map +1 -1
  23. package/fesm2022/acorex-components-decorators.mjs +2 -2
  24. package/fesm2022/acorex-components-decorators.mjs.map +1 -1
  25. package/fesm2022/acorex-components-dropdown.mjs +2 -2
  26. package/fesm2022/acorex-components-dropdown.mjs.map +1 -1
  27. package/fesm2022/acorex-components-fab.mjs +5 -5
  28. package/fesm2022/acorex-components-fab.mjs.map +1 -1
  29. package/fesm2022/acorex-components-image-editor.mjs +600 -409
  30. package/fesm2022/acorex-components-image-editor.mjs.map +1 -1
  31. package/fesm2022/acorex-components-lookup.mjs +1259 -169
  32. package/fesm2022/acorex-components-lookup.mjs.map +1 -1
  33. package/fesm2022/acorex-components-menu.mjs +11 -5
  34. package/fesm2022/acorex-components-menu.mjs.map +1 -1
  35. package/fesm2022/acorex-components-notification.mjs +6 -6
  36. package/fesm2022/acorex-components-notification.mjs.map +1 -1
  37. package/fesm2022/acorex-components-popover.mjs +33 -0
  38. package/fesm2022/acorex-components-popover.mjs.map +1 -1
  39. package/fesm2022/acorex-components-rail-navigation.mjs +2 -2
  40. package/fesm2022/acorex-components-rail-navigation.mjs.map +1 -1
  41. package/fesm2022/acorex-components-range-slider.mjs +2 -2
  42. package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
  43. package/fesm2022/acorex-components-select-box.mjs +38 -11
  44. package/fesm2022/acorex-components-select-box.mjs.map +1 -1
  45. package/fesm2022/acorex-components-tabs.mjs +2 -2
  46. package/fesm2022/acorex-components-tabs.mjs.map +1 -1
  47. package/fesm2022/acorex-components-tree-view.mjs +45 -3
  48. package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
  49. package/lookup/README.md +19 -8
  50. package/package.json +4 -3
  51. package/types/acorex-components-audio-wave.d.ts +3 -0
  52. package/types/acorex-components-calendar.d.ts +41 -9
  53. package/types/acorex-components-combo-box.d.ts +50 -10
  54. package/types/acorex-components-conversation.d.ts +1232 -1782
  55. package/types/acorex-components-data-table.d.ts +12 -2
  56. package/types/acorex-components-image-editor.d.ts +54 -49
  57. package/types/acorex-components-lookup.d.ts +286 -71
  58. package/types/acorex-components-popover.d.ts +8 -0
  59. package/types/acorex-components-select-box.d.ts +11 -0
  60. package/types/acorex-components-tree-view.d.ts +11 -1
  61. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs +0 -50
  62. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs.map +0 -1
  63. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-BuNEjswI.mjs.map +0 -1
@@ -1,23 +1,28 @@
1
1
  import * as _acorex_components_conversation from '@acorex/components/conversation';
2
2
  import * as _angular_core from '@angular/core';
3
- import { OnDestroy, ViewContainerRef, Type, InputSignal, WritableSignal, Signal, Provider, OnInit, EventEmitter, TemplateRef, InjectionToken, ModuleWithProviders } from '@angular/core';
4
- import { AXComponentCloseEvent, AXHtmlEvent, AXClickEvent, AXDataSource, AXPlacement, AXClosableComponent } from '@acorex/cdk/common';
3
+ import { OnDestroy, ViewContainerRef, Type, InputSignal, WritableSignal, Signal, Provider, OnInit, EventEmitter, TemplateRef, InjectionToken, ElementRef, ModuleWithProviders } from '@angular/core';
4
+ import { AXComponentCloseEvent, AXHtmlEvent, AXClickEvent, AXDataSource, AXPlacement } from '@acorex/cdk/common';
5
+ import { AXTranslationService } from '@acorex/core/translation';
6
+ import * as _acorex_components_action_sheet from '@acorex/components/action-sheet';
7
+ import { AXActionSheetRef } from '@acorex/components/action-sheet';
5
8
  import * as _acorex_components_popup from '@acorex/components/popup';
6
9
  import { AXPopupService, AXPopupRef } from '@acorex/components/popup';
7
10
  import { AXFileUploadOptions, AXUploadResult, AXUploadReference, AXUploaderService, AXUploaderFileChangeEvent } from '@acorex/cdk/uploader';
8
11
  import { AXListComponent } from '@acorex/components/list';
9
12
  import * as rxjs from 'rxjs';
10
- import { Observable, BehaviorSubject, Subject } from 'rxjs';
13
+ import { Observable } from 'rxjs';
11
14
  import { AXDialogService } from '@acorex/components/dialog';
12
15
  import { AXContextMenuOpeningEvent, AXContextMenuItemsClickEvent } from '@acorex/components/menu';
16
+ import { AXTabLocation } from '@acorex/components/tabs';
13
17
  import { AXBasePageComponent } from '@acorex/components/page';
14
18
  import * as _acorex_core_file from '@acorex/core/file';
15
- import { AXFileTypeInfoProvider, AXFileType, AXFileService, AXFileTypeRegistryService, AXFileTypeExtensionHint, AXFileTypeOpenContext } from '@acorex/core/file';
16
- import { AXTranslationService } from '@acorex/core/translation';
19
+ import { AXFileTypeRegistryService, AXFileTypeExtensionHint, AXFileTypeOpenContext, AXFileTypeInfoProvider, AXFileType, AXFileService } from '@acorex/core/file';
17
20
  import { AXToastService } from '@acorex/components/toast';
18
21
  import { AXValidationRuleResult } from '@acorex/core/validation';
19
22
  import { AXMapMarker } from '@acorex/components/map';
23
+ import { AXRangeSliderValue } from '@acorex/components/range-slider';
20
24
  import { SafeHtml } from '@angular/platform-browser';
25
+ import { AXWaveConfig, AXAudioWaveChangeEvent } from '@acorex/components/audio-wave';
21
26
  import * as i1 from '@angular/common';
22
27
  import * as i2 from '@angular/forms';
23
28
 
@@ -26,6 +31,7 @@ declare class AXConversationComposerPopupComponent implements OnDestroy {
26
31
  private get registry();
27
32
  contentContainer: _angular_core.Signal<ViewContainerRef>;
28
33
  private currentComponentRef;
34
+ private tabItemSelectedSubscription;
29
35
  /** Popup open state (for backward compatibility) */
30
36
  readonly isOpen: _angular_core.InputSignal<boolean>;
31
37
  /** Close event (for backward compatibility) */
@@ -52,6 +58,7 @@ declare class AXConversationComposerPopupComponent implements OnDestroy {
52
58
  }): void;
53
59
  /** Load tab content component */
54
60
  private loadTabContent;
61
+ private clearTabContent;
55
62
  ngOnDestroy(): void;
56
63
  /** Close popup (for backward compatibility) */
57
64
  close(): void;
@@ -375,12 +382,31 @@ interface AXConversationDeleteMessageCommand {
375
382
  forEveryone?: boolean;
376
383
  }
377
384
 
385
+ /**
386
+ * Per-user preferences for a specific conversation (mute, notifications, etc.).
387
+ * Stored on the user account, keyed by conversation ID — not on the room entity.
388
+ */
389
+ interface AXConversationRoomPreferences {
390
+ /** Muted until timestamp */
391
+ mutedUntil?: Date;
392
+ /** Show notifications for this conversation */
393
+ notifications: boolean;
394
+ /** Custom notification sound */
395
+ notificationSound?: string;
396
+ /** Show message preview in notifications */
397
+ showPreview: boolean;
398
+ /** Custom settings */
399
+ custom?: Record<string, unknown>;
400
+ }
401
+ declare const AX_CONVERSATION_DEFAULT_ROOM_PREFERENCES: AXConversationRoomPreferences;
402
+ /** Map of conversation ID → user-specific room preferences. */
403
+ type AXConversationRoomPreferencesMap = Record<string, AXConversationRoomPreferences>;
404
+
378
405
  /**
379
406
  * Participant Model
380
- * Represents a user/member in a conversation
407
+ * Membership in a conversation (identity fields are snapshots; live presence is on the user store).
381
408
  */
382
- type AXConversationParticipantRole = 'admin' | 'moderator' | 'member';
383
- type AXConversationParticipantStatus = 'online' | 'offline' | 'away';
409
+ type AXConversationParticipantRole = 'owner' | 'admin' | 'moderator' | 'member' | 'guest';
384
410
  /** Extended profile fields shown in private-chat info panels. */
385
411
  interface AXConversationUserProfile {
386
412
  bio?: string;
@@ -391,6 +417,18 @@ interface AXConversationUserProfile {
391
417
  company?: string;
392
418
  title?: string;
393
419
  }
420
+ /** Authenticated user profile (includes per-room preferences). */
421
+ interface AXConversationUser {
422
+ id: string;
423
+ name: string;
424
+ description?: string;
425
+ profile?: AXConversationUserProfile;
426
+ avatar?: string;
427
+ icon?: string;
428
+ metadata?: Record<string, unknown>;
429
+ /** User-specific settings per conversation (key = conversationId). */
430
+ conversationPreferences?: AXConversationRoomPreferencesMap;
431
+ }
394
432
  interface AXConversationParticipant {
395
433
  /** Unique identifier for the participant */
396
434
  id: string;
@@ -411,10 +449,6 @@ interface AXConversationParticipant {
411
449
  icon?: string;
412
450
  /** Role in the conversation (for groups/channels) */
413
451
  role?: AXConversationParticipantRole;
414
- /** Current online status */
415
- status?: AXConversationParticipantStatus;
416
- /** Last seen timestamp (when offline/away) */
417
- lastSeen?: Date;
418
452
  /** Custom metadata */
419
453
  metadata?: Record<string, unknown>;
420
454
  }
@@ -425,34 +459,6 @@ interface AXConversationParticipant {
425
459
  */
426
460
 
427
461
  type AXConversationType = 'private' | 'group' | 'channel' | 'bot';
428
- /**
429
- * Conversation status information
430
- */
431
- interface AXConversationStatus {
432
- /** Whether someone is typing */
433
- isTyping: boolean;
434
- /** User IDs currently typing */
435
- typingUsers: string[];
436
- /** Online presence (for private chats) */
437
- presence?: 'online' | 'offline' | 'away';
438
- /** Last seen timestamp (for private chats when offline) */
439
- lastSeen?: Date;
440
- }
441
- /**
442
- * Conversation settings
443
- */
444
- interface AXConversationSettings {
445
- /** Muted until timestamp */
446
- mutedUntil?: Date;
447
- /** Show notifications */
448
- notifications: boolean;
449
- /** Custom notification sound */
450
- notificationSound?: string;
451
- /** Show message preview in notifications */
452
- showPreview: boolean;
453
- /** Custom settings */
454
- custom?: Record<string, unknown>;
455
- }
456
462
  /** Theme-specific CSS `background` values for the message list area. */
457
463
  interface AXConversationMessageListThemeBackground {
458
464
  light: string;
@@ -510,10 +516,6 @@ interface AXConversation {
510
516
  unreadCount: number;
511
517
  /** Number of unread mentions */
512
518
  unreadMentions?: number;
513
- /** Current status (typing, presence, etc.) */
514
- status: AXConversationStatus;
515
- /** User-specific settings */
516
- settings: AXConversationSettings;
517
519
  /** Pinned messages IDs */
518
520
  pinnedMessageIds?: string[];
519
521
  /** Conversation creation timestamp */
@@ -526,13 +528,11 @@ interface AXConversation {
526
528
  pinned?: boolean;
527
529
  /** Whether conversation is archived */
528
530
  archived?: boolean;
529
- /** Draft message text */
530
- draft?: string;
531
531
  /** Custom metadata */
532
532
  metadata?: AXConversationMetadata;
533
533
  }
534
534
  /**
535
- * Typing indicator
535
+ * Typing indicator (realtime event — ephemeral, not stored on the room entity).
536
536
  */
537
537
  interface AXConversationTypingIndicator {
538
538
  /** Conversation ID */
@@ -543,19 +543,8 @@ interface AXConversationTypingIndicator {
543
543
  userName?: string;
544
544
  /** Timestamp */
545
545
  timestamp: Date;
546
- }
547
- /**
548
- * Presence update
549
- */
550
- interface AXConversationPresenceUpdate {
551
- /** User ID */
552
- userId: string;
553
- /** Presence status */
554
- status: 'online' | 'offline' | 'away';
555
- /** Last seen timestamp */
556
- lastSeen?: Date;
557
- /** Custom status text */
558
- statusText?: string;
546
+ /** When false, user stopped typing */
547
+ isTyping?: boolean;
559
548
  }
560
549
  /**
561
550
  * Conversation filter options
@@ -595,6 +584,26 @@ declare const AX_CONVERSATION_MESSAGE_TYPE_FILE_TYPE: Partial<Record<AXConversat
595
584
  /** Resolves {@link AXConversationMessage.fileType} from command or message type. */
596
585
  declare function resolveConversationMessageFileType(type: AXConversationMessageType, fileType?: string): string | undefined;
597
586
 
587
+ /**
588
+ * User presence — global per-user live state (not room-scoped).
589
+ */
590
+ type AXConversationPresenceStatus = 'online' | 'offline' | 'away' | 'busy';
591
+ /** Live presence for a single user. */
592
+ interface AXConversationUserPresence {
593
+ userId: string;
594
+ status: AXConversationPresenceStatus;
595
+ lastSeen?: Date;
596
+ statusText?: string;
597
+ updatedAt?: Date;
598
+ }
599
+ /** Realtime / API presence event payload. */
600
+ interface AXConversationPresenceUpdate {
601
+ userId: string;
602
+ status: AXConversationPresenceStatus;
603
+ lastSeen?: Date;
604
+ statusText?: string;
605
+ }
606
+
598
607
  /**
599
608
  * Abstract Base Registry
600
609
  * Base class for all registries with common functionality
@@ -673,22 +682,15 @@ declare abstract class AXConversationBaseRegistry<T extends AXConversationRegist
673
682
  protected abstract getRegistryName(): string;
674
683
  }
675
684
 
676
- /**
677
- * Active component state in composer
678
- */
679
- interface AXConversationComposerActiveComponent {
680
- /** Action that triggered this component */
681
- action: AXConversationComposerAction;
682
- /** Component to render */
683
- component?: Type<unknown>;
684
- /** Lazy loader for the component */
685
- componentLoader?: () => Promise<Type<unknown>>;
686
- /** Component inputs */
687
- inputs?: Record<string, unknown>;
688
- }
685
+ /** Primary composer button mode (send / cancel / stopping / default action / locked). */
686
+ type AXConversationComposerPrimaryButtonMode = 'send' | 'cancel' | 'stopping' | 'default-action' | 'locked';
689
687
  declare class AXConversationComposerService {
690
688
  private readonly conversationService;
689
+ private readonly generationState;
691
690
  private readonly translation;
691
+ private readonly popupService;
692
+ private readonly config;
693
+ private readonly _activeActionOverlay;
692
694
  private get registry();
693
695
  private readonly _replyMessage;
694
696
  private readonly _editMessage;
@@ -696,15 +698,10 @@ declare class AXConversationComposerService {
696
698
  readonly editMessage: _angular_core.Signal<AXConversationMessage>;
697
699
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
698
700
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
699
- /** Active component being shown in composer (full-width mode) */
700
- private readonly _activeComponent;
701
- readonly activeComponent: _angular_core.Signal<AXConversationComposerActiveComponent>;
702
701
  /** Draft text */
703
702
  readonly draftText: _angular_core.WritableSignal<string>;
704
703
  /** Attachments */
705
704
  readonly attachments: _angular_core.WritableSignal<File[]>;
706
- /** Show typing indicator */
707
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
708
705
  /** Incremented to request focus on the composer text area (handled by AXConversationComposerComponent). */
709
706
  private readonly _focusRequest;
710
707
  readonly focusRequest: _angular_core.Signal<number>;
@@ -712,8 +709,14 @@ declare class AXConversationComposerService {
712
709
  readonly placeholder: _angular_core.Signal<string>;
713
710
  /** Number of input rows */
714
711
  readonly inputRows: _angular_core.Signal<number>;
715
- /** Can send message */
712
+ /** Can send message (draft has content; does not include generation state). */
716
713
  readonly canSend: _angular_core.Signal<boolean>;
714
+ /** Whether a background generation (e.g. AI response) is in progress. */
715
+ readonly isGenerating: _angular_core.Signal<boolean>;
716
+ /** Whether cancel cleanup is in progress (spinner on primary button). */
717
+ readonly isStopping: _angular_core.Signal<boolean>;
718
+ /** Primary end-button mode for send / cancel / stopping / voice / locked. */
719
+ readonly primaryButtonMode: _angular_core.Signal<AXConversationComposerPrimaryButtonMode>;
717
720
  /** Composer action context */
718
721
  readonly actionContext: _angular_core.Signal<AXConversationComposerActionContext>;
719
722
  /** Start actions from registry */
@@ -730,6 +733,7 @@ declare class AXConversationComposerService {
730
733
  readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
731
734
  /** Default end action (voice/send morph button) */
732
735
  readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
736
+ cancelGeneration(): void;
733
737
  startReply(message: AXConversationMessage): void;
734
738
  startEdit(message: AXConversationMessage): void;
735
739
  /** Focus the composer text area when the composer component is mounted. */
@@ -746,17 +750,16 @@ declare class AXConversationComposerService {
746
750
  */
747
751
  clearComposerInput(conversationId?: string): void;
748
752
  /**
749
- * Show a component in the composer (full-width mode)
753
+ * Open a composer action component in a popup (desktop) or action sheet (mobile).
750
754
  */
751
- showComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>): void;
755
+ openActionComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>, options?: {
756
+ toggleable?: boolean;
757
+ initialFiles?: File[];
758
+ }): Promise<void>;
752
759
  /**
753
- * Hide the active component
760
+ * Hide the active action overlay.
754
761
  */
755
762
  hideComponent(): void;
756
- /**
757
- * Toggle component visibility
758
- */
759
- toggleComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>): void;
760
763
  /**
761
764
  * Get actions for the active conversation
762
765
  */
@@ -797,6 +800,10 @@ interface AXConversationComposerActionContext {
797
800
  isReplying: boolean;
798
801
  /** Message being replied to (if any) */
799
802
  replyingToMessageId?: string;
803
+ /** Whether a background generation (e.g. AI response) is in progress */
804
+ isGenerating?: boolean;
805
+ /** Whether cancel cleanup is in progress */
806
+ isStopping?: boolean;
800
807
  /** Custom context data */
801
808
  custom?: Record<string, unknown>;
802
809
  }
@@ -813,6 +820,15 @@ interface AXConversationComposerActionComponent {
813
820
  readonly initialFiles?: InputSignal<File[]>;
814
821
  /** Set by {@link AXPopupService} when the picker is shown in a popup. */
815
822
  readonly __popup__?: InputSignal<_acorex_components_popup.AXPopupRef | undefined>;
823
+ /** Set by {@link AXActionSheetService} when the picker is shown in an action sheet. */
824
+ readonly __actionSheet__?: InputSignal<_acorex_components_action_sheet.AXActionSheetRef | undefined>;
825
+ /**
826
+ * When true (from action {@link AXConversationComposerAction.autoRun}), runs {@link activate}
827
+ * once after the component is mounted.
828
+ */
829
+ readonly autoRun?: InputSignal<boolean>;
830
+ /** Primary action when opened from the composer (record, browse files, etc.). */
831
+ activate?(): void | Promise<void>;
816
832
  /** Cancel in-flight uploads when the picker is closed or replaced. */
817
833
  abortInProgressUploads?(): void;
818
834
  }
@@ -848,6 +864,11 @@ interface AXConversationComposerAction extends Omit<AXConversationRegistryItem,
848
864
  * Whether this action is toggleable (shows/hides component)
849
865
  */
850
866
  toggleable?: boolean;
867
+ /**
868
+ * When true, runs {@link AXConversationComposerActionComponent.activate} in
869
+ * {@link afterNextRender} after the upload panel is mounted.
870
+ */
871
+ autoRun?: boolean;
851
872
  /** Action handler (optional if component is provided) */
852
873
  handler?: (context: AXConversationComposerActionContext) => void | Promise<void>;
853
874
  /** Tooltip text */
@@ -1237,6 +1258,7 @@ declare class AXConversationMessageRendererRegistry {
1237
1258
  private readonly _composerActions;
1238
1259
  constructor();
1239
1260
  private registerBuiltInRenderers;
1261
+ private registerBuiltInRendererIfMissing;
1240
1262
  /** All registered renderers */
1241
1263
  readonly renderers: Signal<AXConversationMessageRenderer[]>;
1242
1264
  /** Renderers sorted by priority (highest first) */
@@ -1326,10 +1348,6 @@ declare class AXConversationInfoBarService {
1326
1348
  * Reset info-bar overlays when the active conversation changes.
1327
1349
  */
1328
1350
  onConversationChanged(): void;
1329
- /**
1330
- * Open the Telegram-style conversation info panel for the active (or given) conversation.
1331
- */
1332
- openConversationInfoPanel(conversation?: AXConversation): Promise<void>;
1333
1351
  /**
1334
1352
  * Get actions for the active conversation
1335
1353
  */
@@ -1433,7 +1451,7 @@ interface AXConversationInfoBarAction extends AXConversationRegistryItem {
1433
1451
  /** Whether this is a divider */
1434
1452
  divider?: boolean;
1435
1453
  /** Display location: 'inline' for toolbar buttons, 'menu' for dropdown menu */
1436
- location?: 'inline' | 'menu';
1454
+ location?: 'inline' | 'menu' | ((context: AXConversationInfoBarActionContext) => 'inline' | 'menu');
1437
1455
  /**
1438
1456
  * Component to show when action is activated (for inline actions)
1439
1457
  * If provided, clicking the action will show this component in the info-bar
@@ -1483,6 +1501,10 @@ declare class AXConversationInfoBarActionRegistry extends AXConversationBaseRegi
1483
1501
  * Get actions for a specific conversation
1484
1502
  */
1485
1503
  getActionsForConversation(conversation: AXConversation, location?: 'inline' | 'menu'): AXConversationInfoBarAction[];
1504
+ /**
1505
+ * Resolve the display location for an action (supports dynamic location factories).
1506
+ */
1507
+ getActionLocation(action: AXConversationInfoBarAction, conversation: AXConversation): 'inline' | 'menu' | undefined;
1486
1508
  /**
1487
1509
  * Get inline actions (toolbar buttons)
1488
1510
  */
@@ -1600,12 +1622,11 @@ declare class AXConversationMessageActionRegistry {
1600
1622
  }
1601
1623
 
1602
1624
  declare class AXConversationComposerComponent implements OnDestroy {
1603
- #private;
1604
1625
  private readonly conversationService;
1605
1626
  private readonly composerService;
1606
1627
  private readonly messageListService;
1607
1628
  private readonly config;
1608
- private readonly translation;
1629
+ protected readonly translation: AXTranslationService;
1609
1630
  /** Access registry through conversation service */
1610
1631
  protected get composerActionRegistry(): _acorex_components_conversation.AXConversationComposerActionRegistry;
1611
1632
  /** Composer text area reference */
@@ -1618,10 +1639,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1618
1639
  readonly editingMessage: _angular_core.WritableSignal<any>;
1619
1640
  /** Replying to message */
1620
1641
  readonly replyingToMessage: _angular_core.WritableSignal<AXConversationMessage>;
1621
- /** Show typing indicator - use service */
1622
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
1623
1642
  /** Message sent event */
1624
1643
  readonly messageSent: _angular_core.OutputEmitterRef<AXConversationSendMessageCommand>;
1644
+ /** Emitted when the user cancels an in-progress generation from the composer. */
1645
+ readonly generationCancelled: _angular_core.OutputEmitterRef<void>;
1625
1646
  /** Emoji clicked event */
1626
1647
  readonly emojiClick: _angular_core.OutputEmitterRef<void>;
1627
1648
  /** Attach clicked event */
@@ -1631,25 +1652,29 @@ declare class AXConversationComposerComponent implements OnDestroy {
1631
1652
  /** Active conversation */
1632
1653
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
1633
1654
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
1634
- /** Active component from service */
1635
- readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerActiveComponent>;
1636
1655
  /** Emoji popover state */
1637
1656
  private readonly emojiPopoverRef;
1638
1657
  readonly emojiPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1639
1658
  /** Attachment menu popover state */
1640
1659
  private readonly attachPopoverRef;
1641
- readonly attachPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1660
+ private readonly attachMenuButtonRef;
1661
+ readonly attachMenuTarget: _angular_core.Signal<HTMLElement>;
1662
+ private attachMenuCloseTimer?;
1642
1663
  readonly composerPopupLoader: () => Promise<typeof _acorex_components_conversation.AXConversationComposerPopupComponent>;
1643
1664
  /** Input placeholder - use service */
1644
1665
  readonly placeholder: _angular_core.Signal<string>;
1645
- /** Typing indicator subject for rate limiting */
1646
- private readonly typingSubject;
1647
1666
  constructor();
1648
1667
  private draftSaveTimeout?;
1649
1668
  /** Number of input rows - use service */
1650
1669
  readonly inputRows: _angular_core.Signal<number>;
1651
1670
  /** Can send message - use service */
1652
1671
  readonly canSend: _angular_core.Signal<boolean>;
1672
+ /** Whether AI/generation is in progress */
1673
+ readonly isGenerating: _angular_core.Signal<boolean>;
1674
+ /** Whether cancel cleanup is in progress */
1675
+ readonly isStopping: _angular_core.Signal<boolean>;
1676
+ /** Primary button mode */
1677
+ readonly primaryButtonMode: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerPrimaryButtonMode>;
1653
1678
  /** Start actions from registry - use service */
1654
1679
  readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
1655
1680
  /** End actions from registry - use service */
@@ -1664,12 +1689,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1664
1689
  readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1665
1690
  /** Default end action (voice/send morph) */
1666
1691
  readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
1667
- /** Handle key down */
1692
+ /** Handle key down (send on Enter; typing is driven by draft changes only). */
1668
1693
  onKeyDown(event: AXHtmlEvent<KeyboardEvent>): void;
1669
- /** Handle input */
1670
- onInput(): void;
1671
- /** Send typing indicator (throttled via RxJS) */
1672
- private sendTypingIndicator;
1694
+ /** Handle draft text changes — throttled typing indicator via conversation service. */
1695
+ onDraftChanged(): void;
1673
1696
  /** Cleanup on destroy */
1674
1697
  ngOnDestroy(): void;
1675
1698
  /** Handle send click */
@@ -1684,15 +1707,25 @@ declare class AXConversationComposerComponent implements OnDestroy {
1684
1707
  private sendSticker;
1685
1708
  /** Get inputs for emoji popup component */
1686
1709
  getEmojiPopupInputs(): Record<string, unknown>;
1710
+ /** Handle attach menu hover */
1711
+ onAttachMenuMouseEnter(): void;
1712
+ onAttachMenuMouseLeave(): void;
1713
+ onAttachMenuPanelMouseEnter(): void;
1714
+ onAttachMenuPanelMouseLeave(): void;
1715
+ private scheduleAttachMenuClose;
1716
+ private clearAttachMenuCloseTimer;
1687
1717
  /** Handle attach menu click */
1688
1718
  onAttachMenuClick(event: AXClickEvent): void;
1689
- /** Handle attachment popover closed */
1690
- onAttachPopoverClosed(): void;
1691
1719
  /** Handle attachment menu action selection */
1692
1720
  onAttachMenuAction(actionId: string): Promise<void>;
1693
- /** Handle default action click (voice when empty, send when has content) */
1721
+ /** Handle primary button click (send / cancel / stopping / voice / locked). */
1722
+ onPrimaryButtonClick(): Promise<void>;
1723
+ /** @deprecated Use onPrimaryButtonClick */
1694
1724
  onDefaultActionClick(): Promise<void>;
1695
- /** Icon for the default morph button */
1725
+ getPrimaryButtonIcon(): string;
1726
+ getPrimaryButtonLabel(): string;
1727
+ isPrimaryButtonDisabled(): boolean;
1728
+ /** @deprecated Use getPrimaryButtonIcon */
1696
1729
  getDefaultActionIcon(): string;
1697
1730
  /** Handle voice click */
1698
1731
  onVoiceClick(): void;
@@ -1708,7 +1741,7 @@ declare class AXConversationComposerComponent implements OnDestroy {
1708
1741
  private focusTextArea;
1709
1742
  private getClickTarget;
1710
1743
  /** Handle action click */
1711
- onActionClick(actionId: string, event?: AXClickEvent | MouseEvent): Promise<void>;
1744
+ onActionClick(actionId: string, event?: AXClickEvent | MouseEvent, initialFiles?: File[]): Promise<void>;
1712
1745
  /** Check if action is enabled */
1713
1746
  isActionEnabled(action: any): boolean;
1714
1747
  /** Get replying sender name */
@@ -1739,13 +1772,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1739
1772
  }): string;
1740
1773
  /** Handle reply preview click - scroll to original message */
1741
1774
  onReplyPreviewClick(): void;
1742
- /** Inputs for picker / full-width composer components */
1775
+ /** Inputs for picker components opened in popup / action sheet */
1743
1776
  private buildPickerInputs;
1744
- /** Get inputs for dynamic component */
1745
- getComponentInputs(): Record<string, unknown>;
1746
- onEnter(event: AXHtmlEvent<KeyboardEvent>): Promise<void>;
1747
1777
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerComponent, never>;
1748
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationComposerComponent, "ax-conversation-composer", never, {}, { "messageSent": "messageSent"; "emojiClick": "emojiClick"; "attachClick": "attachClick"; "voiceClick": "voiceClick"; }, never, never, true, never>;
1778
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationComposerComponent, "ax-conversation-composer", never, {}, { "messageSent": "messageSent"; "generationCancelled": "generationCancelled"; "emojiClick": "emojiClick"; "attachClick": "attachClick"; "voiceClick": "voiceClick"; }, never, never, true, never>;
1749
1779
  }
1750
1780
 
1751
1781
  declare class AXConversationContainerComponent {
@@ -1754,6 +1784,8 @@ declare class AXConversationContainerComponent {
1754
1784
  private readonly fileService;
1755
1785
  private readonly translation;
1756
1786
  private readonly toast;
1787
+ private readonly platform;
1788
+ private readonly actionSheetService;
1757
1789
  private readonly hostRef;
1758
1790
  private readonly platformId;
1759
1791
  protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
@@ -1787,6 +1819,8 @@ declare class AXConversationContainerDirective {
1787
1819
  private readonly platformId;
1788
1820
  private readonly translation;
1789
1821
  private readonly toast;
1822
+ private readonly platform;
1823
+ private readonly actionSheetService;
1790
1824
  private readonly config;
1791
1825
  constructor();
1792
1826
  private get registry();
@@ -1814,62 +1848,52 @@ interface AXConversationDropdownMenuItem {
1814
1848
  declare class AXConversationInfoBarComponent {
1815
1849
  private readonly conversationService;
1816
1850
  private readonly infoBar;
1851
+ private readonly platform;
1852
+ private readonly destroyRef;
1817
1853
  private readonly customUserAvatarComponent;
1854
+ private readonly layoutTick;
1855
+ constructor();
1818
1856
  protected get registry(): _acorex_components_conversation.AXConversationRegistryService;
1819
- /** Whether a custom user avatar component is registered via conversation config. */
1820
1857
  readonly hasCustomUserAvatar: _angular_core.Signal<boolean>;
1821
- /** Active conversation */
1822
1858
  readonly activeConversation: _angular_core.Signal<AXConversation>;
1823
- /** Active component from service */
1824
1859
  readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveComponent>;
1825
- /** Active banner from service */
1826
1860
  readonly activeBanner: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveBanner>;
1827
- /** Members popover target element — retained for API compatibility */
1861
+ readonly bannerInputs: _angular_core.Signal<{}>;
1828
1862
  readonly membersPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1829
- /** Loading state for async actions */
1830
1863
  readonly actionLoading: _angular_core.WritableSignal<boolean>;
1831
- /** Info area clicked — opens conversation profile panel */
1832
1864
  readonly infoClick: _angular_core.OutputEmitterRef<void>;
1833
- /** @deprecated Use infoClick — kept for backward compatibility */
1834
- readonly avatarClick: _angular_core.OutputEmitterRef<void>;
1835
- /** Search clicked event */
1836
1865
  readonly searchClick: _angular_core.OutputEmitterRef<void>;
1837
- /** Search query changed event */
1838
1866
  readonly searchQuery: _angular_core.OutputEmitterRef<string>;
1839
- /** Menu item clicked event */
1840
1867
  readonly menuItemAction: _angular_core.OutputEmitterRef<string>;
1841
- /** Inline action buttons from registry */
1842
- readonly inlineActions: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarAction[]>;
1843
- /** Dropdown menu items from registry */
1868
+ readonly inlineActions: _angular_core.Signal<AXConversationInfoBarAction[]>;
1844
1869
  readonly menuItems: _angular_core.Signal<AXConversationDropdownMenuItem[]>;
1845
- /** Get conversation status - delegate to utils */
1846
- getStatus(conversation: AXConversation): 'online' | 'offline' | 'away' | undefined;
1847
- /** Get subtitle text - delegate to utils */
1870
+ getStatus(conversation: AXConversation): _acorex_components_conversation.AXConversationPresenceStatus;
1848
1871
  getSubtitle(conversation: AXConversation): string;
1849
- /** Open conversation info panel when the left info area is clicked */
1872
+ isTyping(conversation: AXConversation): boolean;
1850
1873
  onInfoLeftClick(): void;
1851
- /** Handle inline action click */
1852
1874
  onInlineActionClick(actionId: string): Promise<void>;
1853
- /** Get inputs for dynamic component */
1875
+ private activateAction;
1854
1876
  getComponentInputs(): Record<string, unknown>;
1855
1877
  getInlineComponentInputs(): Record<string, unknown>;
1856
1878
  isActiveComponentFullWidth(): boolean;
1857
- /** Handle close component */
1858
1879
  onCloseComponent(): void;
1859
- getBannerInputs(): Record<string, unknown>;
1860
1880
  onCloseBanner(): void;
1861
- /** Handle menu item click */
1862
1881
  onMenuItemClick(item: AXConversationDropdownMenuItem): Promise<void>;
1863
1882
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoBarComponent, never>;
1864
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoBarComponent, "ax-conversation-info-bar", never, {}, { "infoClick": "infoClick"; "avatarClick": "avatarClick"; "searchClick": "searchClick"; "searchQuery": "searchQuery"; "menuItemAction": "menuItemAction"; }, never, ["ax-prefix"], true, never>;
1883
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoBarComponent, "ax-conversation-info-bar", never, {}, { "infoClick": "infoClick"; "searchClick": "searchClick"; "searchQuery": "searchQuery"; "menuItemAction": "menuItemAction"; }, never, ["ax-prefix"], true, never>;
1865
1884
  }
1866
1885
 
1867
1886
  /**
1887
+
1868
1888
  * Shared API Types
1889
+
1869
1890
  * Common types used across all API services
1891
+
1870
1892
  */
1871
1893
  /**
1894
+
1872
1895
  * Pagination parameters
1896
+
1873
1897
  */
1874
1898
  interface AXConversationPagination {
1875
1899
  /** Page number (0-based) */
@@ -1884,7 +1908,9 @@ interface AXConversationPagination {
1884
1908
  sortDirection?: 'asc' | 'desc';
1885
1909
  }
1886
1910
  /**
1911
+
1887
1912
  * Paginated response
1913
+
1888
1914
  */
1889
1915
  interface AXConversationPaginatedResult<T> {
1890
1916
  /** Result items */
@@ -1903,7 +1929,9 @@ interface AXConversationPaginatedResult<T> {
1903
1929
  totalPages?: number;
1904
1930
  }
1905
1931
  /**
1932
+
1906
1933
  * Pagination cursor state for a single list (conversations or messages).
1934
+
1907
1935
  */
1908
1936
  interface AXConversationPaginationState {
1909
1937
  page: number;
@@ -1911,11 +1939,15 @@ interface AXConversationPaginationState {
1911
1939
  nextCursor?: string;
1912
1940
  }
1913
1941
  /**
1942
+
1914
1943
  * Connection status
1944
+
1915
1945
  */
1916
1946
  type AXConversationConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
1917
1947
  /**
1948
+
1918
1949
  * API Error with details
1950
+
1919
1951
  */
1920
1952
  interface AXConversationApiError {
1921
1953
  /** Error code */
@@ -1929,14 +1961,6 @@ interface AXConversationApiError {
1929
1961
  /** Timestamp */
1930
1962
  timestamp?: Date;
1931
1963
  }
1932
- /**
1933
- * User presence status
1934
- */
1935
- type AXConversationPresenceStatus = 'online' | 'offline' | 'away' | 'busy' | 'invisible';
1936
- /**
1937
- * User role in conversation
1938
- */
1939
- type AXConversationUserRole = 'owner' | 'admin' | 'member' | 'guest';
1940
1964
 
1941
1965
  type AXConversationApiName = 'userApi' | 'conversationApi' | 'messageApi' | 'realtimeApi';
1942
1966
  interface AXConversationApiLogEntry {
@@ -1956,11 +1980,6 @@ declare class AXConversationApiLoggerService {
1956
1980
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationApiLoggerService>;
1957
1981
  }
1958
1982
 
1959
- /**
1960
- * Abstract Conversation Management API
1961
- * Handle conversation CRUD operations, participants, and settings
1962
- */
1963
-
1964
1983
  /**
1965
1984
  * Conversation creation data
1966
1985
  */
@@ -2028,20 +2047,9 @@ interface AXConversationFilters {
2028
2047
  custom?: Record<string, unknown>;
2029
2048
  }
2030
2049
  /**
2031
- * Conversation settings update
2050
+ * @deprecated Use {@link AXConversationRoomPreferences} on the user API instead.
2032
2051
  */
2033
- interface AXConversationSettingsUpdate {
2034
- /** Muted until timestamp */
2035
- mutedUntil?: Date;
2036
- /** Show notifications */
2037
- notifications?: boolean;
2038
- /** Custom notification sound */
2039
- notificationSound?: string;
2040
- /** Show message preview in notifications */
2041
- showPreview?: boolean;
2042
- /** Custom settings */
2043
- custom?: Record<string, unknown>;
2044
- }
2052
+ type AXConversationSettingsUpdate = AXConversationRoomPreferences;
2045
2053
  /**
2046
2054
  * Participant update data
2047
2055
  */
@@ -2049,7 +2057,7 @@ interface AXConversationParticipantUpdate {
2049
2057
  /** User ID */
2050
2058
  userId: string;
2051
2059
  /** New role */
2052
- role?: AXConversationUserRole;
2060
+ role?: AXConversationParticipantRole;
2053
2061
  }
2054
2062
  /**
2055
2063
  * Abstract Conversation Management API
@@ -2150,13 +2158,6 @@ declare abstract class AXConversationApi {
2150
2158
  * @throws {AXConversationApiError} If marking fails
2151
2159
  */
2152
2160
  abstract markConversationAsRead(conversationId: string): Promise<void>;
2153
- /**
2154
- * Mark conversation as unread
2155
- *
2156
- * @param conversationId - Conversation ID
2157
- * @throws {AXConversationApiError} If marking fails
2158
- */
2159
- abstract markConversationAsUnread(conversationId: string): Promise<void>;
2160
2161
  /**
2161
2162
  * Search conversations
2162
2163
  *
@@ -2216,37 +2217,6 @@ declare abstract class AXConversationApi {
2216
2217
  * @throws {AXConversationApiError} If update fails
2217
2218
  */
2218
2219
  abstract updateParticipant(conversationId: string, update: AXConversationParticipantUpdate): Promise<AXConversation>;
2219
- /**
2220
- * Get conversation settings
2221
- *
2222
- * @param conversationId - Conversation ID
2223
- * @returns Conversation settings
2224
- * @throws {AXConversationApiError} If request fails
2225
- */
2226
- abstract getConversationSettings(conversationId: string): Promise<AXConversationSettingsUpdate>;
2227
- /**
2228
- * Update conversation settings
2229
- *
2230
- * @param conversationId - Conversation ID
2231
- * @param settings - Settings to update
2232
- * @throws {AXConversationApiError} If update fails
2233
- */
2234
- abstract updateConversationSettings(conversationId: string, settings: AXConversationSettingsUpdate): Promise<void>;
2235
- /**
2236
- * Mute conversation
2237
- *
2238
- * @param conversationId - Conversation ID
2239
- * @param duration - Mute duration in milliseconds (undefined = forever)
2240
- * @throws {AXConversationApiError} If muting fails
2241
- */
2242
- abstract muteConversation(conversationId: string, duration?: number): Promise<void>;
2243
- /**
2244
- * Unmute conversation
2245
- *
2246
- * @param conversationId - Conversation ID
2247
- * @throws {AXConversationApiError} If unmuting fails
2248
- */
2249
- abstract unmuteConversation(conversationId: string): Promise<void>;
2250
2220
  /**
2251
2221
  * Upload conversation avatar
2252
2222
  *
@@ -2665,111 +2635,33 @@ declare abstract class AXConversationMessageApi {
2665
2635
 
2666
2636
  /**
2667
2637
  * Abstract Real-time Events API
2668
- * Handle WebSocket/SSE connections and real-time event subscriptions
2638
+ * Handle WebSocket/SSE event subscriptions for conversation domain updates
2669
2639
  */
2670
2640
 
2671
- /**
2672
- * Connection options
2673
- */
2674
- interface AXConversationConnectionOptions {
2675
- /** WebSocket/SSE endpoint URL */
2676
- url?: string;
2677
- /** Authentication token */
2678
- token?: string;
2679
- /** Reconnect automatically on disconnect */
2680
- autoReconnect?: boolean;
2681
- /** Reconnect delay in milliseconds */
2682
- reconnectDelay?: number;
2683
- /** Maximum reconnect attempts */
2684
- maxReconnectAttempts?: number;
2685
- /** Heartbeat interval in milliseconds */
2686
- heartbeatInterval?: number;
2687
- /** Custom headers */
2688
- headers?: Record<string, string>;
2689
- }
2690
- /**
2691
- * Connection event
2692
- */
2693
- interface AXConversationConnectionEvent {
2694
- /** Event type */
2695
- type: 'connected' | 'disconnected' | 'reconnecting' | 'error';
2696
- /** Timestamp */
2697
- timestamp: Date;
2698
- /** Error message if applicable */
2699
- error?: string;
2700
- /** Attempt number for reconnecting */
2701
- attempt?: number;
2702
- }
2703
- /**
2704
- * Notification event
2705
- */
2706
- interface AXConversationNotificationEvent {
2707
- /** Notification ID */
2708
- id: string;
2709
- /** Notification type */
2710
- type: 'message' | 'mention' | 'reaction' | 'call' | 'system';
2711
- /** Title */
2712
- title: string;
2713
- /** Body text */
2714
- body: string;
2715
- /** Related conversation ID */
2716
- conversationId?: string;
2717
- /** Related message ID */
2718
- messageId?: string;
2719
- /** Icon URL */
2720
- icon?: string;
2721
- /** Timestamp */
2722
- timestamp: Date;
2723
- /** Custom data */
2724
- data?: Record<string, unknown>;
2725
- }
2726
- /**
2727
- * Call event
2728
- */
2729
- interface AXConversationCallEvent {
2730
- /** Call ID */
2731
- callId: string;
2732
- /** Call type */
2733
- type: 'voice' | 'video';
2734
- /** Call status */
2735
- status: 'incoming' | 'outgoing' | 'accepted' | 'rejected' | 'ended' | 'missed';
2736
- /** Caller user ID */
2737
- callerId: string;
2738
- /** Conversation ID */
2739
- conversationId: string;
2740
- /** Timestamp */
2741
- timestamp: Date;
2742
- /** Call duration in seconds (for ended calls) */
2743
- duration?: number;
2744
- }
2745
2641
  /**
2746
2642
  * Abstract Real-time Events API
2747
2643
  *
2748
- * Implement this abstract class to handle real-time event subscriptions.
2749
- * Supports WebSocket, SSE, or any other real-time protocol.
2644
+ * Implement this abstract class to expose domain event streams from your WebSocket/SSE layer.
2645
+ * Connection lifecycle is owned by the implementation — this contract only covers subscriptions.
2646
+ *
2647
+ * Covered domains: message CRUD, conversation (room) CRUD, typing indicators, and presence.
2648
+ * Message updates include edits, reactions, delivery/read status, and other message field changes.
2750
2649
  *
2751
2650
  * @example
2752
2651
  * ```typescript
2753
2652
  * @Injectable()
2754
2653
  * export class MyRealtimeApi extends AXConversationRealtimeApi {
2755
- * private socket: WebSocket;
2756
- * private connectionStatus$ = new BehaviorSubject<AXConversationConnectionStatus>('disconnected');
2654
+ * private readonly messageCreated$ = new Subject<AXConversationMessage>();
2757
2655
  *
2758
- * async connect(options?: AXConversationConnectionOptions): Promise<void> {
2759
- * this.socket = new WebSocket(options?.url || 'ws://localhost:3000');
2760
- * this.socket.onopen = () => this.connectionStatus$.next('connected');
2761
- * // ... handle other events
2656
+ * constructor(private readonly socket: MyChatSocketService) {
2657
+ * super();
2658
+ * this.socket.on('message.created', (message) => this.messageCreated$.next(message));
2762
2659
  * }
2763
2660
  *
2764
2661
  * subscribeToMessages(conversationId: string): Observable<AXConversationMessage> {
2765
- * return new Observable(subscriber => {
2766
- * this.socket.addEventListener('message', (event) => {
2767
- * const data = JSON.parse(event.data);
2768
- * if (data.type === 'message' && data.conversationId === conversationId) {
2769
- * subscriber.next(data.message);
2770
- * }
2771
- * });
2772
- * });
2662
+ * return this.messageCreated$.pipe(
2663
+ * filter((message) => !conversationId || message.conversationId === conversationId),
2664
+ * );
2773
2665
  * }
2774
2666
  *
2775
2667
  * // ... implement other methods
@@ -2777,41 +2669,6 @@ interface AXConversationCallEvent {
2777
2669
  * ```
2778
2670
  */
2779
2671
  declare abstract class AXConversationRealtimeApi {
2780
- /**
2781
- * Current connection status
2782
- * Emit connection status changes through this observable
2783
- */
2784
- abstract readonly connectionStatus$: Observable<AXConversationConnectionStatus>;
2785
- /**
2786
- * Connect to real-time server
2787
- * Establish WebSocket/SSE connection
2788
- *
2789
- * @param options - Connection options
2790
- * @throws {Error} If connection fails
2791
- */
2792
- abstract connect(options?: AXConversationConnectionOptions): Promise<void>;
2793
- /**
2794
- * Disconnect from real-time server
2795
- * Close connection and clean up resources
2796
- */
2797
- abstract disconnect(): Promise<void>;
2798
- /**
2799
- * Check if currently connected
2800
- *
2801
- * @returns True if connected
2802
- */
2803
- abstract isConnected(): boolean;
2804
- /**
2805
- * Reconnect to server
2806
- * Manually trigger reconnection
2807
- */
2808
- abstract reconnect(): Promise<void>;
2809
- /**
2810
- * Subscribe to connection events
2811
- *
2812
- * @returns Observable of connection events
2813
- */
2814
- abstract subscribeToConnectionEvents(): Observable<AXConversationConnectionEvent>;
2815
2672
  /**
2816
2673
  * Subscribe to new messages in a conversation
2817
2674
  *
@@ -2820,7 +2677,7 @@ declare abstract class AXConversationRealtimeApi {
2820
2677
  */
2821
2678
  abstract subscribeToMessages(conversationId: string): Observable<AXConversationMessage>;
2822
2679
  /**
2823
- * Subscribe to message updates (edits, status changes)
2680
+ * Subscribe to message updates (edits, reactions, status changes, metadata, etc.)
2824
2681
  *
2825
2682
  * @param conversationId - Optional conversation ID to filter
2826
2683
  * @returns Observable stream of updated messages
@@ -2834,15 +2691,32 @@ declare abstract class AXConversationRealtimeApi {
2834
2691
  */
2835
2692
  abstract subscribeToMessageDeletions(conversationId?: string): Observable<string>;
2836
2693
  /**
2837
- * Subscribe to message reactions
2694
+ * Subscribe to message status changes
2695
+ * Fires when message status changes (sending -> sent -> delivered -> read)
2696
+ *
2697
+ * @param conversationId - Optional conversation ID to filter
2698
+ * @returns Observable stream of message status updates
2699
+ */
2700
+ abstract subscribeToMessageStatusChanges(conversationId?: string): Observable<{
2701
+ messageId: string;
2702
+ status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
2703
+ timestamp: Date;
2704
+ }>;
2705
+ /**
2706
+ * Subscribe to read receipt updates
2707
+ * Fires when someone reads messages
2838
2708
  *
2839
2709
  * @param conversationId - Optional conversation ID to filter
2840
- * @returns Observable stream of updated messages with reactions
2710
+ * @returns Observable stream of message IDs that were read
2841
2711
  */
2842
- abstract subscribeToMessageReactions(conversationId?: string): Observable<AXConversationMessage>;
2712
+ abstract subscribeToReadReceipts(conversationId?: string): Observable<{
2713
+ messageId: string;
2714
+ userId: string;
2715
+ readAt: Date;
2716
+ }>;
2843
2717
  /**
2844
2718
  * Subscribe to conversation updates
2845
- * Fires when conversation details change (title, avatar, participants, etc.)
2719
+ * Fires when conversation details change (title, avatar, participants, last message, etc.)
2846
2720
  *
2847
2721
  * @returns Observable stream of updated conversations
2848
2722
  */
@@ -2875,97 +2749,6 @@ declare abstract class AXConversationRealtimeApi {
2875
2749
  * @returns Observable stream of presence updates
2876
2750
  */
2877
2751
  abstract subscribeToPresenceUpdates(userIds?: string[]): Observable<AXConversationPresenceUpdate>;
2878
- /**
2879
- * Subscribe to read receipt updates
2880
- * Fires when someone reads messages
2881
- *
2882
- * @param conversationId - Optional conversation ID to filter
2883
- * @returns Observable stream of message IDs that were read
2884
- */
2885
- abstract subscribeToReadReceipts(conversationId?: string): Observable<{
2886
- messageId: string;
2887
- userId: string;
2888
- readAt: Date;
2889
- }>;
2890
- /**
2891
- * Subscribe to push notifications
2892
- * Fires for mentions, calls, and other important events
2893
- *
2894
- * @returns Observable stream of notification events
2895
- */
2896
- abstract subscribeToNotifications(): Observable<AXConversationNotificationEvent>;
2897
- /**
2898
- * Subscribe to call events
2899
- * Fires for incoming/outgoing calls
2900
- *
2901
- * @returns Observable stream of call events
2902
- */
2903
- abstract subscribeToCallEvents?(): Observable<AXConversationCallEvent>;
2904
- /**
2905
- * Subscribe to user blocked/unblocked events
2906
- *
2907
- * @returns Observable stream of user IDs and block status
2908
- */
2909
- abstract subscribeToUserBlockEvents(): Observable<{
2910
- userId: string;
2911
- blocked: boolean;
2912
- }>;
2913
- /**
2914
- * Subscribe to participant added/removed events
2915
- *
2916
- * @param conversationId - Optional conversation ID to filter
2917
- * @returns Observable stream of participant changes
2918
- */
2919
- abstract subscribeToParticipantEvents(conversationId?: string): Observable<{
2920
- conversationId: string;
2921
- userId: string;
2922
- action: 'added' | 'removed';
2923
- }>;
2924
- /**
2925
- * Subscribe to system events
2926
- * Fires for maintenance, updates, or other system-wide events
2927
- *
2928
- * @returns Observable stream of system events
2929
- */
2930
- abstract subscribeToSystemEvents(): Observable<{
2931
- type: string;
2932
- message: string;
2933
- data?: unknown;
2934
- }>;
2935
- /**
2936
- * Subscribe to message status changes
2937
- * Fires when message status changes (sending -> sent -> delivered -> read)
2938
- *
2939
- * @param conversationId - Optional conversation ID to filter
2940
- * @returns Observable stream of message status updates
2941
- */
2942
- abstract subscribeToMessageStatusChanges(conversationId?: string): Observable<{
2943
- messageId: string;
2944
- status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
2945
- timestamp: Date;
2946
- }>;
2947
- /**
2948
- * Subscribe to conversation settings changes
2949
- * Fires when conversation settings are updated
2950
- *
2951
- * @param conversationId - Optional conversation ID to filter
2952
- * @returns Observable stream of settings updates
2953
- */
2954
- abstract subscribeToConversationSettingsChanges(conversationId?: string): Observable<{
2955
- conversationId: string;
2956
- settings: Record<string, unknown>;
2957
- }>;
2958
- /**
2959
- * Subscribe to draft changes
2960
- * Fires when draft is saved/updated in a conversation
2961
- *
2962
- * @param conversationId - Optional conversation ID to filter
2963
- * @returns Observable stream of draft updates
2964
- */
2965
- abstract subscribeToDraftChanges(conversationId?: string): Observable<{
2966
- conversationId: string;
2967
- draft: string | null;
2968
- }>;
2969
2752
  }
2970
2753
 
2971
2754
  /**
@@ -3045,7 +2828,7 @@ declare abstract class AXConversationUserApi {
3045
2828
  * @returns Current user information
3046
2829
  * @throws {AXConversationApiError} If user is not authenticated
3047
2830
  */
3048
- abstract getCurrentUser(): Promise<AXConversationParticipant>;
2831
+ abstract getCurrentUser(): Promise<AXConversationUser>;
3049
2832
  /**
3050
2833
  * Update current user profile
3051
2834
  *
@@ -3053,7 +2836,7 @@ declare abstract class AXConversationUserApi {
3053
2836
  * @returns Updated user information
3054
2837
  * @throws {AXConversationApiError} If update fails
3055
2838
  */
3056
- abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationParticipant>;
2839
+ abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationUser>;
3057
2840
  /**
3058
2841
  * Upload user avatar
3059
2842
  *
@@ -3103,6 +2886,10 @@ declare abstract class AXConversationUserApi {
3103
2886
  * @throws {AXConversationApiError} If request fails
3104
2887
  */
3105
2888
  abstract getUserPresence(userId: string): Promise<AXConversationPresenceUpdate>;
2889
+ /**
2890
+ * Get presence for multiple users (bulk hydration).
2891
+ */
2892
+ abstract getUsersPresence(userIds: string[]): Promise<AXConversationPresenceUpdate[]>;
3106
2893
  /**
3107
2894
  * Update current user presence
3108
2895
  *
@@ -3155,6 +2942,18 @@ declare abstract class AXConversationUserApi {
3155
2942
  * @throws {AXConversationApiError} If update fails
3156
2943
  */
3157
2944
  abstract updateUserSettings(settings: Record<string, unknown>): Promise<void>;
2945
+ /**
2946
+ * Get all conversation preferences for the current user.
2947
+ */
2948
+ abstract getConversationPreferences(): Promise<AXConversationRoomPreferencesMap>;
2949
+ /**
2950
+ * Get preferences for a single conversation.
2951
+ */
2952
+ abstract getConversationPreferencesForRoom(conversationId: string): Promise<AXConversationRoomPreferences>;
2953
+ /**
2954
+ * Update preferences for a conversation (current user's view).
2955
+ */
2956
+ abstract updateConversationPreferences(conversationId: string, preferences: Partial<AXConversationRoomPreferences>): Promise<AXConversationRoomPreferences>;
3158
2957
  /**
3159
2958
  * Create an API error
3160
2959
  * Helper method for consistent error creation
@@ -3168,6 +2967,27 @@ declare abstract class AXConversationUserApi {
3168
2967
  protected createError(code: string, message: string, statusCode?: number, details?: unknown): AXConversationApiError;
3169
2968
  }
3170
2969
 
2970
+ type AXConversationComposerGenerationPhase = 'idle' | 'generating' | 'stopping';
2971
+ declare class AXConversationComposerGenerationStateService {
2972
+ private readonly _phase;
2973
+ private readonly _cancelled$;
2974
+ /** Current generation lifecycle phase. */
2975
+ readonly phase: _angular_core.Signal<AXConversationComposerGenerationPhase>;
2976
+ /** Whether a background generation (e.g. AI response) is in progress. */
2977
+ readonly isGenerating: _angular_core.Signal<boolean>;
2978
+ /** Whether generation is being cancelled (spinner / locked until API finishes). */
2979
+ readonly isStopping: _angular_core.Signal<boolean>;
2980
+ /** Whether generation or stop-cleanup is in progress. */
2981
+ readonly isBusy: _angular_core.Signal<boolean>;
2982
+ /** Emits when the user presses the composer cancel/stop button. */
2983
+ readonly onCancelled: rxjs.Observable<void>;
2984
+ setGenerating(value: boolean): void;
2985
+ /** User requested cancel — enters `stopping` until {@link setGenerating}(false) is called. */
2986
+ cancel(): void;
2987
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerGenerationStateService, never>;
2988
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationComposerGenerationStateService>;
2989
+ }
2990
+
3171
2991
  /**
3172
2992
  * Central Registry Service
3173
2993
  * Provides unified access to all registries
@@ -3234,14 +3054,20 @@ declare class AXConversationService {
3234
3054
  private readonly destroy$;
3235
3055
  /** Registry service - exposed for child services */
3236
3056
  readonly registry: AXConversationRegistryService;
3057
+ private readonly composerGenerationState;
3058
+ /** Whether the composer primary button is in cancel (generation) mode. */
3059
+ readonly isGenerating: _angular_core.Signal<boolean>;
3060
+ /** Whether cancel cleanup is in progress. */
3061
+ readonly isStopping: _angular_core.Signal<boolean>;
3062
+ /** Emits when the user cancels an in-progress generation from the composer. */
3063
+ readonly onGenerationCancelled: rxjs.Observable<void>;
3237
3064
  private readonly _activeConversationId;
3238
3065
  private readonly _loading;
3239
3066
  private readonly _loadingActiveMessages;
3067
+ private readonly _isForwardingMessage;
3240
3068
  private readonly _error;
3241
3069
  private readonly _conversationsPagination;
3242
3070
  private readonly _messagesPaginationByConversation;
3243
- /** Emits when the active conversation changes, cancelling per-conversation subscriptions. */
3244
- private readonly _conversationSwitch$;
3245
3071
  private readonly _messageReceived$;
3246
3072
  private readonly _messageUpdated$;
3247
3073
  private readonly _messageDeleted$;
@@ -3259,14 +3085,14 @@ declare class AXConversationService {
3259
3085
  readonly loading: _angular_core.Signal<boolean>;
3260
3086
  /** Loading state for the active conversation's message history */
3261
3087
  readonly loadingActiveMessages: _angular_core.Signal<boolean>;
3088
+ /** Whether a message forward operation is in progress. */
3089
+ readonly isForwardingMessage: _angular_core.Signal<boolean>;
3262
3090
  /** Sidebar conversation list pagination */
3263
3091
  readonly conversationsPagination: _angular_core.Signal<AXConversationPaginationState>;
3264
3092
  /** Active conversation message pagination */
3265
3093
  readonly activeMessagesPagination: _angular_core.Signal<AXConversationPaginationState>;
3266
3094
  /** Error state */
3267
3095
  readonly error: _angular_core.Signal<Error>;
3268
- /** Connection status */
3269
- readonly connectionStatus$: rxjs.Observable<_acorex_components_conversation.AXConversationConnectionStatus>;
3270
3096
  /** Error stream */
3271
3097
  readonly errors$: rxjs.Observable<_acorex_components_conversation.AXConversationError>;
3272
3098
  readonly onMessageReceived: rxjs.Observable<AXConversationMessage>;
@@ -3275,7 +3101,10 @@ declare class AXConversationService {
3275
3101
  readonly onTypingIndicator: rxjs.Observable<AXConversationTypingIndicator>;
3276
3102
  readonly onPresenceChange: rxjs.Observable<AXConversationPresenceUpdate>;
3277
3103
  private _currentUser;
3278
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3104
+ readonly currentUser: _angular_core.Signal<AXConversationUser>;
3105
+ readonly userPresenceMap: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3106
+ readonly presenceTimeTick: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3107
+ readonly typingRevision: _angular_core.Signal<Map<string, Map<string, number>>>;
3279
3108
  /** One-time async initialization (connect, user, conversations, realtime). */
3280
3109
  private initPromise;
3281
3110
  /** Generation counter — stale page-0 loads are ignored after conversation switches. */
@@ -3285,6 +3114,12 @@ declare class AXConversationService {
3285
3114
  /** Batched read-receipt queue keyed by conversation ID. */
3286
3115
  private readonly readQueue;
3287
3116
  private readFlushHandle;
3117
+ private presenceTickHandle?;
3118
+ private typingPruneHandle?;
3119
+ /** Outgoing typing indicator throttle state (composer -> API). */
3120
+ private readonly outgoingTypingLastEmitAt;
3121
+ private readonly outgoingTypingActive;
3122
+ private readonly outgoingTypingStopHandles;
3288
3123
  /** Session cache for available reaction emojis. */
3289
3124
  private availableReactionsCache;
3290
3125
  private availableReactionsPromise;
@@ -3304,10 +3139,18 @@ declare class AXConversationService {
3304
3139
  */
3305
3140
  private initializeService;
3306
3141
  /**
3307
- * Subscribe to real-time events
3308
- * All subscriptions include error handling to prevent stream termination
3142
+ * Subscribe to real-time events from {@link AXConversationRealtimeApi}.
3143
+ * Binds every abstract subscription: messages (create/update/delete/status/read),
3144
+ * conversations (create/update/delete), typing indicators, and presence.
3309
3145
  */
3310
3146
  private subscribeToEvents;
3147
+ getUserPresence(userId: string): AXConversationUserPresence | undefined;
3148
+ getRoomPreferences(conversationId: string): AXConversationRoomPreferences;
3149
+ isAnyoneTyping(conversationId: string): boolean;
3150
+ getActiveTypingUserIds(conversationId: string): string[];
3151
+ getPeerPresence(conversation: AXConversation): AXConversationUserPresence | undefined;
3152
+ private hydrateUserPresence;
3153
+ private loadRoomPreferences;
3311
3154
  /**
3312
3155
  * Load conversations from server
3313
3156
  * Includes comprehensive error handling
@@ -3340,6 +3183,7 @@ declare class AXConversationService {
3340
3183
  * Resolve a media reference to a playback/download URL.
3341
3184
  */
3342
3185
  resolveMediaUrl(reference: AXConversationUploaderReference, signal?: AbortSignal): Promise<string>;
3186
+ private resolveReplyTo;
3343
3187
  /**
3344
3188
  * Send a message
3345
3189
  * Uses optimistic UI updates - message appears immediately
@@ -3390,11 +3234,33 @@ declare class AXConversationService {
3390
3234
  * Marks messages locally and syncs with server
3391
3235
  */
3392
3236
  markAsRead(conversationId: string): Promise<void>;
3237
+ /**
3238
+ * Set composer generation mode (shows cancel button instead of send/voice).
3239
+ * Call from message APIs while an AI or async response is in progress.
3240
+ */
3241
+ setGenerating(value: boolean): void;
3242
+ /**
3243
+ * Cancel an in-progress generation from the composer UI or programmatically.
3244
+ */
3245
+ cancelGeneration(): void;
3246
+ /**
3247
+ * Notify that the composer has draft content.
3248
+ * Emits typing indicators at most once per {@link AXConversationConfig.typingIndicatorThrottle}.
3249
+ */
3250
+ notifyComposerTyping(conversationId: string): void;
3251
+ /**
3252
+ * Notify that the composer no longer has draft content (or user left the chat).
3253
+ * Sends a single stop event when a typing indicator was previously emitted.
3254
+ */
3255
+ notifyComposerStoppedTyping(conversationId: string): void;
3256
+ private scheduleOutgoingTypingStop;
3257
+ private clearOutgoingTypingStop;
3393
3258
  /**
3394
3259
  * Send typing indicator
3395
3260
  * Non-critical operation, doesn't throw on failure
3396
3261
  */
3397
3262
  sendTypingIndicator(conversationId: string): Promise<void>;
3263
+ stopTypingIndicator(conversationId: string): Promise<void>;
3398
3264
  /**
3399
3265
  * Search conversations
3400
3266
  * Returns empty array on failure
@@ -3430,15 +3296,24 @@ declare class AXConversationService {
3430
3296
  * Updates conversation metadata including unread count, last message, etc.
3431
3297
  */
3432
3298
  private handleConversationUpdate;
3299
+ private handleConversationCreated;
3300
+ private handleConversationDeleted;
3301
+ private handleReadReceipt;
3302
+ private handleMessageStatusChange;
3433
3303
  /**
3434
3304
  * Insert or refresh a conversation in the in-memory inbox.
3435
3305
  * @param promote When true, bumps activity so the chat sorts to the top (create / reopen).
3436
3306
  */
3437
3307
  private syncConversationToInbox;
3308
+ private finalizeSentMessage;
3438
3309
  /**
3439
3310
  * Update conversation's last message
3440
3311
  */
3441
3312
  private updateConversationLastMessage;
3313
+ /** Keep sidebar preview in sync when the last cached message is edited or deleted. */
3314
+ private syncLastMessageIfRelevant;
3315
+ /** Recompute conversation preview after a message is removed from the local cache. */
3316
+ private refreshConversationLastMessage;
3442
3317
  /**
3443
3318
  * Update conversation properties
3444
3319
  * @param conversationId - Conversation ID
@@ -3450,7 +3325,7 @@ declare class AXConversationService {
3450
3325
  * @param conversationId - Conversation ID
3451
3326
  * @param settings - Partial settings to update
3452
3327
  */
3453
- updateConversationSettings(conversationId: string, settings: Partial<AXConversation['settings']>): Promise<void>;
3328
+ updateConversationSettings(conversationId: string, settings: Partial<AXConversationRoomPreferences>): Promise<void>;
3454
3329
  /**
3455
3330
  * Update conversation title
3456
3331
  * @param conversationId - Conversation ID
@@ -3510,11 +3385,6 @@ declare class AXConversationService {
3510
3385
  * @returns Number of times forwarded
3511
3386
  */
3512
3387
  getForwardCount(messageId: string): Promise<number>;
3513
- /**
3514
- * Disconnect and cleanup
3515
- * Cleanly closes all connections and resources
3516
- */
3517
- disconnect(): Promise<void>;
3518
3388
  /**
3519
3389
  * Archive conversation
3520
3390
  * @param conversationId - Conversation ID
@@ -3593,6 +3463,10 @@ declare class AXConversationService {
3593
3463
  * @param caption - Optional caption
3594
3464
  */
3595
3465
  forwardMessage(messageId: string, conversationIds: string[], caption?: string): Promise<void>;
3466
+ /**
3467
+ * Runs a forward operation while locking all forward actions until it completes.
3468
+ */
3469
+ runWithForwardingLock<T>(task: () => Promise<T>): Promise<T>;
3596
3470
  /**
3597
3471
  * Search messages in conversation
3598
3472
  * @param conversationId - Conversation ID
@@ -3647,7 +3521,7 @@ declare class AXConversationService {
3647
3521
  * @param status - Presence status
3648
3522
  * @param statusText - Optional status text
3649
3523
  */
3650
- updatePresence(status: 'online' | 'offline' | 'away' | 'busy' | 'invisible', statusText?: string): Promise<void>;
3524
+ updatePresence(status: AXConversationPresenceStatus, statusText?: string): Promise<void>;
3651
3525
  /**
3652
3526
  * Validate message content before sending
3653
3527
  * Uses centralized validation utilities for consistency
@@ -3795,6 +3669,7 @@ declare class AXConversationForwardMessageDialogComponent implements OnInit {
3795
3669
  readonly forwardListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
3796
3670
  readonly forwardList: _angular_core.Signal<AXListComponent>;
3797
3671
  readonly forwardListDataSource: AXDataSource<unknown>;
3672
+ readonly isForwarding: _angular_core.Signal<boolean>;
3798
3673
  readonly canForward: _angular_core.Signal<boolean>;
3799
3674
  private readonly _syncPopupTitleEffect;
3800
3675
  ngOnInit(): void;
@@ -3808,6 +3683,47 @@ declare class AXConversationForwardMessageDialogComponent implements OnInit {
3808
3683
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationForwardMessageDialogComponent, "ax-conversation-forward-message-dialog", never, { "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3809
3684
  }
3810
3685
 
3686
+ /**
3687
+ * Message Utilities Service
3688
+ * Helper functions for message formatting and display
3689
+ */
3690
+
3691
+ /** Position of a message inside a consecutive same-sender cluster (Telegram grouping). */
3692
+ type AXConversationMessageClusterRole = 'single' | 'start' | 'middle' | 'end';
3693
+ declare class AXConversationMessageUtilsService {
3694
+ static getInitials(name: string): string;
3695
+ static getMessageText(message: AXConversationMessage): string;
3696
+ static getPreviewText(message: AXConversationMessage, maxLength?: number): {
3697
+ value: string;
3698
+ type: string;
3699
+ icon: string;
3700
+ };
3701
+ static isOwnMessage(message: AXConversationMessage, currentUserId: string): boolean;
3702
+ static getSenderName(message: AXConversationMessage, conversation: AXConversation): string;
3703
+ static getSenderAvatar(message: AXConversationMessage, conversation: AXConversation): string | undefined;
3704
+ static getSenderAvatarIcon(message: AXConversationMessage, conversation: AXConversation): string | undefined;
3705
+ static getConversationAvatar(conversation: AXConversation): string | undefined;
3706
+ static getConversationAvatarIcon(conversation: AXConversation): string | undefined;
3707
+ static getConversationStatus(conversation: AXConversation, presence?: AXConversationUserPresence): AXConversationPresenceStatus | undefined;
3708
+ /** Consecutive same-sender messages within this window share one Telegram-style cluster. */
3709
+ static readonly MESSAGE_CLUSTER_MAX_GAP_MS: number;
3710
+ /** Palette of existing theme tokens used to color group sender names (not bubble chrome). */
3711
+ private static readonly SENDER_NAME_COLORS;
3712
+ static toTimestampMs(value: Date | string | number): number;
3713
+ static shouldGroupMessages(message: AXConversationMessage, previousMessage?: AXConversationMessage): boolean;
3714
+ static getMessageClusterRole(message: AXConversationMessage, previousMessage?: AXConversationMessage, nextMessage?: AXConversationMessage): AXConversationMessageClusterRole;
3715
+ static getSenderNameColor(senderId: string): string;
3716
+ static getUserPresenceStatus(presence?: AXConversationUserPresence): AXConversationPresenceStatus | undefined;
3717
+ static getTypingText(conversation: AXConversation, typingUserIds: string[]): string;
3718
+ static formatLastSeen(date: Date): string;
3719
+ static getPrivateChatSubtitle(conversation: AXConversation, presence?: AXConversationUserPresence, currentUserId?: string): string;
3720
+ static getConversationSubtitle(conversation: AXConversation, options?: {
3721
+ typingUserIds?: string[];
3722
+ peerPresence?: AXConversationUserPresence;
3723
+ currentUserId?: string;
3724
+ }): string;
3725
+ }
3726
+
3811
3727
  /** Default message list surface when no conversation is selected and no `ax-conversation-message-list-no-active` content is projected. */
3812
3728
  declare class AXConversationMessageListNoActiveDefaultComponent {
3813
3729
  private readonly translation;
@@ -3819,421 +3735,104 @@ declare class AXConversationMessageListNoActiveDefaultComponent {
3819
3735
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationMessageListNoActiveDefaultComponent, "ax-conversation-message-list-no-active-default", never, {}, {}, never, never, true, never>;
3820
3736
  }
3821
3737
 
3822
- declare class AXConversationMessageListComponent implements OnDestroy {
3823
- private readonly conversationService;
3824
- private readonly messageListService;
3825
- private readonly composerService;
3826
- private readonly fileService;
3827
- private readonly toast;
3828
- private readonly infoBarService;
3829
- private readonly translation;
3830
- private readonly document;
3831
- private readonly platform;
3832
- protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
3738
+ interface AXConversationAvatarDisplay {
3739
+ name: string;
3740
+ avatar?: string;
3741
+ icon?: string;
3742
+ }
3743
+ /** Conversation types that resolve a single peer participant for viewer-scoped avatar/title. */
3744
+ declare const AX_CONVERSATION_PEER_AVATAR_TYPES: ReadonlySet<AXConversationType>;
3745
+ /**
3746
+ * Other participant in a peer-scoped conversation (excludes the current viewer).
3747
+ * Applies to private 1:1 and bot assist chats with exactly one non-viewer participant.
3748
+ */
3749
+ declare function resolveConversationPeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
3750
+ /** Other participant in a private chat (excludes the current user). */
3751
+ declare function resolvePrivatePeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
3752
+ /** Peer participant for private and bot conversations. */
3753
+ declare function resolveConversationPeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
3754
+ /** Whether `auto` kind should render a registered user avatar for this conversation. */
3755
+ declare function shouldUseUserAvatarForConversation(conversation: AXConversation, currentUserId?: string): boolean;
3756
+ declare function resolveUserAvatarDisplay(userId: string, conversation: AXConversation | undefined, message?: AXConversationMessage): AXConversationAvatarDisplay;
3757
+ declare function resolveConversationAvatarDisplay(conversation: AXConversation, currentUserId?: string): AXConversationAvatarDisplay;
3758
+
3759
+ interface AXConversationMessageListBackgroundPreset {
3760
+ id: string;
3761
+ value: AXConversationMessageListThemeBackground;
3762
+ }
3763
+ /** Library default when no per-conversation or global background is set (pattern-5 tile + gradient wash). */
3764
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND: AXConversationMessageListThemeBackground;
3765
+ /** Predefined chat-area backgrounds for the info panel (light + dark variants). */
3766
+ declare const AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS: AXConversationMessageListBackgroundPreset[];
3767
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID = "solid-default";
3768
+
3769
+ /** Subtle Telegram-style chat-area wash when `messageListBackground` is not set (theme-aware). */
3770
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND: string;
3771
+ declare function isMessageListThemeBackground(value: unknown): value is AXConversationMessageListThemeBackground;
3772
+ /** Pick the raw CSS string for the active theme; `undefined` when unset. */
3773
+ declare function resolveMessageListBackgroundRaw(value: AXConversationMessageListBackground | undefined, isDark: boolean): string | undefined;
3774
+ /** Turn bare `https://...` or `/path` into valid CSS `background` for images. */
3775
+ declare function normalizeMessageListBackgroundValue(raw: string): string;
3776
+ /** Whether the built-in pattern-5 wallpaper (gradient + tiled SVG) should be used. */
3777
+ declare function usesDefaultMessageListWallpaper(value: AXConversationMessageListBackground | undefined): boolean;
3778
+ /** Resolve config/metadata background for the active theme, with library default fallback. */
3779
+ declare function resolveMessageListBackgroundStyle(value: AXConversationMessageListBackground | undefined, isDark: boolean): string;
3780
+ /** Whether two stored backgrounds represent the same preset (supports legacy string values). */
3781
+ declare function isSameMessageListBackground(a: AXConversationMessageListBackground | undefined, b: AXConversationMessageListThemeBackground, isDark: boolean): boolean;
3782
+
3783
+ /** Default Font Awesome icon for group conversations without a custom avatar image. */
3784
+ declare const AX_CONVERSATION_DEFAULT_GROUP_ICON = "fa-light fa-users";
3785
+ /** Default Font Awesome icon for private/bot conversations without a custom avatar image. */
3786
+ declare const AX_CONVERSATION_DEFAULT_USER_ICON = "fa-light fa-user";
3787
+ /** True when the stored title is a placeholder, not a user-defined name. */
3788
+ declare function isGenericPrivateConversationTitle(title: string | undefined): boolean;
3789
+ /**
3790
+ * Find an existing private 1:1 conversation between the current user and a peer.
3791
+ * Matches conversations with exactly those two participants.
3792
+ */
3793
+ declare function findExistingPrivateConversation(conversations: AXConversation[], currentUserId: string, peerUserId: string): AXConversation | undefined;
3794
+ /** Other participant in a private 1v1 chat (excludes the current viewer). */
3795
+ declare function resolvePrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
3796
+ /**
3797
+ * Resolves the display title for the current viewer.
3798
+ * Private and bot peer-scoped chats show the other participant's name when no custom title is set.
3799
+ */
3800
+ declare function resolveConversationTitleForViewer(conversation: AXConversation, currentUserId?: string): string;
3801
+ /**
3802
+ * Returns a viewer-scoped copy of a conversation with dynamic peer title/avatar/icon.
3803
+ * Does not mutate the source object.
3804
+ */
3805
+ declare function resolveConversationForViewer(conversation: AXConversation, currentUserId?: string): AXConversation;
3806
+ /** Whether message reactions are enabled for a conversation. Defaults to `true` when omitted. */
3807
+ declare function isConversationReactionsEnabled(conversation?: AXConversation | null): boolean;
3808
+
3809
+ /** Resolves typed `profile`, falling back to legacy `metadata.profile`. */
3810
+ declare function resolveParticipantProfile(participant?: AXConversationParticipant): AXConversationUserProfile;
3811
+
3812
+ type AXConversationDateSeparatorKind = 'today' | 'yesterday' | 'other';
3813
+ declare class AXConversationDateUtilsService {
3833
3814
  /**
3834
- * Background for the message list scroll area from config, or the built-in soft wash when unset/empty.
3835
- * Set `messageListBackground` to `transparent` or `none` for a flat look.
3836
- * Supports `{ light, dark }` for theme-specific backgrounds.
3815
+ * Format relative time (e.g., "2m ago", "1h ago")
3837
3816
  */
3838
- readonly messageListBackgroundStyle: _angular_core.Signal<string>;
3839
- resolvedEmptyStateComponent(): Type<AXConversationMessageListEmptyComponent>;
3840
- /** Fallback when no conversation is active and no `ax-conversation-message-list-no-active` content is projected. */
3841
- protected readonly noActiveFallbackComponent: typeof AXConversationMessageListNoActiveDefaultComponent;
3842
- private readonly timeouts;
3843
- readonly reactionPickerTarget: _angular_core.WritableSignal<string>;
3844
- readonly reactionPickerElement: _angular_core.WritableSignal<HTMLElement>;
3845
- readonly reactionPickerPlacement: _angular_core.WritableSignal<AXPlacement>;
3846
- readonly reactionPopover: _angular_core.Signal<any>;
3847
- /** Message id whose context menu is open (for active row styling). */
3848
- readonly contextMenuMessageId: _angular_core.WritableSignal<string>;
3849
- /** True while files are dragged over the message list drop zone. */
3850
- readonly messageListDragging: _angular_core.WritableSignal<boolean>;
3851
- /** While true, older history is being prepended — do not auto-scroll to the latest message. */
3852
- private restoringScrollAfterPrepend;
3853
- readonly availableReactions: _angular_core.WritableSignal<string[]>;
3854
- private reactionsLoading;
3855
- private get registry();
3856
- /** Message list element reference */
3857
- private readonly messageListRef;
3858
- /** Messages container element reference */
3859
- private readonly messagesContainerRef;
3860
- /** Loading state - use service */
3861
- readonly loading: _angular_core.Signal<boolean>;
3862
- /** Loading more messages state - use service */
3863
- readonly loadingMore: _angular_core.WritableSignal<boolean>;
3864
- /** Whether older messages remain on the server */
3865
- readonly hasMoreMessages: _angular_core.Signal<boolean>;
3866
- /** Show scroll to bottom button - use service */
3867
- readonly showScrollButton: _angular_core.WritableSignal<boolean>;
3868
- /** Active conversation */
3869
- readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
3870
- readonly isGroupConversation: _angular_core.Signal<boolean>;
3871
- /** Placeholder indices for the initial message list skeleton. */
3872
- protected readonly loadingSkeletonItems: readonly [0, 1, 2, 3, 4, 5];
3873
- /** Whether the active conversation allows message reactions. */
3874
- readonly reactionsEnabled: _angular_core.Signal<boolean>;
3875
- /** Messages */
3876
- readonly messages: _angular_core.Signal<AXConversationMessage[]>;
3877
- /** Message action event */
3878
- readonly messageAction: _angular_core.OutputEmitterRef<{
3879
- message: AXConversationMessage;
3880
- action: string;
3881
- }>;
3882
- /** Current user from service */
3883
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3884
- /** Message grouped by date - use service */
3885
- readonly messageGroups: _angular_core.Signal<{
3886
- date: string;
3887
- dateLabel: string;
3888
- messages: AXConversationMessage[];
3889
- }[]>;
3890
- constructor();
3891
- private intersectionObserver?;
3892
- private readonly observedReadMessageIds;
3817
+ static formatRelativeTime(date: Date): string;
3818
+ /** Resolve whether a message date should show Today, Yesterday, or a formatted date. */
3819
+ static getDateSeparatorKind(date: Date): AXConversationDateSeparatorKind;
3893
3820
  /**
3894
- * Setup intersection observer to mark messages as read when visible
3821
+ * Format date label for non-relative separators (localized calendar date).
3895
3822
  */
3896
- private setupIntersectionObserver;
3823
+ static formatDateLabel(date: Date, locale?: string): string;
3897
3824
  /**
3898
- * Mark message as read
3825
+ * Check if two dates are the same day
3899
3826
  */
3900
- private markMessageAsRead;
3901
- /** Get message CSS classes */
3902
- getMessageClasses(message: AXConversationMessage): string;
3903
- /** Get bubble CSS classes */
3904
- getBubbleClasses(message: AXConversationMessage): string;
3905
- /** Check if message is from current user */
3906
- isOwnMessage(message: AXConversationMessage): boolean;
3907
- /** Should show avatar */
3908
- shouldShowAvatar(message: AXConversationMessage): boolean;
3909
- /** Should show sender name */
3910
- shouldShowSenderName(message: AXConversationMessage): boolean;
3911
- /** Get sender name */
3912
- getSenderName(message: AXConversationMessage): string;
3913
- /** Get original sender name for forwarded messages */
3914
- getOriginalSenderName(message: AXConversationMessage): string;
3915
- /** Get forwarded text with sender and conversation info */
3916
- getForwardedText(message: AXConversationMessage): string;
3917
- /** Resolve renderer component for message */
3918
- getRendererComponent(message: AXConversationMessage): Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
3919
- /** Resolve lazy renderer loader for message */
3920
- getRendererComponentLoader(message: AXConversationMessage): (() => Promise<Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
3921
- /** Provide inputs for the dynamic renderer */
3922
- getRendererInputs(message: AXConversationMessage): {
3923
- message: AXConversationMessage;
3924
- };
3925
- /** Get status icon */
3926
- getStatusIcon(message: AXConversationMessage): string;
3927
- /** Get status icon CSS classes */
3928
- getStatusIconClasses(message: AXConversationMessage): string;
3929
- /** Get status tooltip text */
3930
- getStatusTooltip(message: AXConversationMessage): string;
3931
- /** Get first unread message ID */
3932
- readonly firstUnreadMessageId: _angular_core.Signal<string>;
3933
- /** Get grouped reactions */
3934
- getGroupedReactions(message: AXConversationMessage): Array<{
3935
- emoji: string;
3936
- count: number;
3937
- userIds: string[];
3938
- hasReacted: boolean;
3939
- }>;
3940
- /** Get reaction tooltip text */
3941
- getReactionTooltip(reaction: {
3942
- emoji: string;
3943
- count: number;
3944
- userIds: string[];
3945
- hasReacted: boolean;
3946
- }): string;
3947
- /** Whether reactions can be shown or added for a message in the active conversation. */
3948
- messageSupportsReactions(message: AXConversationMessage): boolean;
3949
- /** Toggle reaction picker */
3950
- toggleReactionPicker(message: AXConversationMessage, event: MouseEvent): void;
3951
- /** Close reaction picker */
3952
- closeReactionPicker(): void;
3953
- /** Check if current user has reacted with specific emoji */
3954
- hasUserReacted(message: AXConversationMessage, emoji: string): boolean;
3955
- /** Check if current user has reacted with specific emoji by message ID */
3956
- hasUserReactedById(messageId: string, emoji: string): boolean;
3957
- /** Handle reaction click by message ID */
3958
- onReactionClickById(messageId: string, emoji: string): void;
3959
- /** Get message by ID */
3960
- getMessageById(messageId: string): AXConversationMessage | undefined;
3961
- /** Load available reactions when the picker is opened (session-cached in service). */
3962
- private ensureAvailableReactions;
3963
- /** Get message actions from registry */
3964
- getMessageActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
3965
- /** Handle reaction click */
3966
- onReactionClick(message: AXConversationMessage, emoji: string): void;
3967
- /** Handle message action */
3968
- onMessageAction(message: AXConversationMessage, action: any): Promise<void>;
3969
- /** Handle scroll events */
3970
- onScroll(event: Event): void;
3971
- /** Handle infinite scroll threshold */
3972
- onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
3973
- /** Load older messages - delegate to service and preserve scroll anchor */
3974
- private loadOlderMessages;
3975
- /**
3976
- * Keep the user's viewport on the same messages after older rows are inserted above.
3977
- */
3978
- private restoreScrollPositionAfterPrepend;
3979
- /** Check if user is near bottom of scroll */
3980
- private isUserNearBottom;
3981
- /**
3982
- * After switching chats, the template may still show loading (no #messagesContainer).
3983
- * Poll with rAF until the feed exists, then scroll after double rAF so scrollHeight is stable.
3984
- */
3985
- private scrollToBottomWhenContainerReady;
3986
- /** Scroll to bottom */
3987
- scrollToBottom(smooth?: boolean): void;
3988
- /** Scroll to specific message */
3989
- scrollToMessage(messageId: string): void;
3990
- /** Cleanup timeouts and observers on destroy */
3991
- ngOnDestroy(): void;
3992
- /** Get message preview text for reply */
3993
- getMessagePreviewText(message: AXConversationMessage): {
3994
- value: string;
3995
- type: string;
3996
- icon: string;
3997
- };
3998
- /** Get ARIA label for message */
3999
- getMessageAriaLabel(message: AXConversationMessage): string;
4000
- getDateSeparatorAriaLabel(dateLabel: string): string;
4001
- getReplyCount(message: AXConversationMessage): number;
4002
- getForwardCount(message: AXConversationMessage): number;
4003
- onMessageListDragEnter(): void;
4004
- onMessageListDragLeave(): void;
4005
- /** Open the matching composer picker popup when files are dropped on the message list. */
4006
- onMessageListFilesDropped(event: AXUploaderFileChangeEvent): Promise<void>;
4007
- private composerPickerDeps;
4008
- /** Handle context menu opening for messages */
4009
- handleMessageContextMenuOpening(event: AXContextMenuOpeningEvent, message: AXConversationMessage): void;
4010
- /** Handle context menu item click for messages */
4011
- handleMessageContextMenuItemClick(event: AXContextMenuItemsClickEvent, message: AXConversationMessage): void;
4012
- /**
4013
- * TrackBy function for message groups.
4014
- * Include the latest message id so new messages in the same date group re-render.
4015
- */
4016
- trackMessageGroup(index: number, group: {
4017
- date: string;
4018
- messages: AXConversationMessage[];
4019
- }): string;
4020
- /**
4021
- * TrackBy function for messages
4022
- * Tracks by ID only to prevent unnecessary re-renders
4023
- */
4024
- trackMessage(index: number, message: AXConversationMessage): string;
4025
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListComponent, never>;
4026
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationMessageListComponent, "ax-conversation-message-list", never, {}, { "messageAction": "messageAction"; }, never, ["ax-conversation-message-list-empty, [ax-conversation-message-list-empty]", "ax-conversation-message-list-no-active, [ax-conversation-message-list-no-active]"], true, never>;
4027
- }
4028
-
4029
- declare class AXConversationMessageListService {
4030
- private readonly conversationService;
4031
- private get registry();
4032
- readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
4033
- readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
4034
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
4035
- /** Initial message history load (conversation switch) */
4036
- readonly loading: _angular_core.Signal<boolean>;
4037
- /** Loading older messages (scroll-up pagination) */
4038
- readonly loadingMore: _angular_core.WritableSignal<boolean>;
4039
- /** Whether older messages can be loaded */
4040
- readonly hasMoreMessages: _angular_core.Signal<boolean>;
4041
- /** Show scroll to bottom button */
4042
- readonly showScrollButton: _angular_core.WritableSignal<boolean>;
4043
- /** Scroll requests counter */
4044
- readonly scrollRequests: _angular_core.WritableSignal<number>;
4045
- /** Live renderer instances keyed by message id (for message actions). */
4046
- private readonly _rendererInstances;
4047
- /**
4048
- * Reply counts merged from API fields and loaded messages.
4049
- */
4050
- readonly replyCounts: _angular_core.Signal<Map<string, number>>;
4051
- /**
4052
- * Forward counts merged from API fields and loaded messages.
4053
- */
4054
- readonly forwardCounts: _angular_core.Signal<Map<string, number>>;
4055
- registerRendererInstance(messageId: string, instance: AXConversationMessageRendererComponent): void;
4056
- unregisterRendererInstance(messageId: string): void;
4057
- getRendererInstance(messageId: string): AXConversationMessageRendererComponent | undefined;
4058
- getReplyCount(messageId: string): number;
4059
- getForwardCount(messageId: string): number;
4060
- /** Message grouped by date */
4061
- readonly messageGroups: _angular_core.Signal<{
4062
- date: string;
4063
- dateLabel: string;
4064
- messages: AXConversationMessage[];
4065
- }[]>;
4066
- /**
4067
- * Load older messages when the user scrolls near the top.
4068
- */
4069
- loadMoreMessages(): Promise<boolean>;
4070
- /**
4071
- * Reset pagination when switching conversations (page 0 is loaded by {@link AXConversationService.selectConversation}).
4072
- */
4073
- resetPagination(): void;
4074
- getMenuActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
4075
- executeAction(message: AXConversationMessage, actionId: string): Promise<void>;
4076
- reactToMessage(messageId: string, emoji: string): Promise<void>;
4077
- /** Request message list to scroll to bottom */
4078
- requestScrollToBottom(): void;
4079
- private buildCountMap;
4080
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListService, never>;
4081
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationMessageListService>;
4082
- }
4083
-
4084
- declare class AXConversationSidebarService {
4085
- private readonly conversationService;
4086
- constructor();
4087
- private get registry();
4088
- readonly searchQuery: _angular_core.WritableSignal<string>;
4089
- readonly activeTabId: _angular_core.WritableSignal<string>;
4090
- readonly loadingMore: _angular_core.WritableSignal<boolean>;
4091
- readonly conversations: _angular_core.Signal<AXConversation[]>;
4092
- readonly loading: _angular_core.Signal<boolean>;
4093
- readonly hasMoreConversations: _angular_core.Signal<boolean>;
4094
- readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
4095
- readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
4096
- /**
4097
- * Filter and sort conversations
4098
- */
4099
- private filterAndSort;
4100
- setSearchQuery(q: string): void;
4101
- setActiveTab(tabId: string): void;
4102
- selectConversation(conversation: AXConversation): void;
4103
- getBadgeValue(tabId: string): string | undefined;
4104
- /**
4105
- * Load more conversations when the user scrolls near the bottom of the sidebar list.
4106
- */
4107
- loadMoreConversations(): Promise<void>;
4108
- /**
4109
- * Handle scroll threshold (for infinite scroll)
4110
- */
4111
- onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
4112
- /**
4113
- * Reload conversation list from the first page (e.g. pull-to-refresh).
4114
- */
4115
- reloadConversations(): Promise<void>;
4116
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationSidebarService, never>;
4117
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationSidebarService>;
4118
- }
4119
-
4120
- declare class AXConversationSidebarComponent implements OnDestroy {
4121
- readonly sidebar: AXConversationSidebarService;
4122
- protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
4123
- private readonly conversationService;
4124
- private readonly popupService;
4125
- private readonly translation;
4126
- private readonly ngZone;
4127
- private readonly cdr;
4128
- /** Conversation selected event */
4129
- readonly conversationSelected: _angular_core.OutputEmitterRef<AXConversation>;
4130
- /** Search debouncing */
4131
- private readonly searchSubject;
4132
- /** Derived state for template */
4133
- readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
4134
- readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
4135
- readonly loading: _angular_core.Signal<boolean>;
4136
- readonly loadingMore: _angular_core.WritableSignal<boolean>;
4137
- readonly hasMoreConversations: _angular_core.Signal<boolean>;
4138
- constructor();
4139
- /** Handle search input change with debouncing */
4140
- onSearchChange(value: string): void;
4141
- /** Handle tab change from ax-tabs */
4142
- onTabChange(event: {
4143
- tab?: {
4144
- key?: string;
4145
- };
4146
- }): void;
4147
- /** Select a conversation */
4148
- selectConversation(conversation: AXConversation): void;
4149
- /** Get badge value for tab */
4150
- getBadgeValue(tabId: string): string | undefined;
4151
- getTabLabel(tabId: string): string;
4152
- openNewConversationPopup(): Promise<void>;
4153
- /** Handle infinite scroll threshold - delegate to service */
4154
- onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
4155
- /** Cleanup on destroy */
4156
- ngOnDestroy(): void;
4157
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationSidebarComponent, never>;
4158
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationSidebarComponent, "ax-conversation-sidebar", never, {}, { "conversationSelected": "conversationSelected"; }, never, ["ax-suffix"], true, never>;
4159
- }
4160
-
4161
- type AXConversationNewWizardStep = 'selectUsers' | 'groupDetails';
4162
- declare class AXConversationNewDialogComponent extends AXBasePageComponent {
3827
+ static isSameDay(date1: Date, date2: Date): boolean;
4163
3828
  /**
4164
- * Assigned by {@link AXPopupComponent} from `open(..., { data: { conversationService } })`.
4165
- * Not injected: popup content is created on the root view container, so route-scoped providers
4166
- * would not see the same `AXConversationService` instance as the conversation feature.
3829
+ * Get date key for grouping (YYYY-MM-DD)
4167
3830
  */
4168
- conversationService: AXConversationService;
4169
- private readonly toastService;
4170
- private readonly translation;
4171
- private readonly config;
4172
- private readonly destroyRef;
4173
- private searchDebounceTimer?;
4174
- constructor();
3831
+ static getDateKey(date: Date): string;
4175
3832
  /**
4176
- * Injected by {@link AXPopupComponent} when this dialog is opened via {@link AXPopupService}.
4177
- * Required for `setTitle` / dynamic header — {@link AXBasePageComponent#setTitle} is otherwise unset.
3833
+ * Format time (HH:MM)
4178
3834
  */
4179
- readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4180
- readonly availableUsers: _angular_core.WritableSignal<AXConversationParticipant[]>;
4181
- readonly selectedUserIds: _angular_core.WritableSignal<string[]>;
4182
- readonly groupTitle: _angular_core.WritableSignal<string>;
4183
- readonly groupAvatar: _angular_core.WritableSignal<string>;
4184
- readonly searchQuery: _angular_core.WritableSignal<string>;
4185
- readonly creating: _angular_core.WritableSignal<boolean>;
4186
- /** For 2+ users: step 1 = pick users, step 2 = title + avatar. */
4187
- readonly wizardStep: _angular_core.WritableSignal<AXConversationNewWizardStep>;
4188
- readonly showUserPickerStep: _angular_core.Signal<boolean>;
4189
- readonly showGroupDetailsStep: _angular_core.Signal<boolean>;
4190
- readonly showNextButton: _angular_core.Signal<boolean>;
4191
- readonly showGroupBackButton: _angular_core.Signal<boolean>;
4192
- readonly showCreateButton: _angular_core.Signal<boolean>;
4193
- readonly canGoNextToGroupDetails: _angular_core.Signal<boolean>;
4194
- readonly canCreate: _angular_core.Signal<boolean>;
4195
- private readonly _resetWizardWhenSingleEffect;
4196
- private readonly _syncPopupTitleEffect;
4197
- readonly usersListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
4198
- readonly usersListLoadingTpl: _angular_core.Signal<TemplateRef<unknown>>;
4199
- readonly usersList: _angular_core.Signal<AXListComponent>;
4200
- readonly usersListDataSource: AXDataSource<unknown>;
4201
- onCancel(): void;
4202
- onSelectedUsersChange(ids: string[]): void;
4203
- onNextToGroupDetails(): void;
4204
- onBackFromGroupDetails(): void;
4205
- onSearchChange(value: string): void;
4206
- isUserSelected(id: string): boolean;
4207
- userFromItem(item: unknown): AXConversationParticipant | null;
4208
- private mergeUsersCache;
4209
- onCreateConversation(): Promise<void>;
4210
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationNewDialogComponent, never>;
4211
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationNewDialogComponent, "ax-conversation-new-dialog", never, { "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4212
- }
4213
-
4214
- declare class AXConversationInfiniteScrollDirective {
4215
- private readonly elementRef;
4216
- private readonly platformId;
4217
- /** Threshold in pixels from the edge to trigger the event */
4218
- readonly threshold: _angular_core.InputSignal<number>;
4219
- /** Which edge to watch: 'top', 'bottom', or 'both' */
4220
- readonly edge: _angular_core.InputSignal<"top" | "bottom" | "both">;
4221
- /** When true, scroll events are ignored (e.g. while a page is loading). */
4222
- readonly scrollDisabled: _angular_core.InputSignal<boolean>;
4223
- /** Minimum time between emissions (ms) to avoid duplicate API calls. */
4224
- readonly cooldownMs: _angular_core.InputSignal<number>;
4225
- /** Event emitted when scrolling reaches the threshold */
4226
- readonly scrollThreshold: _angular_core.OutputEmitterRef<"top" | "bottom">;
4227
- private lastScrollTop;
4228
- private ticking;
4229
- private lastEmitAt;
4230
- private pendingEmit;
4231
- constructor();
4232
- private setupScrollListener;
4233
- private handleScroll;
4234
- private emitThreshold;
4235
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfiniteScrollDirective, never>;
4236
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AXConversationInfiniteScrollDirective, "[axInfiniteScroll]", never, { "threshold": { "alias": "threshold"; "required": false; "isSignal": true; }; "edge": { "alias": "edge"; "required": false; "isSignal": true; }; "scrollDisabled": { "alias": "scrollDisabled"; "required": false; "isSignal": true; }; "cooldownMs": { "alias": "cooldownMs"; "required": false; "isSignal": true; }; }, { "scrollThreshold": "scrollThreshold"; }, never, never, true, never>;
3835
+ static formatTime(date: Date): string;
4237
3836
  }
4238
3837
 
4239
3838
  /**
@@ -4251,6 +3850,12 @@ declare function isComposerTabEnabled(tab: AXConversationComposerTabFeature, fea
4251
3850
  * Conversation Configuration Interface
4252
3851
  * Centralized configuration values to avoid magic numbers
4253
3852
  */
3853
+ /**
3854
+ * Sidebar conversation tabs layout.
3855
+ * - `vertical`: horizontal tab strip above the conversation list.
3856
+ * - `horizontal`: vertical tab strip at inline-start beside the list (`ax-tabs` location `start`).
3857
+ */
3858
+ type AXConversationSidebarTabsOrientation = 'vertical' | 'horizontal';
4254
3859
  /**
4255
3860
  * Main configuration interface for the conversation component
4256
3861
  */
@@ -4265,13 +3870,14 @@ interface AXConversationConfig {
4265
3870
  infiniteScrollThreshold?: number;
4266
3871
  /** Typing indicator timeout in milliseconds */
4267
3872
  typingIndicatorTimeout?: number;
4268
- /** Typing indicator throttle in milliseconds (for rate limiting) */
3873
+ /** Typing indicator emit throttle in milliseconds while composing (default: 3000) */
4269
3874
  typingIndicatorThrottle?: number;
3875
+ /** How long to show received typing indicators in the UI (default: 4000) */
3876
+ typingDisplayDuration?: number;
4270
3877
  /** Message highlight duration in milliseconds */
4271
3878
  messageHighlightDuration?: number;
4272
3879
  /** Search debounce delay in milliseconds */
4273
3880
  debounceSearch?: number;
4274
- /** Date separator inactivity fade delay in milliseconds */
4275
3881
  /** Maximum messages per conversation */
4276
3882
  maxMessagesPerConversation?: number;
4277
3883
  /** Maximum total messages in store */
@@ -4284,8 +3890,11 @@ interface AXConversationConfig {
4284
3890
  maxSidebarWidth?: number;
4285
3891
  /** Default sidebar width in pixels */
4286
3892
  defaultSidebarWidth?: number;
4287
- /** Filter cache size */
4288
- filterCacheSize?: number;
3893
+ /**
3894
+ * Sidebar conversation tabs layout.
3895
+ * `vertical` places a horizontal tab strip above the list; `horizontal` places a vertical tab strip at inline-start beside the list.
3896
+ */
3897
+ sidebarTabsOrientation?: AXConversationSidebarTabsOrientation;
4289
3898
  /** Maximum message length in characters */
4290
3899
  maxMessageLength?: number;
4291
3900
  /** Minimum message length in characters */
@@ -4294,7 +3903,7 @@ interface AXConversationConfig {
4294
3903
  maxFilesPerMessage?: number;
4295
3904
  /** Threshold for marking messages as read (0.0 to 1.0, default: 0.3) */
4296
3905
  messageReadThreshold?: number;
4297
- /** Debounce window (ms) before flushing batched read-receipt API calls (default: 400) */
3906
+ /** Debounce window (ms) before flushing batched read-receipt API calls (default: 3000) */
4298
3907
  messageReadDebounce?: number;
4299
3908
  /**
4300
3909
  * When true, marks the whole conversation as read once when it is selected (single API call).
@@ -4305,7 +3914,7 @@ interface AXConversationConfig {
4305
3914
  * CSS `background` for the message list (`ax-conversation-message-list` area, all states: loading, empty, messages).
4306
3915
  * Use full shorthand, or a bare `https://...` / `/path/to.png` (wrapped as `url(...)` with `center/cover`).
4307
3916
  * Pass a string for the same value in both themes, or `{ light, dark }` for theme-specific backgrounds.
4308
- * Empty string = library default. `transparent` or `none` = flat background.
3917
+ * Empty string = Telegram-inspired theme-aware library default (`{ light, dark }`). `transparent` or `none` = flat background.
4309
3918
  */
4310
3919
  messageListBackground?: AXConversationMessageListBackground;
4311
3920
  /** Optional feature flags to reduce bundle size per app. */
@@ -4315,31 +3924,20 @@ interface AXConversationConfig {
4315
3924
  }
4316
3925
 
4317
3926
  /**
4318
-
4319
3927
  * Default Configuration Values
4320
-
4321
3928
  * Centralized defaults to avoid magic numbers throughout the codebase
4322
-
4323
3929
  */
4324
3930
 
4325
3931
  /**
4326
-
4327
3932
  * Default conversation configuration
4328
-
4329
3933
  * All values are explicitly defined here for easy maintenance and documentation
4330
-
4331
3934
  */
4332
3935
  declare const AX_DEFAULT_CONVERSATION_CONFIG: Required<AXConversationConfig>;
4333
3936
  /**
4334
-
4335
3937
  * Helper function to merge user config with defaults
4336
-
4337
3938
  * Properly handles array merging to avoid reference issues
4338
-
4339
3939
  * @param userConfig - User-provided configuration
4340
-
4341
3940
  * @returns Merged configuration with all required fields
4342
-
4343
3941
  */
4344
3942
  declare function mergeWithDefaults(userConfig?: Partial<AXConversationConfig>): Required<AXConversationConfig>;
4345
3943
 
@@ -4379,6 +3977,12 @@ interface AXConversationUserAvatarComponent {
4379
3977
  interface AXConversationConversationAvatarComponent {
4380
3978
  readonly conversationId: InputSignal<string>;
4381
3979
  readonly size: InputSignal<number>;
3980
+ /** Optional resolved display name for the conversation. */
3981
+ readonly displayName?: InputSignal<string | undefined>;
3982
+ /** Optional resolved avatar URL when no platform conversation row exists. */
3983
+ readonly displayAvatar?: InputSignal<string | undefined>;
3984
+ /** Optional icon class when no avatar image is available. */
3985
+ readonly displayIcon?: InputSignal<string | undefined>;
4382
3986
  }
4383
3987
  type AXConversationAvatarKind = 'user' | 'conversation' | 'auto';
4384
3988
  declare const AX_CONVERSATION_USER_AVATAR_COMPONENT: InjectionToken<Type<AXConversationUserAvatarComponent>>;
@@ -4458,469 +4062,632 @@ interface AXConversationRegistryConfiguration {
4458
4062
  declare const AX_CONVERSATION_REGISTRY_CONFIG: InjectionToken<AXConversationRegistryConfiguration>;
4459
4063
 
4460
4064
  /**
4461
- * IndexedDB Storage Wrapper
4462
- * Provides persistent storage for conversation data
4065
+ * Validation Utilities
4066
+ * Centralized validation functions for messages and user input
4463
4067
  */
4464
4068
 
4465
- declare const AXConversationIndexedDbStores: {
4466
- readonly PARTICIPANTS: "participants";
4467
- readonly CONVERSATIONS: "conversations";
4468
- readonly MESSAGES: "messages";
4469
- readonly MEDIA: "media";
4470
- readonly SETTINGS: "settings";
4471
- };
4472
- /** Blob stored for demo multimedia uploads */
4473
- interface AXConversationIndexedDbMediaRecord {
4474
- id: string;
4475
- conversationId: string;
4476
- mimeType: string;
4477
- size: number;
4478
- fileName?: string;
4479
- blob: Blob;
4480
- createdAt: string;
4481
- }
4482
- declare class AXConversationIndexedDbStorage {
4483
- private db;
4484
- private initPromise;
4485
- /**
4486
- * Initialize IndexedDB
4487
- */
4488
- init(): Promise<void>;
4489
- /**
4490
- * Get a value from a store
4491
- */
4492
- get<T>(storeName: string, key: string): Promise<T | undefined>;
4493
- /**
4494
- * Get all values from a store
4495
- */
4496
- getAll<T>(storeName: string): Promise<T[]>;
4497
- /**
4498
- * Get values by index
4499
- */
4500
- getAllByIndex<T>(storeName: string, indexName: string, query: IDBValidKey): Promise<T[]>;
4501
- /**
4502
- * Put a value into a store
4503
- */
4504
- put<T>(storeName: string, value: T): Promise<void>;
4505
- /**
4506
- * Delete a value from a store
4507
- */
4508
- delete(storeName: string, key: string): Promise<void>;
4509
- /**
4510
- * Clear all data from a store
4511
- */
4512
- clear(storeName: string): Promise<void>;
4513
- getParticipant(id: string): Promise<AXConversationParticipant | undefined>;
4514
- getAllParticipants(): Promise<AXConversationParticipant[]>;
4515
- putParticipant(participant: AXConversationParticipant): Promise<void>;
4516
- getConversation(id: string): Promise<AXConversation | undefined>;
4517
- getAllConversations(): Promise<AXConversation[]>;
4518
- putConversation(conversation: AXConversation): Promise<void>;
4519
- deleteConversation(id: string): Promise<void>;
4520
- getMessage(id: string): Promise<AXConversationMessage | undefined>;
4521
- getAllMessages(): Promise<AXConversationMessage[]>;
4522
- getMessagesByConversation(conversationId: string): Promise<AXConversationMessage[]>;
4523
- putMessage(message: AXConversationMessage): Promise<void>;
4524
- deleteMessage(id: string): Promise<void>;
4525
- getSetting(key: string): Promise<unknown>;
4526
- putSetting(key: string, value: unknown): Promise<void>;
4527
- getMedia(id: string): Promise<AXConversationIndexedDbMediaRecord | undefined>;
4528
- putMedia(record: AXConversationIndexedDbMediaRecord): Promise<void>;
4529
- deleteMedia(id: string): Promise<void>;
4530
- }
4531
- declare const axConversationIndexedDbStorage: AXConversationIndexedDbStorage;
4532
-
4533
4069
  /**
4534
- * Shared In-Memory Storage
4535
- * Internal storage shared between all IndexedDB API implementations
4536
- * This is NOT a service - just a shared data structure
4070
+ * Validation result interface
4537
4071
  */
4538
-
4539
- declare class AXConversationSharedStorage {
4540
- readonly connectionStatus$: BehaviorSubject<AXConversationConnectionStatus>;
4541
- readonly participants: Map<string, AXConversationParticipant>;
4542
- readonly conversations: Map<string, AXConversation>;
4543
- readonly messages: Map<string, AXConversationMessage>;
4544
- readonly messagesByConversation: Map<string, string[]>;
4545
- readonly messageStream$: Subject<AXConversationMessage>;
4546
- readonly messageUpdates$: Subject<AXConversationMessage>;
4547
- readonly messageDeletions$: Subject<string>;
4548
- readonly typingIndicators$: Subject<AXConversationTypingIndicator>;
4549
- readonly presenceUpdates$: Subject<AXConversationPresenceUpdate>;
4550
- readonly conversationUpdates$: Subject<AXConversation>;
4551
- readonly currentUserId = "current-user";
4552
- private isSeeded;
4553
- private presenceInterval?;
4554
- private messageSimulationInterval?;
4555
- private isLoadedFromDB;
4556
- /**
4557
- * Load data from IndexedDB
4558
- */
4559
- loadFromIndexedDB(): Promise<void>;
4560
- /**
4561
- * Seed initial data if not already seeded
4562
- */
4563
- seedIfEmpty(): Promise<void>;
4564
- /** Wipe in-memory and persisted demo data (used when seed version changes). */
4565
- private clearAllData;
4566
- /** @internal Used by demo seed module */
4567
- markSeeded(): void;
4568
- /** @internal Starts demo presence and message simulations */
4569
- startDemoSimulations(): void;
4570
- /**
4571
- * Simulate user presence changes (online/offline/away)
4572
- */
4573
- private startPresenceSimulation;
4574
- /**
4575
- * Simulate random messages from users
4576
- */
4577
- private startMessageSimulation;
4578
- /**
4579
- * Stop presence simulation
4580
- */
4581
- stopPresenceSimulation(): void;
4582
- /**
4583
- * Stop message simulation
4584
- */
4585
- stopMessageSimulation(): void;
4072
+ interface AXConversationValidationResult {
4073
+ /** Whether validation passed */
4074
+ valid: boolean;
4075
+ /** Error message if validation failed */
4076
+ error?: string;
4077
+ /** Error code for programmatic handling */
4078
+ errorCode?: string;
4586
4079
  }
4587
- declare const axConversationSharedStorage: AXConversationSharedStorage;
4588
-
4589
- declare const AX_CONVERSATION_DEMO_CONVERSATION_IDS: {
4590
- readonly private: "conv-demo-private";
4591
- readonly group: "conv-demo-group";
4592
- readonly channel: "conv-demo-channel";
4593
- };
4594
- declare function seedSharedStorageInitialData(storage: AXConversationSharedStorage): Promise<void>;
4595
-
4596
4080
  /**
4597
- * Chat-oriented pagination helpers for IndexedDB demo APIs.
4598
- *
4599
- * Convention (matches {@link AXConversationService}):
4600
- * - Page 0: newest items (sidebar: recent chats; messages: latest history window).
4601
- * - Page 1+ or `cursor`: older items before the previous window.
4602
- * - `hasMore`: true when older items remain.
4603
- * - `nextCursor`: id of the oldest item in the current page (use as `pagination.cursor` for the next request).
4604
- */
4605
-
4606
- declare const AX_CONVERSATION_MESSAGE_CURSOR_PREFIX = "msg:";
4607
- declare const AX_CONVERSATION_CURSOR_PREFIX = "conv:";
4608
- type AXConversationChatCursorKind = 'message' | 'conversation';
4609
- interface AXConversationParsedChatCursor {
4610
- kind: AXConversationChatCursorKind;
4611
- id: string;
4612
- }
4613
- declare function encodeMessageCursor(messageId: string): string;
4614
- declare function encodeConversationCursor(conversationId: string): string;
4615
- /** Decode cursor from API pagination (supports prefixed or legacy raw message id). */
4616
- declare function parseChatCursor(cursor?: string): AXConversationParsedChatCursor | null;
4081
+ * Validate message text content
4082
+ * @param text - Text to validate
4083
+ * @param config - Configuration for validation rules
4084
+ * @returns Validation result
4085
+ */
4086
+ declare function validateMessageText(text: string | undefined, config: AXConversationConfig): AXConversationValidationResult;
4087
+ /**
4088
+ * Validate conversation ID
4089
+ * @param conversationId - Conversation ID to validate
4090
+ * @returns Validation result
4091
+ */
4092
+ declare function validateConversationId(conversationId: string | undefined): AXConversationValidationResult;
4617
4093
  /**
4618
- * Paginate a list sorted newest-first (chats, message history windows).
4094
+ * Validate message type
4095
+ * @param type - Message type to validate
4096
+ * @returns Validation result
4619
4097
  */
4620
- declare function paginateChatNewestFirst<T extends {
4621
- id: string;
4622
- }>(sortedNewestFirst: T[], pagination: AXConversationPagination, cursorKind: AXConversationChatCursorKind): AXConversationPaginatedResult<T>;
4098
+ declare function validateMessageType(type: AXConversationMessageType | undefined): AXConversationValidationResult;
4623
4099
  /**
4624
- * Paginate a list sorted oldest-first (replies, forward history).
4100
+ * Validate message payload
4101
+ * @param payload - Message payload to validate
4102
+ * @param type - Message type
4103
+ * @returns Validation result
4625
4104
  */
4626
- declare function paginateChatOldestFirst<T extends {
4105
+ declare function validateMessagePayload(payload: AXConversationMessagePayload | undefined, type: AXConversationMessageType): Promise<AXConversationValidationResult>;
4106
+ /**
4107
+ * Validate user ID
4108
+ * @param userId - User ID to validate
4109
+ * @returns Validation result
4110
+ */
4111
+ declare function validateUserId(userId: string | undefined): AXConversationValidationResult;
4112
+ /**
4113
+ * Validate array of user IDs
4114
+ * @param userIds - Array of user IDs to validate
4115
+ * @param minCount - Minimum number of users required
4116
+ * @param maxCount - Maximum number of users allowed
4117
+ * @returns Validation result
4118
+ */
4119
+ declare function validateUserIds(userIds: string[] | undefined, minCount?: number, maxCount?: number): AXConversationValidationResult;
4120
+ /**
4121
+ * Validate email address
4122
+ * @param email - Email to validate
4123
+ * @returns Validation result
4124
+ */
4125
+ declare function validateEmail(email: string | undefined): AXConversationValidationResult;
4126
+ /**
4127
+ * Validate URL
4128
+ * @param url - URL to validate
4129
+ * @returns Validation result
4130
+ */
4131
+ declare function validateUrl(url: string | undefined): AXConversationValidationResult;
4132
+ /**
4133
+ * Sanitize user input to prevent XSS
4134
+ * Note: Angular provides built-in sanitization, but this is an additional layer
4135
+ * @param input - User input to sanitize
4136
+ * @returns Sanitized input
4137
+ */
4138
+ declare function sanitizeInput(input: string): string;
4139
+ /**
4140
+ * Validate latitude coordinate
4141
+ * @param latitude - Latitude to validate
4142
+ * @returns Validation result
4143
+ */
4144
+ declare function validateLatitude(latitude: number | undefined | null): AXConversationValidationResult;
4145
+ /**
4146
+ * Validate longitude coordinate
4147
+ * @param longitude - Longitude to validate
4148
+ * @returns Validation result
4149
+ */
4150
+ declare function validateLongitude(longitude: number | undefined | null): AXConversationValidationResult;
4151
+
4152
+ /** Infer extension/MIME hints from a persisted message payload. */
4153
+ declare function inferFileExtensionHintFromMessage(message: AXConversationMessage): AXFileTypeExtensionHint;
4154
+ /** Use file-type `copy` on the message when `message.fileType` is set; otherwise fallback. */
4155
+ declare function copyWithFileTypeFallback(message: AXConversationMessage, registry: AXFileTypeRegistryService, fallback: () => string): Promise<string>;
4156
+ /** Use file-type `open` on the message when `message.fileType` is set. */
4157
+ declare function openWithFileType(message: AXConversationMessage, registry: AXFileTypeRegistryService, ctx: AXFileTypeOpenContext): Promise<boolean>;
4158
+
4159
+ interface AXConversationInfoProfileField {
4627
4160
  id: string;
4628
- }>(sortedOldestFirst: T[], pagination: AXConversationPagination): AXConversationPaginatedResult<T>;
4629
-
4630
- /**
4631
- * Pagination demo data — disabled for the minimal 3-chat showcase seed.
4632
- * Kept as a no-op so existing imports remain valid.
4633
- */
4634
- /** @deprecated Pagination demo chat removed from default seed. */
4635
- declare const AX_MESSAGE_PAGINATION_CONVERSATION_ID = "conv-pag-msgs";
4636
- /** No-op: showcase uses a fixed 3-conversation seed (private, group, channel). */
4637
- declare function ensurePaginationDemoData(): Promise<void>;
4638
-
4639
- /**
4640
- * Shared read/write helpers for IndexedDB chat storage (in-memory + persistence).
4641
- */
4642
-
4643
- declare function getConversationLastActivity(conv: AXConversation): number;
4644
- /** Messages for a conversation, newest first (API / pagination order). */
4645
- declare function getConversationMessagesNewestFirst(conversationId: string): AXConversationMessage[];
4646
- /** Keep per-conversation id list sorted ascending by timestamp (store order). */
4647
- declare function sortConversationMessageIds(conversationId: string): void;
4648
- /** Register a message in maps and keep the conversation index sorted. */
4649
- declare function registerChatMessage(message: AXConversationMessage): void;
4650
- /** Remove a message from conversation index and global map. */
4651
- declare function unregisterChatMessage(messageId: string, conversationId: string): void;
4652
- declare function applyConversationFilters(conversations: AXConversation[], filters?: AXConversationFilters): AXConversation[];
4653
- /** Sidebar list order: pinned first, then by last activity (newest first). */
4654
- declare function getSortedConversationsForInbox(filters?: AXConversationFilters): AXConversation[];
4655
- /** Sort all loaded conversation message indexes (after IndexedDB hydration). */
4656
- declare function normalizeAllConversationMessageIndexes(): void;
4657
-
4658
- declare class AXConversationIndexedDbUserApi extends AXConversationUserApi {
4659
- private readonly API_DELAY_MS;
4660
- getCurrentUser(): Promise<AXConversationParticipant>;
4661
- updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationParticipant>;
4662
- uploadAvatar(file: File): Promise<string>;
4663
- getUsers(pagination?: AXConversationPagination, filters?: AXConversationUserSearchFilters): Promise<AXConversationPaginatedResult<AXConversationParticipant>>;
4664
- searchUsers(query: string): Promise<AXConversationParticipant[]>;
4665
- getUserById(userId: string): Promise<AXConversationParticipant>;
4666
- getUsersByIds(userIds: string[]): Promise<AXConversationParticipant[]>;
4667
- getUserPresence(userId: string): Promise<AXConversationPresenceUpdate>;
4668
- updatePresence(_status: AXConversationPresenceStatus, _statusText?: string): Promise<void>;
4669
- blockUser(_userId: string, _reason?: AXConversationBlockReportReason): Promise<void>;
4670
- unblockUser(_userId: string): Promise<void>;
4671
- getBlockedUsers(): Promise<string[]>;
4672
- reportUser(_userId: string, _reason: AXConversationBlockReportReason): Promise<void>;
4673
- getUserSettings(): Promise<Record<string, unknown>>;
4674
- updateUserSettings(_settings: Record<string, unknown>): Promise<void>;
4675
- private getCurrentUserWithoutDelay;
4676
- private fetchUsers;
4677
- private delay;
4678
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbUserApi, never>;
4679
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbUserApi>;
4161
+ labelKey: string;
4162
+ value: string;
4163
+ icon: string;
4680
4164
  }
4681
-
4682
- declare class AXConversationIndexedDbConversationApi extends AXConversationApi {
4683
- createConversation(data: AXConversationCreateData): Promise<AXConversation>;
4684
- getConversation(conversationId: string): Promise<AXConversation>;
4685
- /**
4686
- * Inbox page (pinned + recent activity, newest first).
4687
- * Page 0 / cursor align with {@link AXConversationService.loadConversations} and sidebar infinite scroll.
4688
- */
4689
- getConversations(pagination: AXConversationPagination, filters?: AXConversationFilters): Promise<AXConversationPaginatedResult<AXConversation>>;
4690
- updateConversation(conversationId: string, updates: AXConversationUpdateData): Promise<AXConversation>;
4691
- deleteConversation(conversationId: string): Promise<boolean>;
4692
- archiveConversation(conversationId: string): Promise<void>;
4693
- unarchiveConversation(conversationId: string): Promise<void>;
4694
- pinConversation(conversationId: string): Promise<void>;
4695
- unpinConversation(conversationId: string): Promise<void>;
4696
- markConversationAsRead(conversationId: string): Promise<void>;
4697
- markConversationAsUnread(conversationId: string): Promise<void>;
4698
- searchConversations(query: string): Promise<AXConversation[]>;
4699
- filterConversations(filters: AXConversationFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversation>>;
4700
- getParticipants(conversationId: string): Promise<AXConversationParticipant[]>;
4701
- addParticipants(_conversationId: string, _userIds: string[]): Promise<AXConversation>;
4702
- removeParticipant(conversationId: string, _userId: string): Promise<AXConversation>;
4703
- leaveConversation(_conversationId: string): Promise<void>;
4704
- updateParticipant(conversationId: string, _update: AXConversationParticipantUpdate): Promise<AXConversation>;
4705
- getConversationSettings(conversationId: string): Promise<AXConversationSettingsUpdate>;
4706
- updateConversationSettings(conversationId: string, settings: AXConversationSettingsUpdate): Promise<void>;
4707
- muteConversation(conversationId: string, duration?: number): Promise<void>;
4708
- unmuteConversation(conversationId: string): Promise<void>;
4709
- uploadConversationAvatar(_conversationId: string, file: File): Promise<string>;
4710
- getConversationMedia(conversationId: string, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<unknown>>;
4711
- addConversationTags(conversationId: string, tags: string[]): Promise<void>;
4712
- removeConversationTags(conversationId: string, tags: string[]): Promise<void>;
4713
- getConversationTags(conversationId: string): Promise<string[]>;
4714
- saveDraft(conversationId: string, draft: string): Promise<void>;
4715
- getDraft(conversationId: string): Promise<string | null>;
4716
- clearDraft(conversationId: string): Promise<void>;
4717
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbConversationApi, never>;
4718
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbConversationApi>;
4719
- }
4720
-
4721
- declare class AXConversationIndexedDbMessageApi extends AXConversationMessageApi {
4722
- sendMessage(command: AXConversationSendMessageCommand): Promise<AXConversationMessage>;
4723
- getMessage(messageId: string): Promise<AXConversationMessage>;
4724
- /**
4725
- * Message history for a chat (newest-first pages).
4726
- * - Page 0: latest `pageSize` messages.
4727
- * - Page 1+ or `pagination.cursor`: older messages before the previous window.
4728
- */
4729
- getMessages(conversationId: string, pagination: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4730
- editMessage(messageId: string, payload: AXConversationMessagePayload): Promise<AXConversationMessage>;
4731
- deleteMessage(messageId: string, _forEveryone?: boolean): Promise<void>;
4732
- deleteMessages(messageIds: string[], forEveryone?: boolean): Promise<void>;
4733
- searchMessages(conversationId: string, filters: AXConversationMessageSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4734
- searchAllMessages(filters: AXConversationMessageSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4735
- addReaction(messageId: string, emoji: string): Promise<void>;
4736
- removeReaction(messageId: string, emoji: string): Promise<void>;
4737
- getAvailableReactions(): Promise<string[]>;
4738
- markAsRead(conversationId: string, messageIds: string[]): Promise<void>;
4739
- markAsUnread(conversationId: string): Promise<void>;
4740
- getReadReceipts(_messageId: string): Promise<AXConversationReadReceipt[]>;
4741
- forwardMessage(_data: AXConversationMessageForwardData): Promise<AXConversationMessage[]>;
4742
- pinMessage(_conversationId: string, _messageId: string): Promise<void>;
4743
- unpinMessage(_conversationId: string, _messageId: string): Promise<void>;
4744
- getPinnedMessages(_conversationId: string): Promise<AXConversationPinnedMessage[]>;
4745
- getMessageReplies(messageId: string, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4746
- getReplyCount(messageId: string): Promise<number>;
4747
- getForwardCount(messageId: string): Promise<number>;
4748
- sendTypingIndicator(conversationId: string): Promise<void>;
4749
- stopTypingIndicator(conversationId: string): Promise<void>;
4750
- updateMessageMetadata(messageId: string, metadata: Record<string, unknown>): Promise<void>;
4751
- getMessageMetadata(messageId: string): Promise<Record<string, unknown>>;
4752
- updateMessageStatus(messageId: string, status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed'): Promise<void>;
4753
- getMessageDeliveryStatus(_messageId: string): Promise<{
4754
- delivered: number;
4755
- read: number;
4756
- total: number;
4757
- }>;
4758
- markMessagesAsRead(messageIds: string[]): Promise<void>;
4759
- bulkDeleteMessages(conversationId: string, messageIds: string[], forEveryone?: boolean): Promise<void>;
4760
- exportMessages(conversationId: string, _format: 'json' | 'csv' | 'txt'): Promise<string | Blob>;
4761
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbMessageApi, never>;
4762
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbMessageApi>;
4763
- }
4764
-
4765
- declare class AXConversationIndexedDbRealtimeApi extends AXConversationRealtimeApi {
4766
- readonly connectionStatus$: Observable<AXConversationConnectionStatus>;
4767
- connect(_options?: AXConversationConnectionOptions): Promise<void>;
4768
- disconnect(): Promise<void>;
4769
- isConnected(): boolean;
4770
- reconnect(): Promise<void>;
4771
- subscribeToConnectionEvents(): Observable<AXConversationConnectionEvent>;
4772
- subscribeToMessages(conversationId: string): Observable<AXConversationMessage>;
4773
- subscribeToMessageUpdates(_conversationId?: string): Observable<AXConversationMessage>;
4774
- subscribeToMessageDeletions(_conversationId?: string): Observable<string>;
4775
- subscribeToMessageReactions(_conversationId?: string): Observable<AXConversationMessage>;
4776
- subscribeToConversationUpdates(): Observable<AXConversation>;
4777
- subscribeToConversationCreated(): Observable<AXConversation>;
4778
- subscribeToConversationDeleted(): Observable<string>;
4779
- subscribeToTypingIndicators(conversationId: string): Observable<AXConversationTypingIndicator>;
4780
- subscribeToPresenceUpdates(_userIds?: string[]): Observable<AXConversationPresenceUpdate>;
4781
- subscribeToReadReceipts(_conversationId?: string): Observable<{
4782
- messageId: string;
4783
- userId: string;
4784
- readAt: Date;
4785
- }>;
4786
- subscribeToNotifications(): Observable<AXConversationNotificationEvent>;
4787
- subscribeToCallEvents(): Observable<AXConversationCallEvent>;
4788
- subscribeToUserBlockEvents(): Observable<{
4789
- userId: string;
4790
- blocked: boolean;
4791
- }>;
4792
- subscribeToParticipantEvents(_conversationId?: string): Observable<{
4793
- conversationId: string;
4794
- userId: string;
4795
- action: 'added' | 'removed';
4796
- }>;
4797
- subscribeToSystemEvents(): Observable<{
4798
- type: string;
4799
- message: string;
4800
- data?: any;
4801
- }>;
4802
- subscribeToMessageStatusChanges(_conversationId?: string): Observable<{
4803
- messageId: string;
4804
- status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
4805
- timestamp: Date;
4806
- }>;
4807
- subscribeToConversationSettingsChanges(_conversationId?: string): Observable<{
4808
- conversationId: string;
4809
- settings: Record<string, unknown>;
4810
- }>;
4811
- subscribeToDraftChanges(_conversationId?: string): Observable<{
4812
- conversationId: string;
4813
- draft: string | null;
4814
- }>;
4815
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbRealtimeApi, never>;
4816
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbRealtimeApi>;
4165
+ type AXConversationMediaCategoryId = 'image' | 'video' | 'file' | 'audio' | 'voice' | 'sticker' | 'location' | 'link';
4166
+ interface AXConversationMediaCategory {
4167
+ id: AXConversationMediaCategoryId;
4168
+ labelKey: string;
4169
+ countLabelKey: string;
4170
+ icon: string;
4171
+ count: number;
4172
+ }
4173
+ declare function messageContainsLink(message: AXConversationMessage): boolean;
4174
+ declare function getPrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
4175
+ declare function getConversationProfileFields(conversation: AXConversation, currentUserId?: string): AXConversationInfoProfileField[];
4176
+ declare function getConversationMediaCategories(messages: AXConversationMessage[]): AXConversationMediaCategory[];
4177
+ declare function filterMessagesByMediaCategory(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMessage[];
4178
+ declare function isGridMediaCategory(categoryId: AXConversationMediaCategoryId): boolean;
4179
+ declare function isAttachmentListCategory(categoryId: AXConversationMediaCategoryId): boolean;
4180
+ interface AXConversationMediaGalleryTile {
4181
+ key: string;
4182
+ message: AXConversationMessage;
4183
+ kind: 'image' | 'video' | 'sticker';
4184
+ image?: AXConversationImageMediaItem;
4185
+ video?: AXConversationVideoMediaItem;
4186
+ stickerUrl?: string;
4187
+ stickerAlt?: string;
4817
4188
  }
4189
+ declare function buildMediaGalleryTiles(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMediaGalleryTile[];
4190
+ declare function resolveVideoThumbnailUrl(video: AXConversationVideoMediaItem): string | undefined;
4191
+ declare function resolveGalleryImageUrl(image: AXConversationImageMediaItem): string | undefined;
4192
+ declare function getMessageVideoItems(message: AXConversationMessage): AXConversationVideoMediaItem[];
4193
+ declare function getMessageAudioItems(message: AXConversationMessage): AXConversationAudioMediaItem[];
4194
+ interface AXConversationMediaPageResult {
4195
+ items: AXConversationMessage[];
4196
+ hasMore: boolean;
4197
+ nextCursor?: string;
4198
+ page: number;
4199
+ }
4200
+ declare function fetchConversationMediaPage(conversationApi: AXConversationApi, conversationId: string, page: number, pageSize?: number, cursor?: string): Promise<AXConversationMediaPageResult>;
4201
+ /** Merge media API results with in-memory messages needed for link/sticker/voice/location tabs. */
4202
+ declare function mergeInfoPanelMessages(mediaMessages: AXConversationMessage[], supplemental: AXConversationMessage[]): AXConversationMessage[];
4203
+ declare function filterSupplementalInfoPanelMessages(messages: AXConversationMessage[]): AXConversationMessage[];
4818
4204
 
4819
- /**
4820
- * AI Responder Service
4821
- * Provides AI-powered automatic responses using Google Gemini API
4822
- *
4823
- * @security API key should be provided via injection token in production
4824
- * @example
4825
- * ```typescript
4826
- * export const AX_CONVERSATION_AI_API_KEY = new InjectionToken<string>('AX_CONVERSATION_AI_API_KEY');
4827
- *
4828
- * providers: [
4829
- * { provide: AX_CONVERSATION_AI_API_KEY, useValue: environment.geminiApiKey }
4830
- * ]
4831
- * ```
4832
- */
4833
-
4834
- /**
4835
- * Injection token for AI API key
4836
- * Provide this in your app config to avoid hardcoding the API key
4837
- */
4838
- declare const AX_CONVERSATION_AI_API_KEY: InjectionToken<string>;
4839
- /**
4840
- * Configuration for AI Responder
4841
- */
4842
- interface AXConversationAiResponderConfig {
4843
- /** Maximum retry attempts for failed requests */
4844
- maxRetries?: number;
4845
- /** Timeout for API requests in milliseconds */
4846
- timeout?: number;
4847
- /** Enable fallback to random replies on error */
4848
- useFallbackReplies?: boolean;
4205
+ interface AXConversationMessageDateGroup {
4206
+ date: string;
4207
+ dateKind: AXConversationDateSeparatorKind;
4208
+ dateLabel?: string;
4209
+ messages: AXConversationMessage[];
4849
4210
  }
4850
- declare class AXConversationAiResponderService {
4851
- private readonly injectedApiKey;
4852
- private readonly config;
4211
+ declare class AXConversationMessageListService {
4212
+ private readonly conversationService;
4213
+ private readonly translation;
4214
+ private readonly eventService;
4215
+ private readonly activeLocale;
4216
+ private readonly translationRevision;
4217
+ private get registry();
4218
+ readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
4219
+ readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
4220
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
4221
+ /** Initial message history load (conversation switch) */
4222
+ readonly loading: _angular_core.Signal<boolean>;
4223
+ /** Loading older messages (scroll-up pagination) */
4224
+ readonly loadingMore: _angular_core.WritableSignal<boolean>;
4225
+ /** Whether older messages can be loaded */
4226
+ readonly hasMoreMessages: _angular_core.Signal<boolean>;
4227
+ /** Show scroll to bottom button */
4228
+ readonly showScrollButton: _angular_core.WritableSignal<boolean>;
4229
+ /** Scroll requests counter */
4230
+ readonly scrollRequests: _angular_core.WritableSignal<number>;
4231
+ /** Live renderer instances keyed by message id (for message actions). */
4232
+ private readonly _rendererInstances;
4233
+ /**
4234
+ * Reply counts merged from API fields and loaded messages.
4235
+ */
4236
+ readonly replyCounts: _angular_core.Signal<Map<string, number>>;
4853
4237
  /**
4854
- * Get API key from injection token
4855
- * Returns undefined if not configured - service will use fallback responses
4238
+ * Forward counts merged from API fields and loaded messages.
4856
4239
  */
4857
- private getApiKey;
4240
+ readonly forwardCounts: _angular_core.Signal<Map<string, number>>;
4241
+ registerRendererInstance(messageId: string, instance: AXConversationMessageRendererComponent): void;
4242
+ unregisterRendererInstance(messageId: string): void;
4243
+ getRendererInstance(messageId: string): AXConversationMessageRendererComponent | undefined;
4244
+ getReplyCount(messageId: string): number;
4245
+ getForwardCount(messageId: string): number;
4246
+ /** Message grouped by date */
4247
+ readonly messageGroups: _angular_core.Signal<AXConversationMessageDateGroup[]>;
4858
4248
  /**
4859
- * Get AI-powered response for a given prompt
4860
- * @param prompt - The user's message to respond to
4861
- * @param retryCount - Current retry attempt (internal use)
4862
- * @returns AI-generated response or fallback message
4249
+ * Load older messages when the user scrolls near the top.
4863
4250
  */
4864
- getAIResponse(prompt: string, retryCount?: number): Promise<string>;
4251
+ loadMoreMessages(): Promise<boolean>;
4865
4252
  /**
4866
- * Fetch with timeout
4253
+ * Reset pagination when switching conversations (page 0 is loaded by {@link AXConversationService.selectConversation}).
4867
4254
  */
4868
- private fetchWithTimeout;
4255
+ resetPagination(): void;
4256
+ getMenuActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
4257
+ executeAction(message: AXConversationMessage, actionId: string): Promise<void>;
4258
+ reactToMessage(messageId: string, emoji: string): Promise<void>;
4259
+ /** Request message list to scroll to bottom */
4260
+ requestScrollToBottom(): void;
4261
+ private buildCountMap;
4262
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListService, never>;
4263
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationMessageListService>;
4264
+ }
4265
+
4266
+ declare class AXConversationMessageListComponent implements OnDestroy {
4267
+ private readonly conversationService;
4268
+ private readonly messageListService;
4269
+ private readonly composerService;
4270
+ private readonly fileService;
4271
+ private readonly toast;
4272
+ private readonly infoBarService;
4273
+ private readonly translation;
4274
+ private readonly document;
4275
+ private readonly platform;
4276
+ private readonly actionSheetService;
4277
+ protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
4869
4278
  /**
4870
- * Delay helper for retry logic
4279
+ * Background for the message list scroll area from config, or the built-in soft wash when unset/empty.
4280
+ * Set `messageListBackground` to `transparent` or `none` for a flat look.
4281
+ * Supports `{ light, dark }` for theme-specific backgrounds.
4871
4282
  */
4872
- private delay;
4283
+ readonly messageListUsesDefaultWallpaper: _angular_core.Signal<boolean>;
4284
+ readonly messageListWallpaperDark: _angular_core.Signal<boolean>;
4285
+ readonly messageListBackgroundStyle: _angular_core.Signal<string>;
4286
+ resolvedEmptyStateComponent(): Type<AXConversationMessageListEmptyComponent>;
4287
+ /** Fallback when no conversation is active and no `ax-conversation-message-list-no-active` content is projected. */
4288
+ protected readonly noActiveFallbackComponent: typeof AXConversationMessageListNoActiveDefaultComponent;
4289
+ private readonly timeouts;
4290
+ readonly reactionPickerTarget: _angular_core.WritableSignal<string>;
4291
+ readonly reactionPickerElement: _angular_core.WritableSignal<HTMLElement>;
4292
+ readonly reactionPickerPlacement: _angular_core.WritableSignal<AXPlacement>;
4293
+ readonly reactionPopover: _angular_core.Signal<any>;
4294
+ /** Message id whose context menu is open (for active row styling). */
4295
+ readonly contextMenuMessageId: _angular_core.WritableSignal<string>;
4296
+ /** True while files are dragged over the message list drop zone. */
4297
+ readonly messageListDragging: _angular_core.WritableSignal<boolean>;
4298
+ /** True when the message list uses single-column adaptive layout (matches CSS container query). */
4299
+ readonly isAdaptiveWideLayout: _angular_core.WritableSignal<boolean>;
4300
+ /** While true, older history is being prepended — do not auto-scroll to the latest message. */
4301
+ private restoringScrollAfterPrepend;
4302
+ private adaptiveLayoutResizeObserver?;
4303
+ readonly availableReactions: _angular_core.WritableSignal<string[]>;
4304
+ private reactionsLoading;
4305
+ private get registry();
4306
+ /** Message list element reference */
4307
+ private readonly messageListRef;
4308
+ /** Messages container element reference */
4309
+ private readonly messagesContainerRef;
4310
+ /** Loading state - use service */
4311
+ readonly loading: _angular_core.Signal<boolean>;
4312
+ /** Loading more messages state - use service */
4313
+ readonly loadingMore: _angular_core.WritableSignal<boolean>;
4314
+ /** Whether older messages remain on the server */
4315
+ readonly hasMoreMessages: _angular_core.Signal<boolean>;
4316
+ /** Show scroll to bottom button - use service */
4317
+ readonly showScrollButton: _angular_core.WritableSignal<boolean>;
4318
+ /** Active conversation */
4319
+ readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
4320
+ readonly isGroupConversation: _angular_core.Signal<boolean>;
4321
+ /** Placeholder rows for the initial message list skeleton. */
4322
+ protected readonly loadingSkeletonItems: readonly [0, 1, 2, 3, 4, 5, 6, 7];
4323
+ /** Whether the active conversation allows message reactions. */
4324
+ readonly reactionsEnabled: _angular_core.Signal<boolean>;
4325
+ /** Messages */
4326
+ readonly messages: _angular_core.Signal<AXConversationMessage[]>;
4327
+ /** Message action event */
4328
+ readonly messageAction: _angular_core.OutputEmitterRef<{
4329
+ message: AXConversationMessage;
4330
+ action: string;
4331
+ }>;
4332
+ /** Current user from service */
4333
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
4334
+ /** Message grouped by date - use service */
4335
+ readonly messageGroups: _angular_core.Signal<AXConversationMessageDateGroup[]>;
4336
+ constructor();
4337
+ private intersectionObserver?;
4338
+ private readonly readIntersectionObserver;
4339
+ private readonly observedReadMessageIds;
4340
+ /**
4341
+ * Setup intersection observer to mark messages as read when visible
4342
+ */
4343
+ private setupIntersectionObserver;
4873
4344
  /**
4874
- * Get a random fallback reply when AI is unavailable
4345
+ * Mark message as read
4875
4346
  */
4876
- private getFallbackReply;
4347
+ private markMessageAsRead;
4348
+ getMessageClusterRole(message: AXConversationMessage, previous?: AXConversationMessage, next?: AXConversationMessage): AXConversationMessageClusterRole;
4349
+ getSenderNameColor(senderId: string): string;
4350
+ /** Get message CSS classes */
4351
+ getMessageClasses(message: AXConversationMessage, cluster: AXConversationMessageClusterRole): string;
4352
+ /** Get bubble CSS classes */
4353
+ getBubbleClasses(message: AXConversationMessage): string;
4354
+ /** Check if message is from current user */
4355
+ isOwnMessage(message: AXConversationMessage): boolean;
4356
+ /** Whether the avatar slot is rendered (visibility is CSS-controlled per layout mode). */
4357
+ shouldRenderAvatar(message: AXConversationMessage): boolean;
4358
+ /** Should show sender name */
4359
+ shouldShowSenderName(message: AXConversationMessage, cluster: AXConversationMessageClusterRole): boolean;
4360
+ /** Get sender name */
4361
+ getSenderName(message: AXConversationMessage): string;
4362
+ /** Get original sender name for forwarded messages */
4363
+ getOriginalSenderName(message: AXConversationMessage): string;
4364
+ /** Get forwarded text with sender and conversation info */
4365
+ getForwardedText(message: AXConversationMessage): string;
4366
+ /** Resolve renderer component for message */
4367
+ getRendererComponent(message: AXConversationMessage): Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
4368
+ /** Resolve lazy renderer loader for message */
4369
+ private static readonly fallbackRendererLoader;
4370
+ getRendererComponentLoader(message: AXConversationMessage): (() => Promise<Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
4371
+ /** Provide inputs for the dynamic renderer */
4372
+ getRendererInputs(message: AXConversationMessage): {
4373
+ message: AXConversationMessage;
4374
+ };
4375
+ /** Get status icon CSS classes */
4376
+ getStatusIconClasses(message: AXConversationMessage): string;
4377
+ /** Get status tooltip text */
4378
+ getStatusTooltip(message: AXConversationMessage): string;
4379
+ /** Get first unread message ID */
4380
+ readonly firstUnreadMessageId: _angular_core.Signal<string>;
4381
+ /** Get grouped reactions */
4382
+ getGroupedReactions(message: AXConversationMessage): Array<{
4383
+ emoji: string;
4384
+ count: number;
4385
+ userIds: string[];
4386
+ hasReacted: boolean;
4387
+ }>;
4388
+ /** Get reaction tooltip text */
4389
+ getReactionTooltip(reaction: {
4390
+ emoji: string;
4391
+ count: number;
4392
+ userIds: string[];
4393
+ hasReacted: boolean;
4394
+ }): string;
4395
+ /** Whether reactions can be shown or added for a message in the active conversation. */
4396
+ messageSupportsReactions(message: AXConversationMessage): boolean;
4397
+ /** Toggle reaction picker */
4398
+ toggleReactionPicker(message: AXConversationMessage, event: MouseEvent): void;
4399
+ /** Close reaction picker */
4400
+ closeReactionPicker(): void;
4401
+ /** Check if current user has reacted with specific emoji */
4402
+ hasUserReacted(message: AXConversationMessage, emoji: string): boolean;
4403
+ /** Check if current user has reacted with specific emoji by message ID */
4404
+ hasUserReactedById(messageId: string, emoji: string): boolean;
4405
+ /** Handle reaction click by message ID */
4406
+ onReactionClickById(messageId: string, emoji: string): void;
4407
+ /** Get message by ID */
4408
+ getMessageById(messageId: string): AXConversationMessage | undefined;
4409
+ /** Load available reactions when the picker is opened (session-cached in service). */
4410
+ private ensureAvailableReactions;
4411
+ /** Get message actions from registry */
4412
+ getMessageActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
4413
+ /** Handle reaction click */
4414
+ onReactionClick(message: AXConversationMessage, emoji: string): void;
4415
+ /** Handle message action */
4416
+ onMessageAction(message: AXConversationMessage, action: any): Promise<void>;
4417
+ /** Handle scroll events */
4418
+ onScroll(event: Event): void;
4419
+ /** Handle infinite scroll threshold */
4420
+ onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
4421
+ /** Load older messages - delegate to service and preserve scroll anchor */
4422
+ private loadOlderMessages;
4877
4423
  /**
4878
- * Check if AI service is available
4879
- * @returns true if API key is configured
4424
+ * Keep the user's viewport on the same messages after older rows are inserted above.
4880
4425
  */
4881
- isAvailable(): boolean;
4426
+ private restoreScrollPositionAfterPrepend;
4427
+ /** Check if user is near bottom of scroll */
4428
+ private isUserNearBottom;
4882
4429
  /**
4883
- * Update configuration
4430
+ * After switching chats, the template may still show loading (no #messagesContainer).
4431
+ * Poll with rAF until the feed exists, then scroll after double rAF so scrollHeight is stable.
4884
4432
  */
4885
- configure(config: Partial<AXConversationAiResponderConfig>): void;
4886
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAiResponderService, never>;
4887
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationAiResponderService>;
4433
+ private scrollToBottomWhenContainerReady;
4434
+ /** Scroll to bottom */
4435
+ scrollToBottom(smooth?: boolean): void;
4436
+ /** Scroll to specific message */
4437
+ scrollToMessage(messageId: string): void;
4438
+ /** Cleanup timeouts and observers on destroy */
4439
+ ngOnDestroy(): void;
4440
+ /** Get message preview text for reply */
4441
+ getMessagePreviewText(message: AXConversationMessage): {
4442
+ value: string;
4443
+ type: string;
4444
+ icon: string;
4445
+ };
4446
+ /** Get ARIA label for message */
4447
+ getMessageAriaLabel(message: AXConversationMessage): string;
4448
+ getDateSeparatorAriaLabel(group: AXConversationMessageDateGroup): string;
4449
+ resolveDateSeparatorLabel(group: AXConversationMessageDateGroup): string;
4450
+ getReplyCount(message: AXConversationMessage): number;
4451
+ getForwardCount(message: AXConversationMessage): number;
4452
+ onMessageListDragEnter(): void;
4453
+ onMessageListDragLeave(): void;
4454
+ /** Open the matching composer picker popup when files are dropped on the message list. */
4455
+ onMessageListFilesDropped(event: AXUploaderFileChangeEvent): Promise<void>;
4456
+ private composerPickerDeps;
4457
+ /** Handle context menu opening for messages */
4458
+ handleMessageContextMenuOpening(event: AXContextMenuOpeningEvent, message: AXConversationMessage): void;
4459
+ /** Handle context menu item click for messages */
4460
+ handleMessageContextMenuItemClick(event: AXContextMenuItemsClickEvent, message: AXConversationMessage): void;
4461
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListComponent, never>;
4462
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationMessageListComponent, "ax-conversation-message-list", never, {}, { "messageAction": "messageAction"; }, never, ["ax-conversation-message-list-empty, [ax-conversation-message-list-empty]", "ax-conversation-message-list-no-active, [ax-conversation-message-list-no-active]"], true, never>;
4463
+ }
4464
+
4465
+ declare class AXConversationAvatarPickerComponent {
4466
+ readonly fileInput: _angular_core.Signal<ElementRef<HTMLInputElement>>;
4467
+ readonly showClearButton: _angular_core.InputSignal<boolean>;
4468
+ readonly avatarUrl: _angular_core.ModelSignal<string>;
4469
+ readonly onFileSelected: _angular_core.OutputEmitterRef<string>;
4470
+ triggerFileInput(): void;
4471
+ onFileInputChange(event: Event): Promise<void>;
4472
+ clearAvatar(): void;
4473
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarPickerComponent, never>;
4474
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAvatarPickerComponent, "ax-conversation-avatar-picker", never, { "showClearButton": { "alias": "showClearButton"; "required": false; "isSignal": true; }; "avatarUrl": { "alias": "avatarUrl"; "required": false; "isSignal": true; }; }, { "avatarUrl": "avatarUrlChange"; "onFileSelected": "onFileSelected"; }, never, never, true, never>;
4475
+ }
4476
+
4477
+ declare class AXConversationAvatarComponent {
4478
+ private readonly conversationService;
4479
+ private readonly userAvatarComponent;
4480
+ private readonly conversationAvatarComponent;
4481
+ readonly kind: _angular_core.InputSignal<AXConversationAvatarKind>;
4482
+ readonly userId: _angular_core.InputSignal<string>;
4483
+ readonly conversation: _angular_core.InputSignal<AXConversation>;
4484
+ readonly message: _angular_core.InputSignal<AXConversationMessage>;
4485
+ readonly size: _angular_core.InputSignal<number>;
4486
+ readonly showStatus: _angular_core.InputSignal<boolean>;
4487
+ readonly name: _angular_core.InputSignal<string>;
4488
+ readonly avatar: _angular_core.InputSignal<string>;
4489
+ readonly icon: _angular_core.InputSignal<string>;
4490
+ private readonly currentUserId;
4491
+ readonly resolvedKind: _angular_core.Signal<"user" | "conversation">;
4492
+ readonly resolvedUserId: _angular_core.Signal<string>;
4493
+ readonly customComponent: _angular_core.Signal<Type<unknown>>;
4494
+ readonly customInputs: _angular_core.Signal<Record<string, unknown>>;
4495
+ readonly filteredCustomInputs: _angular_core.Signal<Record<string, unknown>>;
4496
+ readonly fallbackDisplay: _angular_core.Signal<{
4497
+ name: string;
4498
+ avatar: string;
4499
+ icon: string;
4500
+ }>;
4501
+ readonly fallbackInitials: _angular_core.Signal<string>;
4502
+ readonly resolvedStatus: _angular_core.Signal<_acorex_components_conversation.AXConversationPresenceStatus>;
4503
+ readonly statusBadgePresence: _angular_core.Signal<"online" | "offline" | "away" | "busy">;
4504
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarComponent, never>;
4505
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAvatarComponent, "ax-conversation-avatar", never, { "kind": { "alias": "kind"; "required": false; "isSignal": true; }; "userId": { "alias": "userId"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "showStatus": { "alias": "showStatus"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "avatar": { "alias": "avatar"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4888
4506
  }
4889
4507
 
4890
- declare class AXConversationIndexedDbMessageAiApi extends AXConversationIndexedDbMessageApi {
4891
- private readonly aiResponder;
4892
- private readonly AI_TYPING_INDICATOR_DELAY;
4893
- private readonly AI_RESPONSE_DELAY;
4894
- /**
4895
- * Override sendMessage to trigger AI auto-response
4896
- */
4897
- sendMessage(command: AXConversationSendMessageCommand): Promise<AXConversationMessage>;
4508
+ interface AXConversationRegistryComponentRef {
4509
+ component?: Type<unknown>;
4510
+ componentLoader?: () => Promise<Type<unknown>>;
4511
+ }
4512
+ /** Placeholder shown while a lazy registry component is loading. */
4513
+ type AXConversationOutletSkeleton = 'auto' | 'text' | 'media' | 'none';
4514
+ declare class AXConversationRegistryComponentOutletComponent {
4515
+ readonly component: _angular_core.InputSignal<Type<unknown>>;
4516
+ readonly componentLoader: _angular_core.InputSignal<() => Promise<Type<unknown>>>;
4517
+ readonly inputs: _angular_core.InputSignal<Record<string, unknown>>;
4518
+ /**
4519
+ * Skeleton while a `componentLoader` is in flight.
4520
+ * `auto` uses `inputs.message.type`: text/system → single line, other types → multi-line.
4521
+ */
4522
+ readonly skeleton: _angular_core.InputSignal<AXConversationOutletSkeleton>;
4523
+ readonly resolvedComponent: _angular_core.WritableSignal<Type<unknown>>;
4524
+ private readonly pending;
4525
+ readonly isLoading: _angular_core.Signal<boolean>;
4526
+ protected readonly skeletonVariant: _angular_core.Signal<"text" | "none" | "media" | "lines">;
4527
+ /** Avoid re-loading when the parent re-binds the same lazy loader reference. */
4528
+ private activeLoader;
4529
+ constructor();
4530
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationRegistryComponentOutletComponent, never>;
4531
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationRegistryComponentOutletComponent, "ax-conversation-registry-component-outlet", never, { "component": { "alias": "component"; "required": false; "isSignal": true; }; "componentLoader": { "alias": "componentLoader"; "required": false; "isSignal": true; }; "inputs": { "alias": "inputs"; "required": false; "isSignal": true; }; "skeleton": { "alias": "skeleton"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4532
+ }
4533
+ /** Resolve a registry component reference, preferring lazy loaders when provided. */
4534
+ declare function hasRegistryComponent(ref?: AXConversationRegistryComponentRef): boolean;
4535
+
4536
+ declare class AXConversationSidebarService {
4537
+ private readonly conversationService;
4538
+ constructor();
4539
+ private get registry();
4540
+ readonly searchQuery: _angular_core.WritableSignal<string>;
4541
+ readonly activeTabId: _angular_core.WritableSignal<string>;
4542
+ readonly loadingMore: _angular_core.WritableSignal<boolean>;
4543
+ readonly conversations: _angular_core.Signal<AXConversation[]>;
4544
+ readonly loading: _angular_core.Signal<boolean>;
4545
+ readonly hasMoreConversations: _angular_core.Signal<boolean>;
4546
+ readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
4547
+ readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
4898
4548
  /**
4899
- * Extract context from different message types for AI processing
4549
+ * Filter and sort conversations
4900
4550
  */
4901
- private extractMessageContext;
4551
+ private filterAndSort;
4552
+ setSearchQuery(q: string): void;
4553
+ setActiveTab(tabId: string): void;
4554
+ selectConversation(conversation: AXConversation): void;
4555
+ getBadgeValue(tabId: string): string | undefined;
4902
4556
  /**
4903
- * Generate AI response to user message
4557
+ * Load more conversations when the user scrolls near the bottom of the sidebar list.
4904
4558
  */
4905
- private generateAIResponse;
4559
+ loadMoreConversations(): Promise<void>;
4906
4560
  /**
4907
- * Get conversation for AI response
4561
+ * Handle scroll threshold (for infinite scroll)
4908
4562
  */
4909
- private getConversationForAI;
4563
+ onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
4910
4564
  /**
4911
- * Get conversation history (last N messages)
4565
+ * Reload conversation list from the first page (e.g. pull-to-refresh).
4912
4566
  */
4913
- private getConversationHistory;
4567
+ reloadConversations(): Promise<void>;
4568
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationSidebarService, never>;
4569
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationSidebarService>;
4570
+ }
4571
+
4572
+ declare class AXConversationSidebarComponent implements OnDestroy {
4573
+ readonly sidebar: AXConversationSidebarService;
4574
+ protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
4575
+ private readonly conversationService;
4576
+ private readonly popupService;
4577
+ private readonly translation;
4578
+ private readonly ngZone;
4579
+ private readonly cdr;
4580
+ /** Conversation selected event */
4581
+ readonly conversationSelected: _angular_core.OutputEmitterRef<AXConversation>;
4582
+ /** Search debouncing */
4583
+ private readonly searchSubject;
4584
+ /** Derived state for template */
4585
+ readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
4586
+ readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
4587
+ readonly loading: _angular_core.Signal<boolean>;
4588
+ readonly loadingMore: _angular_core.WritableSignal<boolean>;
4589
+ readonly hasMoreConversations: _angular_core.Signal<boolean>;
4590
+ readonly isSidebarTabsHorizontal: _angular_core.Signal<boolean>;
4591
+ readonly sidebarTabLocation: _angular_core.Signal<AXTabLocation>;
4592
+ constructor();
4593
+ /** Handle search input change with debouncing */
4594
+ onSearchChange(value: string): void;
4595
+ /** Handle tab change from ax-tabs */
4596
+ onTabChange(event: {
4597
+ tab?: {
4598
+ key?: string;
4599
+ };
4600
+ }): void;
4601
+ /** Select a conversation */
4602
+ selectConversation(conversation: AXConversation): void;
4603
+ /** Get badge value for tab */
4604
+ getBadgeValue(tabId: string): string | undefined;
4605
+ getTabLabel(tabId: string): string;
4606
+ openNewConversationPopup(): Promise<void>;
4607
+ /** Handle infinite scroll threshold - delegate to service */
4608
+ onScrollThreshold(edge: 'top' | 'bottom'): Promise<void>;
4609
+ /** Cleanup on destroy */
4610
+ ngOnDestroy(): void;
4611
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationSidebarComponent, never>;
4612
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationSidebarComponent, "ax-conversation-sidebar", never, {}, { "conversationSelected": "conversationSelected"; }, never, ["ax-suffix"], true, never>;
4613
+ }
4614
+
4615
+ type AXConversationNewWizardStep = 'selectUsers' | 'groupDetails';
4616
+ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4914
4617
  /**
4915
- * Create AI message directly in storage
4618
+ * Assigned by {@link AXPopupComponent} from `open(..., { data: { conversationService } })`.
4619
+ * Not injected: popup content is created on the root view container, so route-scoped providers
4620
+ * would not see the same `AXConversationService` instance as the conversation feature.
4916
4621
  */
4917
- private createAIMessage;
4622
+ conversationService: AXConversationService;
4623
+ private readonly toastService;
4624
+ private readonly translation;
4625
+ private readonly config;
4626
+ private readonly destroyRef;
4627
+ private searchDebounceTimer?;
4628
+ constructor();
4918
4629
  /**
4919
- * Delay helper
4630
+ * Injected by {@link AXPopupComponent} when this dialog is opened via {@link AXPopupService}.
4631
+ * Required for `setTitle` / dynamic header — {@link AXBasePageComponent#setTitle} is otherwise unset.
4920
4632
  */
4921
- private delay;
4922
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbMessageAiApi, never>;
4923
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbMessageAiApi>;
4633
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4634
+ readonly availableUsers: _angular_core.WritableSignal<AXConversationParticipant[]>;
4635
+ readonly selectedUserIds: _angular_core.WritableSignal<string[]>;
4636
+ readonly groupTitle: _angular_core.WritableSignal<string>;
4637
+ readonly groupAvatar: _angular_core.WritableSignal<string>;
4638
+ readonly searchQuery: _angular_core.WritableSignal<string>;
4639
+ readonly creating: _angular_core.WritableSignal<boolean>;
4640
+ /** For 2+ users: step 1 = pick users, step 2 = title + avatar. */
4641
+ readonly wizardStep: _angular_core.WritableSignal<AXConversationNewWizardStep>;
4642
+ readonly showUserPickerStep: _angular_core.Signal<boolean>;
4643
+ readonly showGroupDetailsStep: _angular_core.Signal<boolean>;
4644
+ readonly showNextButton: _angular_core.Signal<boolean>;
4645
+ readonly showGroupBackButton: _angular_core.Signal<boolean>;
4646
+ readonly showCreateButton: _angular_core.Signal<boolean>;
4647
+ readonly canGoNextToGroupDetails: _angular_core.Signal<boolean>;
4648
+ readonly canCreate: _angular_core.Signal<boolean>;
4649
+ private readonly _resetWizardWhenSingleEffect;
4650
+ private readonly _syncPopupTitleEffect;
4651
+ readonly usersListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
4652
+ readonly usersListLoadingTpl: _angular_core.Signal<TemplateRef<unknown>>;
4653
+ readonly usersList: _angular_core.Signal<AXListComponent>;
4654
+ readonly usersListDataSource: AXDataSource<unknown>;
4655
+ onCancel(): void;
4656
+ onSelectedUsersChange(ids: string[]): void;
4657
+ onNextToGroupDetails(): void;
4658
+ onBackFromGroupDetails(): void;
4659
+ onSearchChange(value: string): void;
4660
+ isUserSelected(id: string): boolean;
4661
+ userFromItem(item: unknown): AXConversationParticipant | null;
4662
+ private mergeUsersCache;
4663
+ onCreateConversation(): Promise<void>;
4664
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationNewDialogComponent, never>;
4665
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationNewDialogComponent, "ax-conversation-new-dialog", never, { "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4666
+ }
4667
+
4668
+ declare class AXConversationInfiniteScrollDirective {
4669
+ private readonly elementRef;
4670
+ private readonly platformId;
4671
+ /** Threshold in pixels from the edge to trigger the event */
4672
+ readonly threshold: _angular_core.InputSignal<number>;
4673
+ /** Which edge to watch: 'top', 'bottom', or 'both' */
4674
+ readonly edge: _angular_core.InputSignal<"top" | "bottom" | "both">;
4675
+ /** When true, scroll events are ignored (e.g. while a page is loading). */
4676
+ readonly scrollDisabled: _angular_core.InputSignal<boolean>;
4677
+ /** Minimum time between emissions (ms) to avoid duplicate API calls. */
4678
+ readonly cooldownMs: _angular_core.InputSignal<number>;
4679
+ /** Event emitted when scrolling reaches the threshold */
4680
+ readonly scrollThreshold: _angular_core.OutputEmitterRef<"top" | "bottom">;
4681
+ private lastScrollTop;
4682
+ private ticking;
4683
+ private lastEmitAt;
4684
+ private pendingEmit;
4685
+ constructor();
4686
+ private setupScrollListener;
4687
+ private handleScroll;
4688
+ private emitThreshold;
4689
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfiniteScrollDirective, never>;
4690
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AXConversationInfiniteScrollDirective, "[axInfiniteScroll]", never, { "threshold": { "alias": "threshold"; "required": false; "isSignal": true; }; "edge": { "alias": "edge"; "required": false; "isSignal": true; }; "scrollDisabled": { "alias": "scrollDisabled"; "required": false; "isSignal": true; }; "cooldownMs": { "alias": "cooldownMs"; "required": false; "isSignal": true; }; }, { "scrollThreshold": "scrollThreshold"; }, never, never, true, never>;
4924
4691
  }
4925
4692
 
4926
4693
  declare const AX_CONVERSATION_AUDIO_PRESENTATION: {
@@ -4945,7 +4712,10 @@ declare function applyAudioLocalPreview(payload: AXConversationMessagePayload, l
4945
4712
  * Shared upload state and helpers for composer media pickers.
4946
4713
  */
4947
4714
 
4715
+ /** Stable id for `@for` tracking while upload state is patched immutably. */
4716
+ declare function createPickerUploadItemId(): string;
4948
4717
  interface AXConversationComposerPickerUploadItem {
4718
+ id: string;
4949
4719
  file: File;
4950
4720
  preview?: string;
4951
4721
  duration?: number;
@@ -4995,16 +4765,14 @@ declare function notifyPickerValidationErrors(toast: AXToastService, translation
4995
4765
  file: File;
4996
4766
  errors: AXValidationRuleResult[];
4997
4767
  }[]): void;
4998
- /** Load files dropped onto the message list after the picker is mounted in a popup. */
4999
- declare function seedPickerInitialFiles(initialFiles: InputSignal<File[]>, handleFiles: (files: File[]) => void | Promise<void>): void;
5000
- /** Close inline composer shell or popup host after send/cancel. */
5001
- declare function dismissComposerPickerHost(composerService: AXConversationComposerService, popupRef?: AXPopupRef | null): void;
4768
+ /** Close popup/action-sheet host or inline composer shell after send/cancel. */
4769
+ declare function dismissComposerPickerHost(composerService: AXConversationComposerService, popupRef?: AXPopupRef | null, actionSheetRef?: AXActionSheetRef | null): void;
5002
4770
 
5003
4771
  interface AXConversationAudioFile extends AXConversationComposerPickerUploadItem {
5004
4772
  duration?: number;
5005
4773
  dataUrl?: string;
5006
4774
  }
5007
- declare class AXConversationAudioPickerComponent implements OnDestroy {
4775
+ declare class AXConversationAudioPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5008
4776
  private uploadsDismissed;
5009
4777
  private retainUploadedOnDismiss;
5010
4778
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -5015,20 +4783,25 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
5015
4783
  private readonly fileTypeRegistry;
5016
4784
  private readonly platformId;
5017
4785
  private readonly toast;
4786
+ private readonly popupService;
5018
4787
  readonly translation: AXTranslationService;
5019
4788
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5020
4789
  readonly maxFiles: _angular_core.InputSignal<number>;
5021
4790
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4791
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5022
4792
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4793
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5023
4794
  readonly catalogFileType: "conversation-audio";
5024
4795
  readonly audioFiles: _angular_core.WritableSignal<AXConversationAudioFile[]>;
5025
4796
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5026
- readonly typeIconClass: "fa-light fa-music text-amber-500";
4797
+ private readonly pickerShell;
5027
4798
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-music text-amber-500" | "fa-light fa-cloud-arrow-up">;
5028
4799
  private catalogFileTypeDef?;
5029
4800
  caption: string;
4801
+ groupItems: boolean;
5030
4802
  readonly allowMultiple: _angular_core.Signal<boolean>;
5031
4803
  constructor();
4804
+ activate(): Promise<void>;
5032
4805
  private createUtilityContext;
5033
4806
  private getCatalogFileTypeDef;
5034
4807
  private runUtility;
@@ -5036,10 +4809,15 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
5036
4809
  private uploadAudioAt;
5037
4810
  private patchAudio;
5038
4811
  removeAudio(index: number): void;
4812
+ renameAudio(index: number): Promise<void>;
4813
+ replaceAttachment(index: number): Promise<void>;
5039
4814
  sendAudio(): Promise<void>;
5040
4815
  canSend(): boolean;
5041
4816
  getUploadingLabel(progress: number): string;
5042
4817
  getCancelUploadLabel(): string;
4818
+ getHeaderTitle(): string;
4819
+ truncateFileName(fileName: string): string;
4820
+ onAddMoreFiles(): void;
5043
4821
  cancel(): void;
5044
4822
  ngOnDestroy(): void;
5045
4823
  private dismissPicker;
@@ -5050,7 +4828,7 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
5050
4828
  getSelectedCountText(): string;
5051
4829
  getSendText(): string;
5052
4830
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAudioPickerComponent, never>;
5053
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAudioPickerComponent, "ax-conversation-audio-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4831
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAudioPickerComponent, "ax-conversation-audio-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "autoRun": { "alias": "autoRun"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5054
4832
  }
5055
4833
 
5056
4834
  declare const AX_CONVERSATION_COMPOSER_EMOJI_TAB: AXConversationComposerTab;
@@ -5112,20 +4890,11 @@ declare function fileItemFromUpload(file: File, result: AXConversationUploaderRe
5112
4890
  declare function mergeFileUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
5113
4891
  declare function applyFileLocalPreview(payload: AXConversationMessagePayload, localUrl: string, mimeType?: string): AXConversationMessagePayload;
5114
4892
 
5115
- interface AXConversationAttachedFile {
5116
- file: File;
5117
- preview?: string;
4893
+ interface AXConversationAttachedFile extends AXConversationComposerPickerUploadItem {
5118
4894
  icon: string;
5119
4895
  type: 'image' | 'video' | 'audio' | 'file';
5120
- uploadProgress?: number;
5121
- uploading?: boolean;
5122
- uploaded?: boolean;
5123
- uploadedUrl?: string;
5124
- mediaId?: string;
5125
- error?: string;
5126
- abortController?: AbortController;
5127
4896
  }
5128
- declare class AXConversationFilePickerComponent implements OnDestroy {
4897
+ declare class AXConversationFilePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5129
4898
  private uploadsDismissed;
5130
4899
  private retainUploadedOnDismiss;
5131
4900
  private readonly uploader;
@@ -5136,32 +4905,44 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
5136
4905
  private readonly composerServiceFromInjector;
5137
4906
  private get composerService();
5138
4907
  private readonly toast;
4908
+ private readonly popupService;
5139
4909
  readonly translation: AXTranslationService;
5140
4910
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5141
4911
  readonly maxFiles: _angular_core.InputSignal<number>;
5142
4912
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4913
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5143
4914
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4915
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5144
4916
  readonly catalogFileType: "conversation-file";
5145
4917
  readonly allowMultiple: _angular_core.Signal<boolean>;
5146
4918
  readonly files: _angular_core.WritableSignal<AXConversationAttachedFile[]>;
5147
4919
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5148
4920
  readonly isUploading: _angular_core.WritableSignal<boolean>;
4921
+ private readonly pickerShell;
5149
4922
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-file text-neutral-500" | "fa-light fa-cloud-arrow-up">;
5150
4923
  private catalogFileTypeDef?;
5151
4924
  caption: string;
4925
+ groupItems: boolean;
5152
4926
  constructor();
4927
+ activate(): Promise<void>;
5153
4928
  private createUtilityContext;
5154
4929
  private getCatalogFileTypeDef;
5155
4930
  private pickerKind;
5156
4931
  handleFiles(fileList: File[]): Promise<void>;
4932
+ private buildAttachedFileEntry;
5157
4933
  private uploadFile;
5158
4934
  removeFile(index: number): void;
4935
+ renameFile(index: number): Promise<void>;
4936
+ replaceAttachment(index: number): Promise<void>;
5159
4937
  sendFiles(): Promise<void>;
5160
4938
  private updateFileProgress;
5161
4939
  private uploadFileWithProgress;
5162
4940
  cancel(): void;
5163
4941
  ngOnDestroy(): void;
5164
4942
  private dismissPicker;
4943
+ getHeaderTitle(): string;
4944
+ truncateFileName(fileName: string): string;
4945
+ onAddMoreFiles(): void;
5165
4946
  getCancelUploadLabel(): string;
5166
4947
  formatFileSize(bytes: number): string;
5167
4948
  canSend(): boolean;
@@ -5171,7 +4952,7 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
5171
4952
  getSelectedCountText(): string;
5172
4953
  getUploadingLabel(progress: number): string;
5173
4954
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationFilePickerComponent, never>;
5174
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationFilePickerComponent, "ax-conversation-file-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4955
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationFilePickerComponent, "ax-conversation-file-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "autoRun": { "alias": "autoRun"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5175
4956
  }
5176
4957
 
5177
4958
  declare const AX_CONVERSATION_IMAGE_PRESENTATION: {
@@ -5191,7 +4972,7 @@ declare class AXConversationImageFileTypeProvider extends AXFileTypeInfoProvider
5191
4972
  interface AXConversationImageFile extends AXConversationComposerPickerUploadItem {
5192
4973
  preview: string;
5193
4974
  }
5194
- declare class AXConversationImagePickerComponent implements OnDestroy {
4975
+ declare class AXConversationImagePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5195
4976
  private uploadsDismissed;
5196
4977
  /** Uploaded blobs are referenced by the sent message — do not delete on dismiss. */
5197
4978
  private retainUploadedOnDismiss;
@@ -5199,6 +4980,7 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5199
4980
  private readonly composerServiceFromInjector;
5200
4981
  private get composerService();
5201
4982
  private readonly uploader;
4983
+ private readonly popupService;
5202
4984
  private readonly fileService;
5203
4985
  private readonly fileTypeRegistry;
5204
4986
  private readonly platformId;
@@ -5208,24 +4990,37 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5208
4990
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5209
4991
  readonly maxFiles: _angular_core.InputSignal<number>;
5210
4992
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4993
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5211
4994
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4995
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5212
4996
  readonly images: _angular_core.WritableSignal<AXConversationImageFile[]>;
4997
+ private readonly pickerShell;
5213
4998
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5214
4999
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-image text-purple-500" | "fa-light fa-cloud-arrow-up">;
5215
5000
  caption: string;
5001
+ groupItems: boolean;
5002
+ sendAsDocuments: boolean;
5216
5003
  readonly allowMultiple: _angular_core.Signal<boolean>;
5217
5004
  private imageFileType?;
5218
5005
  constructor();
5006
+ activate(): Promise<void>;
5219
5007
  private createUtilityContext;
5220
5008
  private loadImageFileType;
5221
5009
  handleFiles(files: File[]): Promise<void>;
5222
5010
  private uploadImageAt;
5223
5011
  private patchImage;
5224
5012
  removeImage(index: number): void;
5013
+ replaceAttachment(index: number): Promise<void>;
5014
+ editImage(index: number): Promise<void>;
5015
+ private applyReplacementFile;
5225
5016
  sendImages(): Promise<void>;
5017
+ private sendImagesAsDocuments;
5018
+ getMediaGridClass(): string;
5226
5019
  canSend(): boolean;
5227
5020
  getUploadingLabel(progress: number): string;
5228
5021
  getCancelUploadLabel(): string;
5022
+ getHeaderTitle(): string;
5023
+ onAddMoreFiles(): void;
5229
5024
  cancel(): void;
5230
5025
  ngOnDestroy(): void;
5231
5026
  private dismissPicker;
@@ -5234,36 +5029,46 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5234
5029
  getSelectedCountText(): string;
5235
5030
  getSendText(): string;
5236
5031
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationImagePickerComponent, never>;
5237
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationImagePickerComponent, "ax-conversation-image-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5032
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationImagePickerComponent, "ax-conversation-image-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "autoRun": { "alias": "autoRun"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5238
5033
  }
5239
5034
 
5240
5035
  declare class AXConversationLocationPickerComponent {
5241
- private readonly composerService;
5242
- private readonly conversationService;
5036
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
5037
+ private readonly composerServiceFromInjector;
5038
+ private get composerService();
5243
5039
  readonly translation: AXTranslationService;
5244
5040
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5041
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
5042
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5245
5043
  readonly currentLocation: _angular_core.WritableSignal<AXConversationLocationPayload>;
5246
5044
  onMarkerAdded(event: AXMapMarker): void;
5247
5045
  sendLocation(): Promise<void>;
5248
5046
  cancel(): void;
5249
5047
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationLocationPickerComponent, never>;
5250
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationLocationPickerComponent, "ax-conversation-location-picker", never, { "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
5048
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationLocationPickerComponent, "ax-conversation-location-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5251
5049
  }
5252
5050
 
5253
5051
  declare class AXConversationPickerFooterComponent {
5254
- readonly sendText: _angular_core.InputSignal<string>;
5052
+ readonly showAdd: _angular_core.InputSignal<boolean>;
5053
+ readonly addLabel: _angular_core.InputSignal<string>;
5054
+ readonly cancelLabel: _angular_core.InputSignal<string>;
5055
+ readonly sendLabel: _angular_core.InputSignal<string>;
5255
5056
  readonly sendDisabled: _angular_core.InputSignal<boolean>;
5057
+ readonly onAdd: _angular_core.OutputEmitterRef<void>;
5256
5058
  readonly onCancel: _angular_core.OutputEmitterRef<void>;
5257
5059
  readonly onSend: _angular_core.OutputEmitterRef<void>;
5258
5060
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerFooterComponent, never>;
5259
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerFooterComponent, "ax-conversation-picker-footer", never, { "sendText": { "alias": "sendText"; "required": true; "isSignal": true; }; "sendDisabled": { "alias": "sendDisabled"; "required": false; "isSignal": true; }; }, { "onCancel": "onCancel"; "onSend": "onSend"; }, never, never, true, never>;
5061
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerFooterComponent, "ax-conversation-picker-footer", never, { "showAdd": { "alias": "showAdd"; "required": false; "isSignal": true; }; "addLabel": { "alias": "addLabel"; "required": false; "isSignal": true; }; "cancelLabel": { "alias": "cancelLabel"; "required": true; "isSignal": true; }; "sendLabel": { "alias": "sendLabel"; "required": true; "isSignal": true; }; "sendDisabled": { "alias": "sendDisabled"; "required": false; "isSignal": true; }; }, { "onAdd": "onAdd"; "onCancel": "onCancel"; "onSend": "onSend"; }, never, never, true, never>;
5260
5062
  }
5261
5063
 
5262
5064
  declare class AXConversationPickerHeaderComponent {
5263
5065
  readonly title: _angular_core.InputSignal<string>;
5066
+ readonly showMenu: _angular_core.InputSignal<boolean>;
5067
+ readonly addMoreLabel: _angular_core.InputSignal<string>;
5264
5068
  readonly onClose: _angular_core.OutputEmitterRef<void>;
5069
+ readonly onAddMore: _angular_core.OutputEmitterRef<void>;
5265
5070
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerHeaderComponent, never>;
5266
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerHeaderComponent, "ax-conversation-picker-header", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; }, { "onClose": "onClose"; }, never, never, true, never>;
5071
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerHeaderComponent, "ax-conversation-picker-header", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "showMenu": { "alias": "showMenu"; "required": false; "isSignal": true; }; "addMoreLabel": { "alias": "addMoreLabel"; "required": false; "isSignal": true; }; }, { "onClose": "onClose"; "onAddMore": "onAddMore"; }, never, never, true, never>;
5267
5072
  }
5268
5073
 
5269
5074
  declare function formatFileSize(bytes: number): string;
@@ -5278,12 +5083,29 @@ declare function resolvePersistableMediaUrl(url: string | undefined): string | u
5278
5083
  /** First non-empty URL for img/video/audio at runtime (includes resolved blob: URLs). */
5279
5084
  declare function pickDisplayMediaUrl(...candidates: (string | null | undefined)[]): string;
5280
5085
 
5281
- /** Optional caption field shared by composer media pickers. */
5086
+ /** Caption field with emoji picker for composer media pickers. */
5282
5087
  declare class AXConversationPickerCaptionComponent {
5283
5088
  readonly translation: AXTranslationService;
5284
5089
  readonly caption: _angular_core.ModelSignal<string>;
5090
+ readonly showInlineSend: _angular_core.InputSignal<boolean>;
5091
+ readonly sendDisabled: _angular_core.InputSignal<boolean>;
5092
+ readonly onSend: _angular_core.OutputEmitterRef<void>;
5093
+ private readonly emojiPopoverRef;
5094
+ onEmojiClick(event: AXClickEvent): void;
5095
+ onEmojiSelected(emoji: string): void;
5096
+ onCaptionKeyDown(event: AXHtmlEvent<KeyboardEvent>): void;
5285
5097
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerCaptionComponent, never>;
5286
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerCaptionComponent, "ax-conversation-picker-caption", never, { "caption": { "alias": "caption"; "required": false; "isSignal": true; }; }, { "caption": "captionChange"; }, never, never, true, never>;
5098
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerCaptionComponent, "ax-conversation-picker-caption", never, { "caption": { "alias": "caption"; "required": false; "isSignal": true; }; "showInlineSend": { "alias": "showInlineSend"; "required": false; "isSignal": true; }; "sendDisabled": { "alias": "sendDisabled"; "required": false; "isSignal": true; }; }, { "caption": "captionChange"; "onSend": "onSend"; }, never, never, true, never>;
5099
+ }
5100
+
5101
+ /** Grouping and delivery options shown below composer picker previews. */
5102
+ declare class AXConversationPickerOptionsComponent {
5103
+ readonly showGroupItems: _angular_core.InputSignal<boolean>;
5104
+ readonly showSendAsDocuments: _angular_core.InputSignal<boolean>;
5105
+ readonly groupItems: _angular_core.ModelSignal<boolean>;
5106
+ readonly sendAsDocuments: _angular_core.ModelSignal<boolean>;
5107
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerOptionsComponent, never>;
5108
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerOptionsComponent, "ax-conversation-picker-options", never, { "showGroupItems": { "alias": "showGroupItems"; "required": false; "isSignal": true; }; "showSendAsDocuments": { "alias": "showSendAsDocuments"; "required": false; "isSignal": true; }; "groupItems": { "alias": "groupItems"; "required": false; "isSignal": true; }; "sendAsDocuments": { "alias": "sendAsDocuments"; "required": false; "isSignal": true; }; }, { "groupItems": "groupItemsChange"; "sendAsDocuments": "sendAsDocumentsChange"; }, never, never, true, never>;
5287
5109
  }
5288
5110
 
5289
5111
  /** Shared drag-and-drop handlers for composer pickers. */
@@ -5311,12 +5133,15 @@ declare class AXConversationPickerEmptyComponent {
5311
5133
  declare class AXConversationPickerShellComponent {
5312
5134
  private readonly toast;
5313
5135
  private readonly translation;
5136
+ private readonly zone;
5314
5137
  readonly fileType: _angular_core.InputSignal<string>;
5315
5138
  readonly multiple: _angular_core.InputSignal<boolean>;
5316
5139
  readonly filesSelected: _angular_core.OutputEmitterRef<File[]>;
5317
5140
  readonly dragEnter: _angular_core.OutputEmitterRef<DragEvent>;
5318
5141
  readonly dragLeave: _angular_core.OutputEmitterRef<DragEvent>;
5319
5142
  readonly dragOver: _angular_core.OutputEmitterRef<DragEvent>;
5143
+ /** Open the OS file picker for this shell's catalog. */
5144
+ browse(): Promise<void>;
5320
5145
  protected onZoneFileChange(event: AXUploaderFileChangeEvent): void;
5321
5146
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerShellComponent, never>;
5322
5147
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerShellComponent, "ax-conversation-picker-shell", never, { "fileType": { "alias": "fileType"; "required": true; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; }, { "filesSelected": "filesSelected"; "dragEnter": "dragEnter"; "dragLeave": "dragLeave"; "dragOver": "dragOver"; }, never, ["*"], true, never>;
@@ -5386,7 +5211,7 @@ interface AXConversationVideoFile extends AXConversationComposerPickerUploadItem
5386
5211
  preview?: string;
5387
5212
  duration?: number;
5388
5213
  }
5389
- declare class AXConversationVideoPickerComponent implements OnDestroy {
5214
+ declare class AXConversationVideoPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5390
5215
  private uploadsDismissed;
5391
5216
  private retainUploadedOnDismiss;
5392
5217
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -5401,16 +5226,22 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5401
5226
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5402
5227
  readonly maxFiles: _angular_core.InputSignal<number>;
5403
5228
  readonly initialFiles: _angular_core.InputSignal<File[]>;
5229
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5404
5230
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
5231
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5405
5232
  readonly catalogFileType: "conversation-video";
5406
5233
  readonly videos: _angular_core.WritableSignal<AXConversationVideoFile[]>;
5407
5234
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5235
+ private readonly pickerShell;
5408
5236
  caption: string;
5237
+ groupItems: boolean;
5238
+ sendAsDocuments: boolean;
5409
5239
  readonly allowMultiple: _angular_core.Signal<boolean>;
5410
5240
  readonly typeIconClass: "fa-light fa-video ax-text-blue-500";
5411
5241
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-video ax-text-blue-500" | "fa-light fa-cloud-arrow-up">;
5412
5242
  private catalogFileTypeDef?;
5413
5243
  constructor();
5244
+ activate(): Promise<void>;
5414
5245
  private createUtilityContext;
5415
5246
  private getCatalogFileTypeDef;
5416
5247
  private runUtility;
@@ -5418,10 +5249,15 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5418
5249
  private uploadVideoAt;
5419
5250
  private patchVideo;
5420
5251
  removeVideo(index: number): void;
5252
+ replaceAttachment(index: number): Promise<void>;
5421
5253
  sendVideos(): Promise<void>;
5254
+ private sendVideosAsDocuments;
5255
+ getMediaGridClass(): string;
5422
5256
  canSend(): boolean;
5423
5257
  getUploadingLabel(progress: number): string;
5424
5258
  getCancelUploadLabel(): string;
5259
+ getHeaderTitle(): string;
5260
+ onAddMoreFiles(): void;
5425
5261
  cancel(): void;
5426
5262
  ngOnDestroy(): void;
5427
5263
  private dismissPicker;
@@ -5432,7 +5268,7 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5432
5268
  getSelectedCountText(): string;
5433
5269
  getSendText(): string;
5434
5270
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationVideoPickerComponent, never>;
5435
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationVideoPickerComponent, "ax-conversation-video-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5271
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationVideoPickerComponent, "ax-conversation-video-picker", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "autoRun": { "alias": "autoRun"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5436
5272
  }
5437
5273
 
5438
5274
  declare const AX_CONVERSATION_VOICE_PRESENTATION: {
@@ -5452,14 +5288,21 @@ declare class AXConversationVoiceFileTypeProvider extends AXFileTypeInfoProvider
5452
5288
  declare function mergeVoiceUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
5453
5289
  declare function applyVoiceLocalPreview(payload: AXConversationMessagePayload, localUrl: string): AXConversationMessagePayload;
5454
5290
 
5455
- declare class AXConversationVoiceRecorderComponent {
5291
+ declare class AXConversationVoiceRecorderComponent implements AXConversationComposerActionComponent {
5456
5292
  private readonly platformId;
5457
5293
  private readonly destroyRef;
5458
- private readonly composerService;
5294
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
5295
+ private readonly composerServiceFromInjector;
5296
+ private get composerService();
5459
5297
  private readonly uploader;
5298
+ private readonly fileTypeRegistry;
5460
5299
  private readonly toast;
5461
5300
  readonly translation: AXTranslationService;
5462
5301
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5302
+ readonly initialFiles: _angular_core.InputSignal<File[]>;
5303
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5304
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
5305
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5463
5306
  readonly recordingComplete: _angular_core.OutputEmitterRef<Blob>;
5464
5307
  readonly recordingCancelled: _angular_core.OutputEmitterRef<void>;
5465
5308
  readonly isRecording: _angular_core.WritableSignal<boolean>;
@@ -5475,7 +5318,9 @@ declare class AXConversationVoiceRecorderComponent {
5475
5318
  private uploadAbortController?;
5476
5319
  readonly formattedTime: _angular_core.Signal<string>;
5477
5320
  constructor();
5321
+ activate(): Promise<void>;
5478
5322
  startRecording(): Promise<void>;
5323
+ private dismissHost;
5479
5324
  /** Stop recording and send */
5480
5325
  stopRecording(): void;
5481
5326
  cancelRecording(): void;
@@ -5489,7 +5334,7 @@ declare class AXConversationVoiceRecorderComponent {
5489
5334
  private sendVoiceMessage;
5490
5335
  private stopAndCleanup;
5491
5336
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationVoiceRecorderComponent, never>;
5492
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationVoiceRecorderComponent, "ax-conversation-voice-recorder", never, { "conversation": { "alias": "conversation"; "required": false; "isSignal": true; }; }, { "recordingComplete": "recordingComplete"; "recordingCancelled": "recordingCancelled"; }, never, never, true, never>;
5337
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationVoiceRecorderComponent, "ax-conversation-voice-recorder", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "initialFiles": { "alias": "initialFiles"; "required": false; "isSignal": true; }; "autoRun": { "alias": "autoRun"; "required": false; "isSignal": true; }; "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; "__actionSheet__": { "alias": "__actionSheet__"; "required": false; "isSignal": true; }; }, { "recordingComplete": "recordingComplete"; "recordingCancelled": "recordingCancelled"; }, never, never, true, never>;
5493
5338
  }
5494
5339
 
5495
5340
  declare const AX_CONVERSATION_COMPOSER_EMOJI_ACTION: AXConversationComposerAction;
@@ -5511,6 +5356,8 @@ declare const AX_CONVERSATION_FILE_TYPES_READY: InjectionToken<boolean>;
5511
5356
  /** Registers validation rules and lazy conversation file-type catalogs for composer actions. */
5512
5357
  declare function provideConversationComposerFileTypes(): Provider[];
5513
5358
 
5359
+ /** Ensure a built-in conversation catalog is registered before pre-overlay file selection. */
5360
+ declare function ensureConversationFileCatalogRegistered(registry: AXFileTypeRegistryService, catalogName: string): Promise<void>;
5514
5361
  /**
5515
5362
  * Lazy-loads conversation file catalogs for the root file-type registry.
5516
5363
  * Must not inject {@link AXConversationComposerActionRegistry} — that registry
@@ -5531,170 +5378,6 @@ declare function createLocalPreviewUrl(fileService: AXFileService, platformId: o
5531
5378
 
5532
5379
  declare function resolveComposerMaxFiles(action: Pick<AXConversationComposerAction, 'maxFiles'> | undefined, config: Pick<Required<AXConversationConfig>, 'maxFilesPerMessage'>): number;
5533
5380
 
5534
- interface AXConversationInfoProfileField {
5535
- id: string;
5536
- labelKey: string;
5537
- value: string;
5538
- icon: string;
5539
- }
5540
- type AXConversationMediaCategoryId = 'image' | 'video' | 'file' | 'audio' | 'voice' | 'sticker' | 'location' | 'link';
5541
- interface AXConversationMediaCategory {
5542
- id: AXConversationMediaCategoryId;
5543
- labelKey: string;
5544
- countLabelKey: string;
5545
- icon: string;
5546
- count: number;
5547
- }
5548
- declare function messageContainsLink(message: AXConversationMessage): boolean;
5549
- declare function getPrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
5550
- declare function getConversationProfileFields(conversation: AXConversation, currentUserId?: string): AXConversationInfoProfileField[];
5551
- declare function getConversationMediaCategories(messages: AXConversationMessage[]): AXConversationMediaCategory[];
5552
- declare function filterMessagesByMediaCategory(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMessage[];
5553
- declare function isGridMediaCategory(categoryId: AXConversationMediaCategoryId): boolean;
5554
- declare function isAttachmentListCategory(categoryId: AXConversationMediaCategoryId): boolean;
5555
- interface AXConversationMediaGalleryTile {
5556
- key: string;
5557
- message: AXConversationMessage;
5558
- kind: 'image' | 'video' | 'sticker';
5559
- image?: AXConversationImageMediaItem;
5560
- video?: AXConversationVideoMediaItem;
5561
- stickerUrl?: string;
5562
- stickerAlt?: string;
5563
- }
5564
- declare function buildMediaGalleryTiles(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMediaGalleryTile[];
5565
- declare function resolveVideoThumbnailUrl(video: AXConversationVideoMediaItem): string | undefined;
5566
- declare function resolveGalleryImageUrl(image: AXConversationImageMediaItem): string | undefined;
5567
- declare function getMessageVideoItems(message: AXConversationMessage): AXConversationVideoMediaItem[];
5568
- declare function getMessageAudioItems(message: AXConversationMessage): AXConversationAudioMediaItem[];
5569
- interface AXConversationMediaPageResult {
5570
- items: AXConversationMessage[];
5571
- hasMore: boolean;
5572
- nextCursor?: string;
5573
- page: number;
5574
- }
5575
- declare function fetchConversationMediaPage(conversationApi: AXConversationApi, conversationId: string, page: number, pageSize?: number, cursor?: string): Promise<AXConversationMediaPageResult>;
5576
- /** @deprecated Use {@link fetchConversationMediaPage} — loads only the first page. */
5577
- declare function fetchConversationMediaMessages(conversationApi: AXConversationApi, conversationId: string, pageSize: number): Promise<AXConversationMessage[]>;
5578
- /** Merge media API results with in-memory messages needed for link/sticker/voice/location tabs. */
5579
- declare function mergeInfoPanelMessages(mediaMessages: AXConversationMessage[], supplemental: AXConversationMessage[]): AXConversationMessage[];
5580
- declare function filterSupplementalInfoPanelMessages(messages: AXConversationMessage[]): AXConversationMessage[];
5581
-
5582
- interface AXInfoPanelQuickAction {
5583
- id: string;
5584
- labelKey: string;
5585
- icon: string;
5586
- danger?: boolean;
5587
- }
5588
- declare class AXConversationInfoPanelComponent extends AXClosableComponent implements OnInit, OnDestroy {
5589
- private readonly toastService;
5590
- readonly translation: AXTranslationService;
5591
- private readonly platform;
5592
- private readonly injectedConversationService;
5593
- readonly onClosed: _angular_core.OutputEmitterRef<AXComponentCloseEvent>;
5594
- conversation: AXConversation;
5595
- conversationService: AXConversationService;
5596
- readonly activeTab: _angular_core.WritableSignal<"profile" | "manage">;
5597
- readonly showMemberSearch: _angular_core.WritableSignal<boolean>;
5598
- readonly panelView: _angular_core.WritableSignal<"main" | "media">;
5599
- readonly selectedMediaCategory: _angular_core.WritableSignal<AXConversationMediaCategory>;
5600
- readonly mediaViewLoader: () => Promise<typeof _acorex_components_conversation.AXConversationInfoMediaViewComponent>;
5601
- readonly conversationMessages: _angular_core.WritableSignal<AXConversationMessage[]>;
5602
- readonly loadingMessages: _angular_core.WritableSignal<boolean>;
5603
- readonly loadingMoreMedia: _angular_core.WritableSignal<boolean>;
5604
- readonly mediaHasMore: _angular_core.WritableSignal<boolean>;
5605
- private mediaNextPage;
5606
- private mediaNextCursor;
5607
- readonly memberSearchQuery: _angular_core.WritableSignal<string>;
5608
- archived: boolean;
5609
- private initialNotifications;
5610
- private initialArchived;
5611
- editTitle: string;
5612
- editAvatar: string;
5613
- private groupTitleSaveTimer;
5614
- private groupDetailsSaveInFlight;
5615
- readonly backgroundPresets: {
5616
- label: string;
5617
- id: string;
5618
- value: AXConversationMessageListThemeBackground;
5619
- }[];
5620
- readonly heroSubtitle: _angular_core.Signal<string>;
5621
- readonly liveConversation: _angular_core.Signal<AXConversation>;
5622
- readonly isConversationMuted: _angular_core.Signal<boolean>;
5623
- readonly profileFields: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoProfileField[]>;
5624
- readonly mediaCategories: _angular_core.Signal<AXConversationMediaCategory[]>;
5625
- readonly quickActions: _angular_core.Signal<AXInfoPanelQuickAction[]>;
5626
- readonly filteredMembers: _angular_core.Signal<AXConversationParticipant[]>;
5627
- ngOnInit(): void;
5628
- private loadConversationMessages;
5629
- loadMoreMedia(): Promise<void>;
5630
- isPrivateConversation(): boolean;
5631
- isGroupConversation(): boolean;
5632
- membersSectionTitle(): string;
5633
- getMemberRoleLabel(participant: AXConversationParticipant): string | null;
5634
- onMemberSearchChange(value: string | null | undefined): void;
5635
- setActiveTab(tab: 'profile' | 'manage'): void;
5636
- toggleMemberSearch(): void;
5637
- openMediaCategory(category: AXConversationMediaCategory): void;
5638
- closeMediaView(): void;
5639
- getMediaViewInputs(category: AXConversationMediaCategory): Record<string, unknown>;
5640
- getMediaRowLabel(category: AXConversationMediaCategory): string;
5641
- getMemberSubtitle(participant: AXConversationParticipant): string;
5642
- onQuickAction(actionId: string): void;
5643
- toggleConversationMute(): Promise<void>;
5644
- onNotificationsChange(value: boolean): Promise<void>;
5645
- onArchivedChange(value: boolean): Promise<void>;
5646
- close(data?: unknown): void;
5647
- closeAll(): void;
5648
- onLeave(): Promise<void>;
5649
- onGroupTitleChange(value: string): void;
5650
- onGroupAvatarChange(value: string): void;
5651
- private persistGroupDetails;
5652
- isBackgroundSelected(preset: {
5653
- id: string;
5654
- value: AXConversationMessageListThemeBackground;
5655
- }): boolean;
5656
- presetBackgroundPreview(preset: AXConversationMessageListThemeBackground): string;
5657
- applyMessageListBackground(value: AXConversationMessageListBackground): Promise<void>;
5658
- getBackgroundAriaLabel(label: string): string;
5659
- private translateBackgroundPresetLabel;
5660
- ngOnDestroy(): void;
5661
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoPanelComponent, never>;
5662
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoPanelComponent, "ax-conversation-info-panel", never, {}, { "onClosed": "onClosed"; }, never, never, true, never>;
5663
- }
5664
-
5665
- declare class AXConversationInfoMediaViewComponent {
5666
- private readonly translation;
5667
- private readonly parentInjector;
5668
- readonly category: _angular_core.InputSignal<AXConversationMediaCategory>;
5669
- readonly messages: _angular_core.InputSignal<AXConversationMessage[]>;
5670
- readonly conversation: _angular_core.InputSignal<AXConversation>;
5671
- readonly conversationServiceInput: _angular_core.InputSignal<AXConversationService>;
5672
- readonly hasMoreMedia: _angular_core.InputSignal<boolean>;
5673
- readonly loadingMoreMedia: _angular_core.InputSignal<boolean>;
5674
- readonly onLoadMoreMedia: _angular_core.InputSignal<() => void | Promise<void>>;
5675
- /** Callback for lazy outlet wiring (alternative to the `back` output). */
5676
- readonly onBack: _angular_core.InputSignal<() => void>;
5677
- readonly back: _angular_core.OutputEmitterRef<void>;
5678
- readonly items: _angular_core.Signal<AXConversationMessage[]>;
5679
- readonly isGrid: _angular_core.Signal<boolean>;
5680
- readonly isAttachmentList: _angular_core.Signal<boolean>;
5681
- readonly galleryTiles: _angular_core.Signal<_acorex_components_conversation.AXConversationMediaGalleryTile[]>;
5682
- readonly rendererInjector: _angular_core.Signal<_angular_core.DestroyableInjector>;
5683
- readonly titleLabel: _angular_core.Signal<string>;
5684
- readonly getMessageVideoItems: typeof getMessageVideoItems;
5685
- readonly getMessageAudioItems: typeof getMessageAudioItems;
5686
- getRendererComponent(message: AXConversationMessage): _angular_core.Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
5687
- getRendererComponentLoader(message: AXConversationMessage): (() => Promise<_angular_core.Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
5688
- getRendererInputs(message: AXConversationMessage): {
5689
- message: AXConversationMessage;
5690
- };
5691
- formatTimestamp(message: AXConversationMessage): string;
5692
- handleBack(): void;
5693
- onScrollThreshold(edge: 'top' | 'bottom'): void;
5694
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoMediaViewComponent, never>;
5695
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoMediaViewComponent, "ax-conversation-info-media-view", never, { "category": { "alias": "category"; "required": true; "isSignal": true; }; "messages": { "alias": "messages"; "required": true; "isSignal": true; }; "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; "conversationServiceInput": { "alias": "conversationService"; "required": true; "isSignal": true; }; "hasMoreMedia": { "alias": "hasMoreMedia"; "required": false; "isSignal": true; }; "loadingMoreMedia": { "alias": "loadingMoreMedia"; "required": false; "isSignal": true; }; "onLoadMoreMedia": { "alias": "onLoadMoreMedia"; "required": false; "isSignal": true; }; "onBack": { "alias": "onBack"; "required": false; "isSignal": true; }; }, { "back": "back"; }, never, never, true, never>;
5696
- }
5697
-
5698
5381
  declare class AXConversationInfoBarSearchComponent {
5699
5382
  private readonly platformId;
5700
5383
  private readonly destroyRef;
@@ -5737,7 +5420,7 @@ declare class AXConversationInfoBarSearchComponent {
5737
5420
  */
5738
5421
 
5739
5422
  /**
5740
- * Search in conversation action (inline)
5423
+ * Search in conversation action (inline on desktop, menu on mobile)
5741
5424
  */
5742
5425
  declare const AX_CONVERSATION_INFO_BAR_SEARCH_ACTION: AXConversationInfoBarAction;
5743
5426
  /**
@@ -5766,6 +5449,7 @@ declare const AX_CONVERSATION_INFO_BAR_BLOCK_ACTION: AXConversationInfoBarAction
5766
5449
  declare function toUploaderReference(item: AXConversationMediaItemFields): AXConversationUploaderReference;
5767
5450
 
5768
5451
  declare class AXConversationAudioAttachmentComponent {
5452
+ private readonly platformId;
5769
5453
  readonly item: _angular_core.InputSignal<AXConversationAudioMediaItem>;
5770
5454
  readonly playingChange: _angular_core.OutputEmitterRef<boolean>;
5771
5455
  readonly timeUpdate: _angular_core.OutputEmitterRef<number>;
@@ -5775,18 +5459,31 @@ declare class AXConversationAudioAttachmentComponent {
5775
5459
  private readonly audioElementRef;
5776
5460
  private readonly mediaReference;
5777
5461
  private readonly resolvedUrl;
5462
+ readonly isPlaying: _angular_core.WritableSignal<boolean>;
5463
+ readonly currentTime: _angular_core.WritableSignal<number>;
5464
+ readonly liveDuration: _angular_core.WritableSignal<number>;
5465
+ readonly coverVisible: _angular_core.WritableSignal<boolean>;
5778
5466
  readonly audioUrl: _angular_core.Signal<string>;
5779
5467
  readonly title: _angular_core.Signal<string>;
5468
+ readonly coverUrl: _angular_core.Signal<string>;
5780
5469
  readonly duration: _angular_core.Signal<number>;
5781
- readonly durationLabel: _angular_core.Signal<string>;
5470
+ readonly effectiveDuration: _angular_core.Signal<number>;
5471
+ readonly sliderMax: _angular_core.Signal<number>;
5472
+ readonly currentTimeLabel: _angular_core.Signal<string>;
5473
+ readonly downloadName: _angular_core.Signal<string>;
5474
+ constructor();
5782
5475
  togglePlay(): void;
5783
5476
  pause(): void;
5477
+ setPlaybackRate(rate: number): void;
5478
+ setMuted(muted: boolean): void;
5479
+ onSeek(value: AXRangeSliderValue): void;
5784
5480
  onPlay(): void;
5785
5481
  onPause(): void;
5786
5482
  onTimeUpdate(): void;
5787
5483
  onLoadedMetadata(): void;
5788
5484
  onEnded(): void;
5789
5485
  onError(): void;
5486
+ onCoverError(): void;
5790
5487
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAudioAttachmentComponent, never>;
5791
5488
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAudioAttachmentComponent, "ax-conversation-audio-attachment", never, { "item": { "alias": "item"; "required": true; "isSignal": true; }; }, { "playingChange": "playingChange"; "timeUpdate": "timeUpdate"; "durationChange": "durationChange"; "playbackEnded": "playbackEnded"; "playbackError": "playbackError"; }, never, never, true, never>;
5792
5489
  }
@@ -5799,7 +5496,6 @@ declare class AXConversationFileAttachmentComponent {
5799
5496
  readonly fileName: _angular_core.Signal<string>;
5800
5497
  readonly fileSize: _angular_core.Signal<number>;
5801
5498
  readonly fileExtension: _angular_core.Signal<string>;
5802
- readonly swatchColor: _angular_core.Signal<string>;
5803
5499
  readonly formattedSize: _angular_core.Signal<string>;
5804
5500
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationFileAttachmentComponent, never>;
5805
5501
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationFileAttachmentComponent, "ax-conversation-file-attachment", never, { "item": { "alias": "item"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -5821,7 +5517,7 @@ declare class AXConversationImageAttachmentComponent {
5821
5517
  constructor();
5822
5518
  onImageLoad(): void;
5823
5519
  onImageError(): void;
5824
- toggleFullscreen(event: MouseEvent): void;
5520
+ toggleFullscreen(event: AXClickEvent): void;
5825
5521
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationImageAttachmentComponent, never>;
5826
5522
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationImageAttachmentComponent, "ax-conversation-image-attachment", never, { "item": { "alias": "item"; "required": true; "isSignal": true; }; "alt": { "alias": "alt"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5827
5523
  }
@@ -5836,6 +5532,9 @@ interface AXConversationPlaybackBannerInputs {
5836
5532
  playbackSpeed?: number;
5837
5533
  onCycleSpeed?: () => void;
5838
5534
  showSpeedControl?: boolean;
5535
+ isMuted?: boolean;
5536
+ onToggleMute?: () => void;
5537
+ showMuteControl?: boolean;
5839
5538
  }
5840
5539
  declare class AXConversationMediaPlaybackInfoBarBannerComponent implements AXConversationMessageInfoBarBannerComponent {
5841
5540
  readonly message: _angular_core.InputSignal<AXConversationMessage>;
@@ -5847,14 +5546,18 @@ declare class AXConversationMediaPlaybackInfoBarBannerComponent implements AXCon
5847
5546
  readonly playbackSpeed: _angular_core.InputSignal<number>;
5848
5547
  readonly onCycleSpeed: _angular_core.InputSignal<() => void>;
5849
5548
  readonly showSpeedControl: _angular_core.InputSignal<boolean>;
5549
+ readonly isMuted: _angular_core.InputSignal<boolean>;
5550
+ readonly onToggleMute: _angular_core.InputSignal<() => void>;
5551
+ readonly showMuteControl: _angular_core.InputSignal<boolean>;
5850
5552
  readonly iconClass: _angular_core.Signal<string>;
5851
5553
  readonly resolvedTitle: _angular_core.Signal<string>;
5852
5554
  readonly progressPercent: _angular_core.Signal<number>;
5853
5555
  readonly timeLabel: _angular_core.Signal<string>;
5854
5556
  onTogglePlayClick(): void;
5855
5557
  onCycleSpeedClick(): void;
5558
+ onToggleMuteClick(): void;
5856
5559
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMediaPlaybackInfoBarBannerComponent, never>;
5857
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationMediaPlaybackInfoBarBannerComponent, "ax-conversation-media-playback-info-bar-banner", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "currentTime": { "alias": "currentTime"; "required": false; "isSignal": true; }; "duration": { "alias": "duration"; "required": false; "isSignal": true; }; "isPlaying": { "alias": "isPlaying"; "required": false; "isSignal": true; }; "onTogglePlay": { "alias": "onTogglePlay"; "required": false; "isSignal": true; }; "playbackSpeed": { "alias": "playbackSpeed"; "required": false; "isSignal": true; }; "onCycleSpeed": { "alias": "onCycleSpeed"; "required": false; "isSignal": true; }; "showSpeedControl": { "alias": "showSpeedControl"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5560
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationMediaPlaybackInfoBarBannerComponent, "ax-conversation-media-playback-info-bar-banner", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "currentTime": { "alias": "currentTime"; "required": false; "isSignal": true; }; "duration": { "alias": "duration"; "required": false; "isSignal": true; }; "isPlaying": { "alias": "isPlaying"; "required": false; "isSignal": true; }; "onTogglePlay": { "alias": "onTogglePlay"; "required": false; "isSignal": true; }; "playbackSpeed": { "alias": "playbackSpeed"; "required": false; "isSignal": true; }; "onCycleSpeed": { "alias": "onCycleSpeed"; "required": false; "isSignal": true; }; "showSpeedControl": { "alias": "showSpeedControl"; "required": false; "isSignal": true; }; "isMuted": { "alias": "isMuted"; "required": false; "isSignal": true; }; "onToggleMute": { "alias": "onToggleMute"; "required": false; "isSignal": true; }; "showMuteControl": { "alias": "showMuteControl"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5858
5561
  }
5859
5562
 
5860
5563
  /**
@@ -5904,10 +5607,11 @@ declare class AXConversationMessageRendererStateComponent {
5904
5607
  readonly contentRetry: _angular_core.OutputEmitterRef<void>;
5905
5608
  readonly retryBusy: _angular_core.WritableSignal<boolean>;
5906
5609
  private readonly currentUser;
5907
- private readonly isOwn;
5610
+ readonly isOwn: _angular_core.Signal<boolean>;
5908
5611
  readonly showFailed: _angular_core.Signal<boolean>;
5909
5612
  readonly showContentError: _angular_core.Signal<boolean>;
5910
5613
  readonly hasVisibleChrome: _angular_core.Signal<boolean>;
5614
+ readonly resolvedContentErrorIconClass: _angular_core.Signal<string>;
5911
5615
  readonly contentErrorText: _angular_core.Signal<string>;
5912
5616
  readonly deliveryFailedText: _angular_core.Signal<string>;
5913
5617
  onRetry(): Promise<void>;
@@ -5959,6 +5663,14 @@ declare class AXConversationAudioRendererComponent extends AXConversationMessage
5959
5663
  private readonly isPlaying;
5960
5664
  private readonly currentTime;
5961
5665
  private readonly duration;
5666
+ readonly playbackSpeed: _angular_core.WritableSignal<number>;
5667
+ readonly isMuted: _angular_core.WritableSignal<boolean>;
5668
+ private lastBannerSyncAt;
5669
+ private readonly speeds;
5670
+ private readonly bannerTogglePlay;
5671
+ private readonly bannerClose;
5672
+ private readonly bannerCycleSpeed;
5673
+ private readonly bannerToggleMute;
5962
5674
  readonly message: _angular_core.InputSignal<AXConversationMessage>;
5963
5675
  readonly rendererState: _angular_core.Signal<{
5964
5676
  deliveryStatus: _acorex_components_conversation.AXConversationMessageStatus;
@@ -5976,8 +5688,11 @@ declare class AXConversationAudioRendererComponent extends AXConversationMessage
5976
5688
  onPlaybackEnded(index: number): void;
5977
5689
  onPlaybackError(): void;
5978
5690
  togglePlay(): void;
5691
+ cyclePlaybackSpeed(): void;
5692
+ toggleMute(): void;
5979
5693
  private pauseOtherTracks;
5980
5694
  private pausePlayback;
5695
+ private applyPlaybackSettings;
5981
5696
  private syncInfoBarBanner;
5982
5697
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAudioRendererComponent, never>;
5983
5698
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationAudioRendererComponent, "ax-conversation-audio-renderer", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -6016,6 +5731,12 @@ declare class AXConversationFileRendererComponent extends AXConversationMessageR
6016
5731
 
6017
5732
  declare function normalizeFilePayload(payload: AXConversationFilePayload): AXConversationFilePayload;
6018
5733
 
5734
+ type AXConversationMediaGalleryLayoutMode = 'single' | 'dual' | 'triple' | 'masonry';
5735
+ interface AXConversationMediaGalleryRow<T> {
5736
+ items: T[];
5737
+ startIndex: number;
5738
+ }
5739
+
6019
5740
  declare class AXConversationImageRendererComponent extends AXConversationMessageRendererCopyHostComponent {
6020
5741
  private readonly fileTypes;
6021
5742
  readonly message: _angular_core.InputSignal<AXConversationMessage>;
@@ -6027,7 +5748,8 @@ declare class AXConversationImageRendererComponent extends AXConversationMessage
6027
5748
  readonly images: _angular_core.Signal<_acorex_components_conversation.AXConversationImageMediaItem[]>;
6028
5749
  readonly caption: _angular_core.Signal<string>;
6029
5750
  copy(): Promise<string>;
6030
- readonly gridModeClass: _angular_core.Signal<"ax-conversation-msg__grid--single" | "ax-conversation-msg__grid--dual" | "ax-conversation-msg__grid--multi">;
5751
+ readonly layoutMode: _angular_core.Signal<AXConversationMediaGalleryLayoutMode>;
5752
+ readonly imageRows: _angular_core.Signal<AXConversationMediaGalleryRow<_acorex_components_conversation.AXConversationImageMediaItem>[]>;
6031
5753
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationImageRendererComponent, never>;
6032
5754
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationImageRendererComponent, "ax-conversation-image-renderer", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
6033
5755
  }
@@ -6134,6 +5856,8 @@ declare class AXConversationVideoRendererComponent extends AXConversationMessage
6134
5856
  readonly videos: _angular_core.Signal<_acorex_components_conversation.AXConversationVideoMediaItem[]>;
6135
5857
  readonly caption: _angular_core.Signal<string>;
6136
5858
  readonly videoLoadErrorLabel: _angular_core.Signal<string>;
5859
+ readonly layoutMode: _angular_core.Signal<AXConversationMediaGalleryLayoutMode>;
5860
+ readonly videoRows: _angular_core.Signal<AXConversationMediaGalleryRow<_acorex_components_conversation.AXConversationVideoMediaItem>[]>;
6137
5861
  copy(): Promise<string>;
6138
5862
  constructor();
6139
5863
  onPlayingChange(index: number, playing: boolean): void;
@@ -6157,7 +5881,8 @@ declare class AXConversationVoiceRendererComponent extends AXConversationMessage
6157
5881
  private readonly platformId;
6158
5882
  private readonly destroyRef;
6159
5883
  private readonly infoBarService;
6160
- private readonly audioElementRef;
5884
+ private readonly conversationService;
5885
+ private readonly waveRef;
6161
5886
  private readonly _contentState;
6162
5887
  readonly message: _angular_core.InputSignal<AXConversationMessage>;
6163
5888
  readonly rendererState: _angular_core.Signal<{
@@ -6168,23 +5893,34 @@ declare class AXConversationVoiceRendererComponent extends AXConversationMessage
6168
5893
  readonly currentTime: _angular_core.WritableSignal<number>;
6169
5894
  readonly duration: _angular_core.WritableSignal<number>;
6170
5895
  readonly playbackSpeed: _angular_core.WritableSignal<number>;
5896
+ readonly isMuted: _angular_core.WritableSignal<boolean>;
6171
5897
  private readonly speeds;
5898
+ private lastBannerSyncAt;
5899
+ private readonly bannerTogglePlay;
5900
+ private readonly bannerClose;
5901
+ private readonly bannerCycleSpeed;
5902
+ private readonly bannerToggleMute;
6172
5903
  readonly payload: _angular_core.Signal<AXConversationVoicePayload>;
6173
5904
  private readonly mediaReference;
6174
5905
  private readonly resolvedUrl;
6175
5906
  readonly voiceUrl: _angular_core.Signal<string>;
6176
- readonly waveformBars: _angular_core.Signal<number[]>;
6177
- readonly activeBarIndex: _angular_core.Signal<number>;
5907
+ readonly isOwnMessage: _angular_core.Signal<boolean>;
5908
+ readonly waveConfig: _angular_core.Signal<AXWaveConfig>;
5909
+ readonly displayDuration: _angular_core.Signal<number>;
6178
5910
  readonly timeLabel: _angular_core.Signal<string>;
6179
5911
  readonly voiceLoadErrorLabel: _angular_core.Signal<string>;
6180
5912
  copy(): Promise<string>;
6181
5913
  constructor();
6182
5914
  togglePlay(): void;
6183
5915
  cyclePlaybackSpeed(): void;
6184
- onTimeUpdate(): void;
5916
+ toggleMute(): void;
5917
+ onWaveStatusChanged(event: AXAudioWaveChangeEvent): void;
6185
5918
  onEnded(): void;
6186
5919
  onError(): void;
6187
5920
  private pausePlayback;
5921
+ private isWavePlayable;
5922
+ private applyPlaybackSettings;
5923
+ private syncPlaybackTimeFromWave;
6188
5924
  private syncInfoBarBanner;
6189
5925
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationVoiceRendererComponent, never>;
6190
5926
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationVoiceRendererComponent, "ax-conversation-voice-renderer", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -6212,14 +5948,6 @@ declare const AX_CONVERSATION_MESSAGE_DELETE_ACTION: AXConversationMessageAction
6212
5948
  */
6213
5949
  declare const AX_CONVERSATION_MESSAGE_FORWARD_ACTION: AXConversationMessageAction;
6214
5950
 
6215
- /** Normalize payload; loads media normalizers on demand. */
6216
- declare function normalizeMessagePayloadAsync(payload: AXConversationMessagePayload): Promise<AXConversationMessagePayload>;
6217
- /**
6218
- * Sync normalize — uses cached normalizers when available.
6219
- * Media payloads pass through until a normalizer chunk has loaded (renderers normalize on display).
6220
- */
6221
- declare function normalizeMessagePayload(payload: AXConversationMessagePayload): AXConversationMessagePayload;
6222
-
6223
5951
  declare const AX_CONVERSATION_TEXT_RENDERER: AXConversationMessageRenderer;
6224
5952
 
6225
5953
  declare const AX_CONVERSATION_IMAGE_RENDERER: AXConversationMessageRenderer;
@@ -6371,284 +6099,6 @@ declare class AXConversationModule {
6371
6099
  */
6372
6100
  declare function provideConversation(options: AXConversationOptions): Provider[];
6373
6101
 
6374
- interface AXConversationAvatarDisplay {
6375
- name: string;
6376
- avatar?: string;
6377
- icon?: string;
6378
- }
6379
- /** Conversation types that resolve a single peer participant for viewer-scoped avatar/title. */
6380
- declare const AX_CONVERSATION_PEER_AVATAR_TYPES: ReadonlySet<AXConversationType>;
6381
- /**
6382
- * Other participant in a peer-scoped conversation (excludes the current viewer).
6383
- * Applies to private 1:1 and bot assist chats with exactly one non-viewer participant.
6384
- */
6385
- declare function resolveConversationPeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6386
- /** Other participant in a private chat (excludes the current user). */
6387
- declare function resolvePrivatePeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6388
- /** Peer participant for private and bot conversations. */
6389
- declare function resolveConversationPeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
6390
- /** Whether `auto` kind should render a registered user avatar for this conversation. */
6391
- declare function shouldUseUserAvatarForConversation(conversation: AXConversation, currentUserId?: string): boolean;
6392
- declare function resolveUserAvatarDisplay(userId: string, conversation: AXConversation | undefined, message?: AXConversationMessage): AXConversationAvatarDisplay;
6393
- declare function resolveConversationAvatarDisplay(conversation: AXConversation, currentUserId?: string): AXConversationAvatarDisplay;
6394
-
6395
- interface AXConversationMessageListBackgroundPreset {
6396
- id: string;
6397
- value: AXConversationMessageListThemeBackground;
6398
- }
6399
- /** Library default when no per-conversation or global background is set. */
6400
- declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND: AXConversationMessageListThemeBackground;
6401
- /** Predefined chat-area backgrounds for the info panel (light + dark variants). */
6402
- declare const AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS: AXConversationMessageListBackgroundPreset[];
6403
- declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID = "solid-default";
6404
-
6405
- /** Subtle chat-area wash when `messageListBackground` is not set (theme-aware). */
6406
- declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND: string;
6407
- declare function isMessageListThemeBackground(value: unknown): value is AXConversationMessageListThemeBackground;
6408
- /** Pick the raw CSS string for the active theme; `undefined` when unset. */
6409
- declare function resolveMessageListBackgroundRaw(value: AXConversationMessageListBackground | undefined, isDark: boolean): string | undefined;
6410
- /** Turn bare `https://...` or `/path` into valid CSS `background` for images. */
6411
- declare function normalizeMessageListBackgroundValue(raw: string): string;
6412
- /** Resolve config/metadata background for the active theme, with library default fallback. */
6413
- declare function resolveMessageListBackgroundStyle(value: AXConversationMessageListBackground | undefined, isDark: boolean): string;
6414
- /** Whether two stored backgrounds represent the same preset (supports legacy string values). */
6415
- declare function isSameMessageListBackground(a: AXConversationMessageListBackground | undefined, b: AXConversationMessageListThemeBackground, isDark: boolean): boolean;
6416
-
6417
- /** Default Font Awesome icon for group conversations without a custom avatar image. */
6418
- declare const AX_CONVERSATION_DEFAULT_GROUP_ICON = "fa-light fa-users";
6419
- /** Default Font Awesome icon for private/bot conversations without a custom avatar image. */
6420
- declare const AX_CONVERSATION_DEFAULT_USER_ICON = "fa-light fa-user";
6421
- /** True when the stored title is a placeholder, not a user-defined name. */
6422
- declare function isGenericPrivateConversationTitle(title: string | undefined): boolean;
6423
- /**
6424
- * Find an existing private 1:1 conversation between the current user and a peer.
6425
- * Matches conversations with exactly those two participants.
6426
- */
6427
- declare function findExistingPrivateConversation(conversations: AXConversation[], currentUserId: string, peerUserId: string): AXConversation | undefined;
6428
- /** Other participant in a private 1v1 chat (excludes the current viewer). */
6429
- declare function resolvePrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
6430
- /**
6431
- * Resolves the display title for the current viewer.
6432
- * Private and bot peer-scoped chats show the other participant's name when no custom title is set.
6433
- */
6434
- declare function resolveConversationTitleForViewer(conversation: AXConversation, currentUserId?: string): string;
6435
- /**
6436
- * Returns a viewer-scoped copy of a conversation with dynamic peer title/avatar/icon.
6437
- * Does not mutate the source object.
6438
- */
6439
- declare function resolveConversationForViewer(conversation: AXConversation, currentUserId?: string): AXConversation;
6440
- /** Whether message reactions are enabled for a conversation. Defaults to `true` when omitted. */
6441
- declare function isConversationReactionsEnabled(conversation?: AXConversation | null): boolean;
6442
-
6443
- /** Resolves typed `profile`, falling back to legacy `metadata.profile`. */
6444
- declare function resolveParticipantProfile(participant?: AXConversationParticipant): AXConversationUserProfile;
6445
-
6446
- declare class AXConversationDateUtilsService {
6447
- /**
6448
- * Format relative time (e.g., "2m ago", "1h ago")
6449
- */
6450
- static formatRelativeTime(date: Date): string;
6451
- /**
6452
- * Format date label (Today, Yesterday, or date)
6453
- */
6454
- static formatDateLabel(date: Date): string;
6455
- /**
6456
- * Check if two dates are the same day
6457
- */
6458
- static isSameDay(date1: Date, date2: Date): boolean;
6459
- /**
6460
- * Get date key for grouping (YYYY-MM-DD)
6461
- */
6462
- static getDateKey(date: Date): string;
6463
- /**
6464
- * Format time (HH:MM)
6465
- */
6466
- static formatTime(date: Date): string;
6467
- }
6468
-
6469
- declare class AXConversationMessageUtilsService {
6470
- /**
6471
- * Normalize optional avatar/icon values so empty or whitespace-only strings
6472
- * are treated as missing data.
6473
- */
6474
- private static normalizeOptionalMediaValue;
6475
- /**
6476
- * Get conversation avatar image URL.
6477
- */
6478
- static getConversationAvatar(conversation: AXConversation): string | undefined;
6479
- /**
6480
- * Font Awesome icon class(es) for a conversation when there is no avatar image.
6481
- */
6482
- static getConversationAvatarIcon(conversation: AXConversation): string | undefined;
6483
- /**
6484
- * Font Awesome icon for a participant when there is no avatar image.
6485
- */
6486
- static getParticipantAvatarIcon(participant?: {
6487
- avatar?: string;
6488
- icon?: string;
6489
- }): string | undefined;
6490
- /**
6491
- * Get sender name from message
6492
- */
6493
- static getSenderName(message: AXConversationMessage, conversation: AXConversation): string;
6494
- /**
6495
- * Get sender avatar image URL (takes precedence over {@link getSenderAvatarIcon}).
6496
- */
6497
- static getSenderAvatar(message: AXConversationMessage, conversation: AXConversation): string | undefined;
6498
- /**
6499
- * Font Awesome icon class(es) for the sender when there is no avatar image:
6500
- * participant `icon` first, then conversation-level `icon`.
6501
- */
6502
- static getSenderAvatarIcon(message: AXConversationMessage, conversation: AXConversation): string | undefined;
6503
- /**
6504
- * Get initials from name
6505
- */
6506
- static getInitials(name: string): string;
6507
- /**
6508
- * Type guard for text payload
6509
- */
6510
- static isTextPayload(payload: AXConversationMessagePayload): payload is AXConversationTextPayload;
6511
- /**
6512
- * Get message text content
6513
- */
6514
- static getMessageText(message: AXConversationMessage): string;
6515
- /**
6516
- * Format message preview text
6517
- */
6518
- static getPreviewText(message: AXConversationMessage, maxLength?: number): {
6519
- value: string;
6520
- type: string;
6521
- icon: string;
6522
- };
6523
- /**
6524
- * Check if message is from current user
6525
- */
6526
- static isOwnMessage(message: AXConversationMessage, currentUserId: string): boolean;
6527
- /**
6528
- * Get message status icon class (Font Awesome)
6529
- */
6530
- static getStatusIcon(message: AXConversationMessage): string;
6531
- /**
6532
- * Check if message should show avatar
6533
- */
6534
- static shouldShowAvatar(message: AXConversationMessage, previousMessage: AXConversationMessage | undefined, conversation: AXConversation): boolean;
6535
- /**
6536
- * Group messages by sender for consecutive messages
6537
- */
6538
- static shouldGroupWithPrevious(message: AXConversationMessage, previousMessage: AXConversationMessage | undefined): boolean;
6539
- /**
6540
- * Get conversation status for avatar (private conversations only)
6541
- */
6542
- static getConversationStatus(conversation: AXConversation): 'online' | 'offline' | 'away' | undefined;
6543
- /**
6544
- * Get typing indicator text for conversation
6545
- */
6546
- static getTypingText(conversation: AXConversation): string;
6547
- /**
6548
- * Format last seen time
6549
- */
6550
- static formatLastSeen(date: Date): string;
6551
- /**
6552
- * Get conversation subtitle (status or member count)
6553
- */
6554
- static getConversationSubtitle(conversation: AXConversation): string;
6555
- }
6556
-
6557
- /**
6558
- * Validation Utilities
6559
- * Centralized validation functions for messages and user input
6560
- */
6561
-
6562
- /**
6563
- * Validation result interface
6564
- */
6565
- interface AXConversationValidationResult {
6566
- /** Whether validation passed */
6567
- valid: boolean;
6568
- /** Error message if validation failed */
6569
- error?: string;
6570
- /** Error code for programmatic handling */
6571
- errorCode?: string;
6572
- }
6573
- /**
6574
- * Validate message text content
6575
- * @param text - Text to validate
6576
- * @param config - Configuration for validation rules
6577
- * @returns Validation result
6578
- */
6579
- declare function validateMessageText(text: string | undefined, config: AXConversationConfig): AXConversationValidationResult;
6580
- /**
6581
- * Validate conversation ID
6582
- * @param conversationId - Conversation ID to validate
6583
- * @returns Validation result
6584
- */
6585
- declare function validateConversationId(conversationId: string | undefined): AXConversationValidationResult;
6586
- /**
6587
- * Validate message type
6588
- * @param type - Message type to validate
6589
- * @returns Validation result
6590
- */
6591
- declare function validateMessageType(type: AXConversationMessageType | undefined): AXConversationValidationResult;
6592
- /**
6593
- * Validate message payload
6594
- * @param payload - Message payload to validate
6595
- * @param type - Message type
6596
- * @returns Validation result
6597
- */
6598
- declare function validateMessagePayload(payload: AXConversationMessagePayload | undefined, type: AXConversationMessageType): Promise<AXConversationValidationResult>;
6599
- /**
6600
- * Validate user ID
6601
- * @param userId - User ID to validate
6602
- * @returns Validation result
6603
- */
6604
- declare function validateUserId(userId: string | undefined): AXConversationValidationResult;
6605
- /**
6606
- * Validate array of user IDs
6607
- * @param userIds - Array of user IDs to validate
6608
- * @param minCount - Minimum number of users required
6609
- * @param maxCount - Maximum number of users allowed
6610
- * @returns Validation result
6611
- */
6612
- declare function validateUserIds(userIds: string[] | undefined, minCount?: number, maxCount?: number): AXConversationValidationResult;
6613
- /**
6614
- * Validate email address
6615
- * @param email - Email to validate
6616
- * @returns Validation result
6617
- */
6618
- declare function validateEmail(email: string | undefined): AXConversationValidationResult;
6619
- /**
6620
- * Validate URL
6621
- * @param url - URL to validate
6622
- * @returns Validation result
6623
- */
6624
- declare function validateUrl(url: string | undefined): AXConversationValidationResult;
6625
- /**
6626
- * Sanitize user input to prevent XSS
6627
- * Note: Angular provides built-in sanitization, but this is an additional layer
6628
- * @param input - User input to sanitize
6629
- * @returns Sanitized input
6630
- */
6631
- declare function sanitizeInput(input: string): string;
6632
- /**
6633
- * Validate latitude coordinate
6634
- * @param latitude - Latitude to validate
6635
- * @returns Validation result
6636
- */
6637
- declare function validateLatitude(latitude: number | undefined | null): AXConversationValidationResult;
6638
- /**
6639
- * Validate longitude coordinate
6640
- * @param longitude - Longitude to validate
6641
- * @returns Validation result
6642
- */
6643
- declare function validateLongitude(longitude: number | undefined | null): AXConversationValidationResult;
6644
-
6645
- /** Infer extension/MIME hints from a persisted message payload. */
6646
- declare function inferFileExtensionHintFromMessage(message: AXConversationMessage): AXFileTypeExtensionHint;
6647
- /** Use file-type `copy` on the message when `message.fileType` is set; otherwise fallback. */
6648
- declare function copyWithFileTypeFallback(message: AXConversationMessage, registry: AXFileTypeRegistryService, fallback: () => string): Promise<string>;
6649
- /** Use file-type `open` on the message when `message.fileType` is set. */
6650
- declare function openWithFileType(message: AXConversationMessage, registry: AXFileTypeRegistryService, ctx: AXFileTypeOpenContext): Promise<boolean>;
6651
-
6652
6102
  /**
6653
6103
  * Error Message Constants
6654
6104
  * Centralized error messages with i18n support structure
@@ -7041,5 +6491,5 @@ declare function getErrorMessage(code: string, params?: Record<string, string |
7041
6491
  */
7042
6492
  type AXConversationErrorCode = typeof AX_CONVERSATION_MESSAGE_ERRORS[keyof typeof AX_CONVERSATION_MESSAGE_ERRORS]['code'] | typeof AX_CONVERSATION_FILE_ERRORS[keyof typeof AX_CONVERSATION_FILE_ERRORS]['code'] | typeof AX_CONVERSATION_USER_ERRORS[keyof typeof AX_CONVERSATION_USER_ERRORS]['code'] | typeof AX_CONVERSATION_ERRORS[keyof typeof AX_CONVERSATION_ERRORS]['code'] | typeof AX_CONVERSATION_CONNECTION_ERRORS[keyof typeof AX_CONVERSATION_CONNECTION_ERRORS]['code'] | typeof AX_CONVERSATION_LOCATION_ERRORS[keyof typeof AX_CONVERSATION_LOCATION_ERRORS]['code'] | typeof AX_CONVERSATION_URL_ERRORS[keyof typeof AX_CONVERSATION_URL_ERRORS]['code'];
7043
6493
 
7044
- export { AXConversationAiResponderService, AXConversationApi, AXConversationApiLoggerService, AXConversationAudioAttachmentComponent, AXConversationAudioFileTypeProvider, AXConversationAudioPickerComponent, AXConversationAudioRendererComponent, AXConversationBaseRegistry, AXConversationComposerActionRegistry, AXConversationComposerComponent, AXConversationComposerFileTypesProvider, AXConversationComposerPopupComponent, AXConversationComposerService, AXConversationComposerTabRegistry, AXConversationContainerComponent, AXConversationContainerDirective, AXConversationDateUtilsService, AXConversationEmojiTabComponent, AXConversationErrorHandlerService, AXConversationFallbackRendererComponent, AXConversationFileAttachmentComponent, AXConversationFileFileTypeProvider, AXConversationFilePickerComponent, AXConversationFileRendererComponent, AXConversationForwardMessageDialogComponent, AXConversationImageAttachmentComponent, AXConversationImageFileTypeProvider, AXConversationImagePickerComponent, AXConversationImageRendererComponent, AXConversationIndexedDbConversationApi, AXConversationIndexedDbMessageAiApi, AXConversationIndexedDbMessageApi, AXConversationIndexedDbRealtimeApi, AXConversationIndexedDbStorage, AXConversationIndexedDbStores, AXConversationIndexedDbUserApi, AXConversationInfiniteScrollDirective, AXConversationInfoBarActionRegistry, AXConversationInfoBarComponent, AXConversationInfoBarSearchComponent, AXConversationInfoBarService, AXConversationInfoMediaViewComponent, AXConversationInfoPanelComponent, AXConversationItemActionRegistry, AXConversationLocationPickerComponent, AXConversationLocationRendererComponent, AXConversationMediaPlaybackInfoBarBannerComponent, AXConversationMessageActionRegistry, AXConversationMessageApi, AXConversationMessageListComponent, AXConversationMessageListNoActiveDefaultComponent, AXConversationMessageListService, AXConversationMessageRendererCopyHostComponent, AXConversationMessageRendererRegistry, AXConversationMessageRendererStateComponent, AXConversationMessageUtilsService, AXConversationModule, AXConversationNewDialogComponent, AXConversationPickerCaptionComponent, AXConversationPickerEmptyComponent, AXConversationPickerFooterComponent, AXConversationPickerHeaderComponent, AXConversationPickerShellComponent, AXConversationPickerToolbarComponent, AXConversationRealtimeApi, AXConversationRegistryService, AXConversationService, AXConversationSharedStorage, AXConversationSidebarComponent, AXConversationSidebarService, AXConversationStickerRendererComponent, AXConversationStickerTabComponent, AXConversationSystemRendererComponent, AXConversationTabRegistry, AXConversationTextRendererComponent, AXConversationUserApi, AXConversationVideoAttachmentComponent, AXConversationVideoFileTypeProvider, AXConversationVideoPickerComponent, AXConversationVideoRendererComponent, AXConversationVoiceFileTypeProvider, AXConversationVoiceRecorderComponent, AXConversationVoiceRendererComponent, AX_CONVERSATION_AI_API_KEY, AX_CONVERSATION_AUDIO_CATALOG, AX_CONVERSATION_AUDIO_PRESENTATION, AX_CONVERSATION_AUDIO_RENDERER, AX_CONVERSATION_BUILTIN_COMPOSER_TABS, AX_CONVERSATION_COMPOSER_AUDIO_ACTION, AX_CONVERSATION_COMPOSER_EMOJI_ACTION, AX_CONVERSATION_COMPOSER_EMOJI_TAB, AX_CONVERSATION_COMPOSER_FILE_ACTION, AX_CONVERSATION_COMPOSER_IMAGE_ACTION, AX_CONVERSATION_COMPOSER_LOCATION_ACTION, AX_CONVERSATION_COMPOSER_STICKER_TAB, AX_CONVERSATION_COMPOSER_VIDEO_ACTION, AX_CONVERSATION_COMPOSER_VOICE_RECORDING_ACTION, AX_CONVERSATION_CONFIG, AX_CONVERSATION_CONNECTION_ERRORS, AX_CONVERSATION_CONVERSATION_AVATAR_COMPONENT, AX_CONVERSATION_CURSOR_PREFIX, AX_CONVERSATION_DEFAULT_COMPOSER_ACTIONS, AX_CONVERSATION_DEFAULT_COMPOSER_TABS, AX_CONVERSATION_DEFAULT_CONVERSATION_ITEM_ACTIONS, AX_CONVERSATION_DEFAULT_CONVERSATION_TABS, AX_CONVERSATION_DEFAULT_GROUP_ICON, AX_CONVERSATION_DEFAULT_INFO_BAR_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND, AX_CONVERSATION_DEFAULT_MESSAGE_RENDERERS, AX_CONVERSATION_DEFAULT_USER_ICON, AX_CONVERSATION_DEMO_CONVERSATION_IDS, AX_CONVERSATION_ERRORS, AX_CONVERSATION_ERROR_HANDLER_CONFIG, AX_CONVERSATION_ERROR_MESSAGES, AX_CONVERSATION_FALLBACK_RENDERER, AX_CONVERSATION_FILE_CATALOG, AX_CONVERSATION_FILE_ERRORS, AX_CONVERSATION_FILE_PRESENTATION, AX_CONVERSATION_FILE_RENDERER, AX_CONVERSATION_FILE_TYPES_READY, AX_CONVERSATION_IMAGE_CATALOG, AX_CONVERSATION_IMAGE_PRESENTATION, AX_CONVERSATION_IMAGE_RENDERER, AX_CONVERSATION_INFO_BAR_ARCHIVE_ACTION, AX_CONVERSATION_INFO_BAR_BLOCK_ACTION, AX_CONVERSATION_INFO_BAR_DELETE_ACTION, AX_CONVERSATION_INFO_BAR_DIVIDER, AX_CONVERSATION_INFO_BAR_MUTE_ACTION, AX_CONVERSATION_INFO_BAR_SEARCH_ACTION, AX_CONVERSATION_ITEM_BLOCK_ACTION, AX_CONVERSATION_ITEM_DELETE_ACTION, AX_CONVERSATION_ITEM_DIVIDER, AX_CONVERSATION_ITEM_MARK_READ_ACTION, AX_CONVERSATION_ITEM_MUTE_ACTION, AX_CONVERSATION_ITEM_PIN_ACTION, AX_CONVERSATION_LOCATION_ERRORS, AX_CONVERSATION_LOCATION_RENDERER, AX_CONVERSATION_MESSAGE_CURSOR_PREFIX, AX_CONVERSATION_MESSAGE_DELETE_ACTION, AX_CONVERSATION_MESSAGE_EDIT_ACTION, AX_CONVERSATION_MESSAGE_ERRORS, AX_CONVERSATION_MESSAGE_FORWARD_ACTION, AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS, AX_CONVERSATION_MESSAGE_REPLY_ACTION, AX_CONVERSATION_MESSAGE_TYPE_FILE_TYPE, AX_CONVERSATION_PEER_AVATAR_TYPES, AX_CONVERSATION_REGISTRY_CONFIG, AX_CONVERSATION_STICKER_API_KEY, AX_CONVERSATION_STICKER_RENDERER, AX_CONVERSATION_SYSTEM_RENDERER, AX_CONVERSATION_TAB_ALL, AX_CONVERSATION_TAB_ARCHIVED, AX_CONVERSATION_TAB_BOT, AX_CONVERSATION_TAB_CHANNELS, AX_CONVERSATION_TAB_GROUPS, AX_CONVERSATION_TAB_PRIVATE, AX_CONVERSATION_TAB_UNREAD, AX_CONVERSATION_TEXT_RENDERER, AX_CONVERSATION_URL_ERRORS, AX_CONVERSATION_USER_AVATAR_COMPONENT, AX_CONVERSATION_USER_ERRORS, AX_CONVERSATION_VIDEO_CATALOG, AX_CONVERSATION_VIDEO_PRESENTATION, AX_CONVERSATION_VIDEO_RENDERER, AX_CONVERSATION_VOICE_CATALOG, AX_CONVERSATION_VOICE_PRESENTATION, AX_CONVERSATION_VOICE_RENDERER, AX_DEFAULT_CONVERSATION_CONFIG, AX_MESSAGE_PAGINATION_CONVERSATION_ID, abortPickerUploads, applyAudioLocalPreview, applyConversationFilters, applyFileLocalPreview, applyLocalPreview, applyVideoLocalPreview, applyVoiceLocalPreview, audioItemFromUpload, axConversationIndexedDbStorage, axConversationSharedStorage, bindMediaRendererContentState, buildMediaGalleryTiles, canShowRendererContentError, cleanupPickerUploads, conversationAudioUtilities, conversationFileUtilities, conversationImageUtilities, conversationVideoUtilities, conversationVoiceUtilities, copyWithFileTypeFallback, createConversationAudioFileType, createConversationFileFileType, createConversationImageFileType, createConversationVideoFileType, createConversationVoiceFileType, createLocalPreviewUrl, createObjectUrl, createPickerDragHandlers, createResolvedMediaUrlSignal, deleteUploadedPickerMedia, dismissComposerPickerHost, encodeConversationCursor, encodeMessageCursor, ensurePaginationDemoData, fetchConversationMediaMessages, fetchConversationMediaPage, fileItemFromUpload, filterMessagesByMediaCategory, filterSupplementalInfoPanelMessages, findExistingPrivateConversation, formatDuration, formatErrorMessage, formatFileByteSize, formatFileSize, formatMediaDuration, formatPickerValidationMessage, getConversationLastActivity, getConversationMediaCategories, getConversationMessagesNewestFirst, getConversationProfileFields, getErrorMessage, getMessageAudioItems, getMessageVideoItems, getPickerCancelUploadLabel, getPrivatePeerParticipant, getSortedConversationsForInbox, inferFileExtensionHintFromMessage, isAttachmentListCategory, isComposerTabEnabled, isConversationReactionsEnabled, isGenericPrivateConversationTitle, isGridMediaCategory, isMessageDeliveryPending, isMessageListThemeBackground, isNonPersistableMediaUrl, isPickerItemReadyToSend, isSameMessageListBackground, isUploadAborted, limitFilesToCapacity, mediaCopyText, mergeAudioUploadResult, mergeFileUploadResult, mergeInfoPanelMessages, mergeUploadResult, mergeVideoUploadResult, mergeVoiceUploadResult, mergeWithDefaults, messageContainsLink, normalizeAllConversationMessageIndexes, normalizeAudioPayload, normalizeFilePayload, normalizeImagePayload, normalizeMessageListBackgroundValue, normalizeMessagePayload, normalizeMessagePayloadAsync, normalizeVideoPayload, notifyMaxFilesCapacityExceeded, notifyPickerValidationErrors, openWithFileType, paginateChatNewestFirst, paginateChatOldestFirst, parseChatCursor, pickDisplayMediaUrl, pickerItemToMediaReference, pickerItemToUploadResult, provideConversation, provideConversationComposerFileTypes, provideConversationFileCatalog, registerChatMessage, reportMediaLoadError, resolveComposerMaxFiles, resolveConversationAvatarDisplay, resolveConversationComposerTabs, resolveConversationForViewer, resolveConversationMessageFileType, resolveConversationPeerParticipant, resolveConversationPeerUserId, resolveConversationTitleForViewer, resolveGalleryImageUrl, resolveImageDisplayUrl, resolveMessageListBackgroundRaw, resolveMessageListBackgroundStyle, resolveParticipantProfile, resolvePersistableMediaUrl, resolvePersistedThumbnailUrl, resolvePrivatePeerParticipant, resolvePrivatePeerUserId, resolveUserAvatarDisplay, resolveVideoThumbnailUrl, revokeObjectUrl, revokePickerBlobPreviews, sanitizeInput, seedPickerInitialFiles, seedSharedStorageInitialData, shouldUseUserAvatarForConversation, sortConversationMessageIds, syncPlaybackInfoBarBanner, toUploaderReference as toMediaItemUploaderReference, toUploaderReference$1 as toUploaderReference, unregisterChatMessage, uploadPickerFile, validateConversationId, validateEmail, validateLatitude, validateLongitude, validateMessagePayload, validateMessageText, validateMessageType, validateUrl, validateUserId, validateUserIds, videoItemFromUpload };
7045
- export type { AXConversation, AXConversationAiResponderConfig, AXConversationApiError, AXConversationApiLogEntry, AXConversationApiName, AXConversationAudioMediaItem, AXConversationAudioPayload, AXConversationAvatarComponents, AXConversationAvatarDisplay, AXConversationAvatarKind, AXConversationBlockReportReason, AXConversationCallEvent, AXConversationChatCursorKind, AXConversationCleanupPickerUploadsOptions, AXConversationComposerAction, AXConversationComposerActionComponent, AXConversationComposerActionContext, AXConversationComposerActiveComponent, AXConversationComposerPickerUploadItem, AXConversationComposerTab, AXConversationComposerTabFeature, AXConversationConfig, AXConversationConnectionEvent, AXConversationConnectionOptions, AXConversationConnectionStatus, AXConversationConversationAvatarComponent, AXConversationCreateData, AXConversationDeleteMessageCommand, AXConversationDropdownMenuItem, AXConversationEditMessageCommand, AXConversationError, AXConversationErrorCode, AXConversationErrorHandlerConfig, AXConversationErrorMessage, AXConversationErrorSeverity, AXConversationFeatures, AXConversationFileMediaItem, AXConversationFilePayload, AXConversationFilter, AXConversationFilters, AXConversationGroupedReaction, AXConversationImageMediaItem, AXConversationImagePayload, AXConversationIndexedDbMediaRecord, AXConversationInfoBarAction, AXConversationInfoBarActionComponent, AXConversationInfoBarActionContext, AXConversationInfoBarActiveBanner, AXConversationInfoBarActiveComponent, AXConversationInfoProfileField, AXConversationItemAction, AXConversationItemActionContext, AXConversationLink, AXConversationLinkPreview, AXConversationLoadMessagesResult, AXConversationLocationPayload, AXConversationMediaCategory, AXConversationMediaCategoryId, AXConversationMediaGalleryTile, AXConversationMediaItemFields, AXConversationMediaPageResult, AXConversationMention, AXConversationMessage, AXConversationMessageAction, AXConversationMessageActionContext, AXConversationMessageForwardData, AXConversationMessageInfoBarBannerComponent, AXConversationMessageListBackground, AXConversationMessageListBackgroundPreset, AXConversationMessageListEmptyComponent, AXConversationMessageListThemeBackground, AXConversationMessagePayload, AXConversationMessageRenderer, AXConversationMessageRendererCapabilities, AXConversationMessageRendererComponent, AXConversationMessageRendererContentState, AXConversationMessageRendererState, AXConversationMessageSearchFilters, AXConversationMessageStatus, AXConversationMessageType, AXConversationMetadata, AXConversationNotificationEvent, AXConversationOptions, AXConversationPaginatedResult, AXConversationPagination, AXConversationPaginationState, AXConversationParsedChatCursor, AXConversationParticipant, AXConversationParticipantRole, AXConversationParticipantStatus, AXConversationParticipantUpdate, AXConversationPinnedMessage, AXConversationPlaybackBannerInputs, AXConversationPollOption, AXConversationPollPayload, AXConversationPresenceStatus, AXConversationPresenceUpdate, AXConversationReaction, AXConversationReadReceipt, AXConversationRegistryConfiguration, AXConversationRegistryItem, AXConversationSendMessageCommand, AXConversationSendMessageOptions, AXConversationSendMessageUploadSource, AXConversationSettings, AXConversationSettingsUpdate, AXConversationSort, AXConversationStatus, AXConversationStickerPayload, AXConversationSystemPayload, AXConversationTab, AXConversationTextFormat, AXConversationTextPayload, AXConversationType, AXConversationTypingIndicator, AXConversationUpdateData, AXConversationUploadOptions, AXConversationUploaderFilePreview, AXConversationUploaderReference, AXConversationUploaderResult, AXConversationUserAvatarComponent, AXConversationUserProfile, AXConversationUserProfileUpdate, AXConversationUserRole, AXConversationUserSearchFilters, AXConversationValidationResult, AXConversationVideoMediaItem, AXConversationVideoPayload, AXConversationVoicePayload };
6494
+ export { AXConversationApi, AXConversationApiLoggerService, AXConversationAudioAttachmentComponent, AXConversationAudioFileTypeProvider, AXConversationAudioPickerComponent, AXConversationAudioRendererComponent, AXConversationAvatarComponent, AXConversationAvatarPickerComponent, AXConversationBaseRegistry, AXConversationComposerActionRegistry, AXConversationComposerComponent, AXConversationComposerFileTypesProvider, AXConversationComposerGenerationStateService, AXConversationComposerPopupComponent, AXConversationComposerService, AXConversationComposerTabRegistry, AXConversationContainerComponent, AXConversationContainerDirective, AXConversationDateUtilsService, AXConversationEmojiTabComponent, AXConversationErrorHandlerService, AXConversationFallbackRendererComponent, AXConversationFileAttachmentComponent, AXConversationFileFileTypeProvider, AXConversationFilePickerComponent, AXConversationFileRendererComponent, AXConversationForwardMessageDialogComponent, AXConversationImageAttachmentComponent, AXConversationImageFileTypeProvider, AXConversationImagePickerComponent, AXConversationImageRendererComponent, AXConversationInfiniteScrollDirective, AXConversationInfoBarActionRegistry, AXConversationInfoBarComponent, AXConversationInfoBarSearchComponent, AXConversationInfoBarService, AXConversationItemActionRegistry, AXConversationLocationPickerComponent, AXConversationLocationRendererComponent, AXConversationMediaPlaybackInfoBarBannerComponent, AXConversationMessageActionRegistry, AXConversationMessageApi, AXConversationMessageListComponent, AXConversationMessageListNoActiveDefaultComponent, AXConversationMessageListService, AXConversationMessageRendererCopyHostComponent, AXConversationMessageRendererRegistry, AXConversationMessageRendererStateComponent, AXConversationMessageUtilsService, AXConversationModule, AXConversationNewDialogComponent, AXConversationPickerCaptionComponent, AXConversationPickerEmptyComponent, AXConversationPickerFooterComponent, AXConversationPickerHeaderComponent, AXConversationPickerOptionsComponent, AXConversationPickerShellComponent, AXConversationPickerToolbarComponent, AXConversationRealtimeApi, AXConversationRegistryComponentOutletComponent, AXConversationRegistryService, AXConversationService, AXConversationSidebarComponent, AXConversationSidebarService, AXConversationStickerRendererComponent, AXConversationStickerTabComponent, AXConversationSystemRendererComponent, AXConversationTabRegistry, AXConversationTextRendererComponent, AXConversationUserApi, AXConversationVideoAttachmentComponent, AXConversationVideoFileTypeProvider, AXConversationVideoPickerComponent, AXConversationVideoRendererComponent, AXConversationVoiceFileTypeProvider, AXConversationVoiceRecorderComponent, AXConversationVoiceRendererComponent, AX_CONVERSATION_AUDIO_CATALOG, AX_CONVERSATION_AUDIO_PRESENTATION, AX_CONVERSATION_AUDIO_RENDERER, AX_CONVERSATION_BUILTIN_COMPOSER_TABS, AX_CONVERSATION_COMPOSER_AUDIO_ACTION, AX_CONVERSATION_COMPOSER_EMOJI_ACTION, AX_CONVERSATION_COMPOSER_EMOJI_TAB, AX_CONVERSATION_COMPOSER_FILE_ACTION, AX_CONVERSATION_COMPOSER_IMAGE_ACTION, AX_CONVERSATION_COMPOSER_LOCATION_ACTION, AX_CONVERSATION_COMPOSER_STICKER_TAB, AX_CONVERSATION_COMPOSER_VIDEO_ACTION, AX_CONVERSATION_COMPOSER_VOICE_RECORDING_ACTION, AX_CONVERSATION_CONFIG, AX_CONVERSATION_CONNECTION_ERRORS, AX_CONVERSATION_CONVERSATION_AVATAR_COMPONENT, AX_CONVERSATION_DEFAULT_COMPOSER_ACTIONS, AX_CONVERSATION_DEFAULT_COMPOSER_TABS, AX_CONVERSATION_DEFAULT_CONVERSATION_ITEM_ACTIONS, AX_CONVERSATION_DEFAULT_CONVERSATION_TABS, AX_CONVERSATION_DEFAULT_GROUP_ICON, AX_CONVERSATION_DEFAULT_INFO_BAR_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID, AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND, AX_CONVERSATION_DEFAULT_MESSAGE_RENDERERS, AX_CONVERSATION_DEFAULT_ROOM_PREFERENCES, AX_CONVERSATION_DEFAULT_USER_ICON, AX_CONVERSATION_ERRORS, AX_CONVERSATION_ERROR_HANDLER_CONFIG, AX_CONVERSATION_ERROR_MESSAGES, AX_CONVERSATION_FALLBACK_RENDERER, AX_CONVERSATION_FILE_CATALOG, AX_CONVERSATION_FILE_ERRORS, AX_CONVERSATION_FILE_PRESENTATION, AX_CONVERSATION_FILE_RENDERER, AX_CONVERSATION_FILE_TYPES_READY, AX_CONVERSATION_IMAGE_CATALOG, AX_CONVERSATION_IMAGE_PRESENTATION, AX_CONVERSATION_IMAGE_RENDERER, AX_CONVERSATION_INFO_BAR_ARCHIVE_ACTION, AX_CONVERSATION_INFO_BAR_BLOCK_ACTION, AX_CONVERSATION_INFO_BAR_DELETE_ACTION, AX_CONVERSATION_INFO_BAR_DIVIDER, AX_CONVERSATION_INFO_BAR_MUTE_ACTION, AX_CONVERSATION_INFO_BAR_SEARCH_ACTION, AX_CONVERSATION_ITEM_BLOCK_ACTION, AX_CONVERSATION_ITEM_DELETE_ACTION, AX_CONVERSATION_ITEM_DIVIDER, AX_CONVERSATION_ITEM_MARK_READ_ACTION, AX_CONVERSATION_ITEM_MUTE_ACTION, AX_CONVERSATION_ITEM_PIN_ACTION, AX_CONVERSATION_LOCATION_ERRORS, AX_CONVERSATION_LOCATION_RENDERER, AX_CONVERSATION_MESSAGE_DELETE_ACTION, AX_CONVERSATION_MESSAGE_EDIT_ACTION, AX_CONVERSATION_MESSAGE_ERRORS, AX_CONVERSATION_MESSAGE_FORWARD_ACTION, AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS, AX_CONVERSATION_MESSAGE_REPLY_ACTION, AX_CONVERSATION_MESSAGE_TYPE_FILE_TYPE, AX_CONVERSATION_PEER_AVATAR_TYPES, AX_CONVERSATION_REGISTRY_CONFIG, AX_CONVERSATION_STICKER_API_KEY, AX_CONVERSATION_STICKER_RENDERER, AX_CONVERSATION_SYSTEM_RENDERER, AX_CONVERSATION_TAB_ALL, AX_CONVERSATION_TAB_ARCHIVED, AX_CONVERSATION_TAB_BOT, AX_CONVERSATION_TAB_CHANNELS, AX_CONVERSATION_TAB_GROUPS, AX_CONVERSATION_TAB_PRIVATE, AX_CONVERSATION_TAB_UNREAD, AX_CONVERSATION_TEXT_RENDERER, AX_CONVERSATION_URL_ERRORS, AX_CONVERSATION_USER_AVATAR_COMPONENT, AX_CONVERSATION_USER_ERRORS, AX_CONVERSATION_VIDEO_CATALOG, AX_CONVERSATION_VIDEO_PRESENTATION, AX_CONVERSATION_VIDEO_RENDERER, AX_CONVERSATION_VOICE_CATALOG, AX_CONVERSATION_VOICE_PRESENTATION, AX_CONVERSATION_VOICE_RENDERER, AX_DEFAULT_CONVERSATION_CONFIG, abortPickerUploads, applyAudioLocalPreview, applyFileLocalPreview, applyLocalPreview, applyVideoLocalPreview, applyVoiceLocalPreview, audioItemFromUpload, bindMediaRendererContentState, buildMediaGalleryTiles, canShowRendererContentError, cleanupPickerUploads, conversationAudioUtilities, conversationFileUtilities, conversationImageUtilities, conversationVideoUtilities, conversationVoiceUtilities, copyWithFileTypeFallback, createConversationAudioFileType, createConversationFileFileType, createConversationImageFileType, createConversationVideoFileType, createConversationVoiceFileType, createLocalPreviewUrl, createObjectUrl, createPickerDragHandlers, createPickerUploadItemId, createResolvedMediaUrlSignal, deleteUploadedPickerMedia, dismissComposerPickerHost, ensureConversationFileCatalogRegistered, fetchConversationMediaPage, fileItemFromUpload, filterMessagesByMediaCategory, filterSupplementalInfoPanelMessages, findExistingPrivateConversation, formatDuration, formatErrorMessage, formatFileByteSize, formatFileSize, formatMediaDuration, formatPickerValidationMessage, getConversationMediaCategories, getConversationProfileFields, getErrorMessage, getMessageAudioItems, getMessageVideoItems, getPickerCancelUploadLabel, getPrivatePeerParticipant, hasRegistryComponent, inferFileExtensionHintFromMessage, isAttachmentListCategory, isComposerTabEnabled, isConversationReactionsEnabled, isGenericPrivateConversationTitle, isGridMediaCategory, isMessageDeliveryPending, isMessageListThemeBackground, isNonPersistableMediaUrl, isPickerItemReadyToSend, isSameMessageListBackground, isUploadAborted, limitFilesToCapacity, mediaCopyText, mergeAudioUploadResult, mergeFileUploadResult, mergeInfoPanelMessages, mergeUploadResult, mergeVideoUploadResult, mergeVoiceUploadResult, mergeWithDefaults, messageContainsLink, normalizeAudioPayload, normalizeFilePayload, normalizeImagePayload, normalizeMessageListBackgroundValue, normalizeVideoPayload, notifyMaxFilesCapacityExceeded, notifyPickerValidationErrors, openWithFileType, pickDisplayMediaUrl, pickerItemToMediaReference, pickerItemToUploadResult, provideConversation, provideConversationComposerFileTypes, provideConversationFileCatalog, reportMediaLoadError, resolveComposerMaxFiles, resolveConversationAvatarDisplay, resolveConversationComposerTabs, resolveConversationForViewer, resolveConversationMessageFileType, resolveConversationPeerParticipant, resolveConversationPeerUserId, resolveConversationTitleForViewer, resolveGalleryImageUrl, resolveImageDisplayUrl, resolveMessageListBackgroundRaw, resolveMessageListBackgroundStyle, resolveParticipantProfile, resolvePersistableMediaUrl, resolvePersistedThumbnailUrl, resolvePrivatePeerParticipant, resolvePrivatePeerUserId, resolveUserAvatarDisplay, resolveVideoThumbnailUrl, revokeObjectUrl, revokePickerBlobPreviews, sanitizeInput, shouldUseUserAvatarForConversation, syncPlaybackInfoBarBanner, toUploaderReference as toMediaItemUploaderReference, toUploaderReference$1 as toUploaderReference, uploadPickerFile, usesDefaultMessageListWallpaper, validateConversationId, validateEmail, validateLatitude, validateLongitude, validateMessagePayload, validateMessageText, validateMessageType, validateUrl, validateUserId, validateUserIds, videoItemFromUpload };
6495
+ export type { AXConversation, AXConversationApiError, AXConversationApiLogEntry, AXConversationApiName, AXConversationAudioMediaItem, AXConversationAudioPayload, AXConversationAvatarComponents, AXConversationAvatarDisplay, AXConversationAvatarKind, AXConversationBlockReportReason, AXConversationCleanupPickerUploadsOptions, AXConversationComposerAction, AXConversationComposerActionComponent, AXConversationComposerActionContext, AXConversationComposerGenerationPhase, AXConversationComposerPickerUploadItem, AXConversationComposerPrimaryButtonMode, AXConversationComposerTab, AXConversationComposerTabFeature, AXConversationConfig, AXConversationConnectionStatus, AXConversationConversationAvatarComponent, AXConversationCreateData, AXConversationDateSeparatorKind, AXConversationDeleteMessageCommand, AXConversationDropdownMenuItem, AXConversationEditMessageCommand, AXConversationError, AXConversationErrorCode, AXConversationErrorHandlerConfig, AXConversationErrorMessage, AXConversationErrorSeverity, AXConversationFeatures, AXConversationFileMediaItem, AXConversationFilePayload, AXConversationFilter, AXConversationFilters, AXConversationGroupedReaction, AXConversationImageMediaItem, AXConversationImagePayload, AXConversationInfoBarAction, AXConversationInfoBarActionComponent, AXConversationInfoBarActionContext, AXConversationInfoBarActiveBanner, AXConversationInfoBarActiveComponent, AXConversationInfoProfileField, AXConversationItemAction, AXConversationItemActionContext, AXConversationLink, AXConversationLinkPreview, AXConversationLoadMessagesResult, AXConversationLocationPayload, AXConversationMediaCategory, AXConversationMediaCategoryId, AXConversationMediaGalleryTile, AXConversationMediaItemFields, AXConversationMediaPageResult, AXConversationMention, AXConversationMessage, AXConversationMessageAction, AXConversationMessageActionContext, AXConversationMessageClusterRole, AXConversationMessageDateGroup, AXConversationMessageForwardData, AXConversationMessageInfoBarBannerComponent, AXConversationMessageListBackground, AXConversationMessageListBackgroundPreset, AXConversationMessageListEmptyComponent, AXConversationMessageListThemeBackground, AXConversationMessagePayload, AXConversationMessageRenderer, AXConversationMessageRendererCapabilities, AXConversationMessageRendererComponent, AXConversationMessageRendererContentState, AXConversationMessageRendererState, AXConversationMessageSearchFilters, AXConversationMessageStatus, AXConversationMessageType, AXConversationMetadata, AXConversationOptions, AXConversationOutletSkeleton, AXConversationPaginatedResult, AXConversationPagination, AXConversationPaginationState, AXConversationParticipant, AXConversationParticipantRole, AXConversationParticipantUpdate, AXConversationPinnedMessage, AXConversationPlaybackBannerInputs, AXConversationPollOption, AXConversationPollPayload, AXConversationPresenceStatus, AXConversationPresenceUpdate, AXConversationReaction, AXConversationReadReceipt, AXConversationRegistryComponentRef, AXConversationRegistryConfiguration, AXConversationRegistryItem, AXConversationRoomPreferences, AXConversationRoomPreferencesMap, AXConversationSendMessageCommand, AXConversationSendMessageOptions, AXConversationSendMessageUploadSource, AXConversationSettingsUpdate, AXConversationSidebarTabsOrientation, AXConversationSort, AXConversationStickerPayload, AXConversationSystemPayload, AXConversationTab, AXConversationTextFormat, AXConversationTextPayload, AXConversationType, AXConversationTypingIndicator, AXConversationUpdateData, AXConversationUploadOptions, AXConversationUploaderFilePreview, AXConversationUploaderReference, AXConversationUploaderResult, AXConversationUser, AXConversationUserAvatarComponent, AXConversationUserPresence, AXConversationUserProfile, AXConversationUserProfileUpdate, AXConversationUserSearchFilters, AXConversationValidationResult, AXConversationVideoMediaItem, AXConversationVideoPayload, AXConversationVoicePayload };