@acorex/components 22.0.0-next.8 → 22.0.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 (120) hide show
  1. package/combo-box/README.md +35 -0
  2. package/fesm2022/acorex-components-accordion.mjs +2 -2
  3. package/fesm2022/acorex-components-accordion.mjs.map +1 -1
  4. package/fesm2022/acorex-components-action-sheet.mjs +1 -0
  5. package/fesm2022/acorex-components-action-sheet.mjs.map +1 -1
  6. package/fesm2022/acorex-components-alert.mjs +2 -2
  7. package/fesm2022/acorex-components-alert.mjs.map +1 -1
  8. package/fesm2022/acorex-components-button.mjs +4 -4
  9. package/fesm2022/acorex-components-button.mjs.map +1 -1
  10. package/fesm2022/acorex-components-calendar.mjs +10 -12
  11. package/fesm2022/acorex-components-calendar.mjs.map +1 -1
  12. package/fesm2022/acorex-components-check-box.mjs +2 -2
  13. package/fesm2022/acorex-components-check-box.mjs.map +1 -1
  14. package/fesm2022/acorex-components-combo-box.mjs +783 -0
  15. package/fesm2022/acorex-components-combo-box.mjs.map +1 -0
  16. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs +50 -0
  17. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs.map +1 -0
  18. package/fesm2022/{acorex-components-conversation-open-composer-picker-for-files-Hh5Oyp3p.mjs → acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs} +7 -20
  19. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs.map +1 -0
  20. package/fesm2022/acorex-components-conversation.mjs +9946 -17396
  21. package/fesm2022/acorex-components-conversation.mjs.map +1 -1
  22. package/fesm2022/acorex-components-data-table.mjs +188 -64
  23. package/fesm2022/acorex-components-data-table.mjs.map +1 -1
  24. package/fesm2022/acorex-components-datetime-box.mjs +14 -16
  25. package/fesm2022/acorex-components-datetime-box.mjs.map +1 -1
  26. package/fesm2022/acorex-components-datetime-input.mjs +61 -32
  27. package/fesm2022/acorex-components-datetime-input.mjs.map +1 -1
  28. package/fesm2022/acorex-components-decorators.mjs +21 -5
  29. package/fesm2022/acorex-components-decorators.mjs.map +1 -1
  30. package/fesm2022/acorex-components-dialog.mjs +7 -4
  31. package/fesm2022/acorex-components-dialog.mjs.map +1 -1
  32. package/fesm2022/acorex-components-drawer.mjs +2 -2
  33. package/fesm2022/acorex-components-drawer.mjs.map +1 -1
  34. package/fesm2022/acorex-components-dropdown.mjs +4 -4
  35. package/fesm2022/acorex-components-dropdown.mjs.map +1 -1
  36. package/fesm2022/acorex-components-fab.mjs +5 -5
  37. package/fesm2022/acorex-components-fab.mjs.map +1 -1
  38. package/fesm2022/acorex-components-file-viewer.mjs +38 -78
  39. package/fesm2022/acorex-components-file-viewer.mjs.map +1 -1
  40. package/fesm2022/acorex-components-form.mjs +21 -5
  41. package/fesm2022/acorex-components-form.mjs.map +1 -1
  42. package/fesm2022/acorex-components-grid-layout-builder.mjs +238 -36
  43. package/fesm2022/acorex-components-grid-layout-builder.mjs.map +1 -1
  44. package/fesm2022/acorex-components-label.mjs +2 -2
  45. package/fesm2022/acorex-components-label.mjs.map +1 -1
  46. package/fesm2022/acorex-components-list.mjs +2 -2
  47. package/fesm2022/acorex-components-list.mjs.map +1 -1
  48. package/fesm2022/acorex-components-loading-dialog.mjs +59 -42
  49. package/fesm2022/acorex-components-loading-dialog.mjs.map +1 -1
  50. package/fesm2022/acorex-components-lookup.mjs +2897 -0
  51. package/fesm2022/acorex-components-lookup.mjs.map +1 -0
  52. package/fesm2022/acorex-components-map.mjs +2 -2
  53. package/fesm2022/acorex-components-map.mjs.map +1 -1
  54. package/fesm2022/acorex-components-menu.mjs +238 -75
  55. package/fesm2022/acorex-components-menu.mjs.map +1 -1
  56. package/fesm2022/acorex-components-notification.mjs +13 -6
  57. package/fesm2022/acorex-components-notification.mjs.map +1 -1
  58. package/fesm2022/acorex-components-number-box.mjs +30 -29
  59. package/fesm2022/acorex-components-number-box.mjs.map +1 -1
  60. package/fesm2022/acorex-components-password-box.mjs +3 -3
  61. package/fesm2022/acorex-components-password-box.mjs.map +1 -1
  62. package/fesm2022/acorex-components-popover.mjs +29 -6
  63. package/fesm2022/acorex-components-popover.mjs.map +1 -1
  64. package/fesm2022/acorex-components-popup.mjs +4 -2
  65. package/fesm2022/acorex-components-popup.mjs.map +1 -1
  66. package/fesm2022/acorex-components-radio.mjs +2 -2
  67. package/fesm2022/acorex-components-radio.mjs.map +1 -1
  68. package/fesm2022/acorex-components-range-slider.mjs +2 -2
  69. package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
  70. package/fesm2022/acorex-components-scheduler.mjs +12 -22
  71. package/fesm2022/acorex-components-scheduler.mjs.map +1 -1
  72. package/fesm2022/acorex-components-select-box.mjs +55 -18
  73. package/fesm2022/acorex-components-select-box.mjs.map +1 -1
  74. package/fesm2022/acorex-components-selection-list.mjs +2 -2
  75. package/fesm2022/acorex-components-selection-list.mjs.map +1 -1
  76. package/fesm2022/acorex-components-switch.mjs +2 -2
  77. package/fesm2022/acorex-components-switch.mjs.map +1 -1
  78. package/fesm2022/acorex-components-tabs.mjs +2 -2
  79. package/fesm2022/acorex-components-tabs.mjs.map +1 -1
  80. package/fesm2022/acorex-components-tag-box.mjs +2 -2
  81. package/fesm2022/acorex-components-tag-box.mjs.map +1 -1
  82. package/fesm2022/acorex-components-text-area.mjs +2 -2
  83. package/fesm2022/acorex-components-text-area.mjs.map +1 -1
  84. package/fesm2022/acorex-components-toast.mjs +9 -2
  85. package/fesm2022/acorex-components-toast.mjs.map +1 -1
  86. package/fesm2022/acorex-components-tooltip.mjs +2 -2
  87. package/fesm2022/acorex-components-tooltip.mjs.map +1 -1
  88. package/fesm2022/acorex-components-tree-view.mjs +40 -3
  89. package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
  90. package/lookup/README.md +74 -0
  91. package/package.json +12 -7
  92. package/select-box/README.md +5 -0
  93. package/types/acorex-components-action-sheet.d.ts +9 -1
  94. package/types/acorex-components-combo-box.d.ts +280 -0
  95. package/types/acorex-components-conversation.d.ts +947 -1354
  96. package/types/acorex-components-data-table.d.ts +47 -5
  97. package/types/acorex-components-datetime-box.d.ts +2 -0
  98. package/types/acorex-components-datetime-input.d.ts +24 -5
  99. package/types/acorex-components-decorators.d.ts +1 -0
  100. package/types/acorex-components-dialog.d.ts +9 -0
  101. package/types/acorex-components-file-viewer.d.ts +15 -52
  102. package/types/acorex-components-grid-layout-builder.d.ts +34 -2
  103. package/types/acorex-components-loading-dialog.d.ts +12 -4
  104. package/types/acorex-components-lookup.d.ts +831 -0
  105. package/types/acorex-components-menu.d.ts +28 -4
  106. package/types/acorex-components-notification.d.ts +11 -1
  107. package/types/acorex-components-number-box.d.ts +3 -1
  108. package/types/acorex-components-popover.d.ts +10 -1
  109. package/types/acorex-components-popup.d.ts +9 -1
  110. package/types/acorex-components-scheduler.d.ts +2 -4
  111. package/types/acorex-components-select-box.d.ts +21 -4
  112. package/types/acorex-components-toast.d.ts +10 -1
  113. package/types/acorex-components-tree-view.d.ts +9 -1
  114. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-CNHiM1Sp.mjs +0 -106
  115. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-CNHiM1Sp.mjs.map +0 -1
  116. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-Hh5Oyp3p.mjs.map +0 -1
  117. package/fesm2022/acorex-components-selection-list-2.mjs +0 -168
  118. package/fesm2022/acorex-components-selection-list-2.mjs.map +0 -1
  119. package/selection-list-2/README.md +0 -3
  120. package/types/acorex-components-selection-list-2.d.ts +0 -52
@@ -1,18 +1,21 @@
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, AXDataSource, AXPlacement, AXClosableComponent } from '@acorex/cdk/common';
3
+ import { OnDestroy, ViewContainerRef, Type, InputSignal, WritableSignal, Signal, Provider, OnInit, EventEmitter, TemplateRef, ElementRef, InjectionToken, ModuleWithProviders } from '@angular/core';
4
+ import { AXComponentCloseEvent, AXHtmlEvent, AXClickEvent, AXDataSource, AXPlacement } from '@acorex/cdk/common';
5
+ import * as _acorex_components_action_sheet from '@acorex/components/action-sheet';
6
+ import { AXActionSheetRef } from '@acorex/components/action-sheet';
5
7
  import * as _acorex_components_popup from '@acorex/components/popup';
6
8
  import { AXPopupService, AXPopupRef } from '@acorex/components/popup';
7
9
  import { AXFileUploadOptions, AXUploadResult, AXUploadReference, AXUploaderService, AXUploaderFileChangeEvent } from '@acorex/cdk/uploader';
8
10
  import { AXListComponent } from '@acorex/components/list';
9
11
  import * as rxjs from 'rxjs';
10
- import { Observable, BehaviorSubject, Subject } from 'rxjs';
12
+ import { Observable } from 'rxjs';
11
13
  import { AXDialogService } from '@acorex/components/dialog';
12
14
  import { AXContextMenuOpeningEvent, AXContextMenuItemsClickEvent } from '@acorex/components/menu';
15
+ import { AXTabLocation } from '@acorex/components/tabs';
13
16
  import { AXBasePageComponent } from '@acorex/components/page';
14
17
  import * as _acorex_core_file from '@acorex/core/file';
15
- import { AXFileTypeInfoProvider, AXFileType, AXFileService, AXFileTypeRegistryService, AXFileTypeExtensionHint, AXFileTypeOpenContext } from '@acorex/core/file';
18
+ import { AXFileTypeInfoProvider, AXFileType, AXFileTypeRegistryService, AXFileService, AXFileTypeExtensionHint, AXFileTypeOpenContext } from '@acorex/core/file';
16
19
  import { AXTranslationService } from '@acorex/core/translation';
17
20
  import { AXToastService } from '@acorex/components/toast';
18
21
  import { AXValidationRuleResult } from '@acorex/core/validation';
@@ -26,6 +29,7 @@ declare class AXConversationComposerPopupComponent implements OnDestroy {
26
29
  private get registry();
27
30
  contentContainer: _angular_core.Signal<ViewContainerRef>;
28
31
  private currentComponentRef;
32
+ private tabItemSelectedSubscription;
29
33
  /** Popup open state (for backward compatibility) */
30
34
  readonly isOpen: _angular_core.InputSignal<boolean>;
31
35
  /** Close event (for backward compatibility) */
@@ -37,9 +41,11 @@ declare class AXConversationComposerPopupComponent implements OnDestroy {
37
41
  /** Close event for popup service */
38
42
  readonly onClosed: _angular_core.OutputEmitterRef<AXComponentCloseEvent>;
39
43
  /** Active tab ID */
40
- private readonly activeTabId;
44
+ readonly activeTabId: _angular_core.WritableSignal<string>;
41
45
  /** Enabled tabs from registry */
42
46
  readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerTab[]>;
47
+ /** Whether more than one tab is available */
48
+ readonly hasMultipleTabs: _angular_core.Signal<boolean>;
43
49
  getTabTitle(tabId: string): string;
44
50
  constructor();
45
51
  /** Handle tab change */
@@ -50,6 +56,7 @@ declare class AXConversationComposerPopupComponent implements OnDestroy {
50
56
  }): void;
51
57
  /** Load tab content component */
52
58
  private loadTabContent;
59
+ private clearTabContent;
53
60
  ngOnDestroy(): void;
54
61
  /** Close popup (for backward compatibility) */
55
62
  close(): void;
@@ -284,6 +291,16 @@ interface AXConversationMessage {
284
291
  };
285
292
  /** Message reactions */
286
293
  reactions: AXConversationReaction[];
294
+ /**
295
+ * Total reply count when provided by the message API (`getMessages` or realtime).
296
+ * When omitted, the UI derives a minimum from loaded messages in the active conversation.
297
+ */
298
+ replyCount?: number;
299
+ /**
300
+ * Total forward count when provided by the message API (`getMessages` or realtime).
301
+ * When omitted, the UI derives a minimum from loaded messages in the active conversation.
302
+ */
303
+ forwardCount?: number;
287
304
  /** Whether message is pinned */
288
305
  pinned?: boolean;
289
306
  /** Edit timestamp (if edited) */
@@ -363,12 +380,31 @@ interface AXConversationDeleteMessageCommand {
363
380
  forEveryone?: boolean;
364
381
  }
365
382
 
383
+ /**
384
+ * Per-user preferences for a specific conversation (mute, notifications, etc.).
385
+ * Stored on the user account, keyed by conversation ID — not on the room entity.
386
+ */
387
+ interface AXConversationRoomPreferences {
388
+ /** Muted until timestamp */
389
+ mutedUntil?: Date;
390
+ /** Show notifications for this conversation */
391
+ notifications: boolean;
392
+ /** Custom notification sound */
393
+ notificationSound?: string;
394
+ /** Show message preview in notifications */
395
+ showPreview: boolean;
396
+ /** Custom settings */
397
+ custom?: Record<string, unknown>;
398
+ }
399
+ declare const AX_CONVERSATION_DEFAULT_ROOM_PREFERENCES: AXConversationRoomPreferences;
400
+ /** Map of conversation ID → user-specific room preferences. */
401
+ type AXConversationRoomPreferencesMap = Record<string, AXConversationRoomPreferences>;
402
+
366
403
  /**
367
404
  * Participant Model
368
- * Represents a user/member in a conversation
405
+ * Membership in a conversation (identity fields are snapshots; live presence is on the user store).
369
406
  */
370
- type AXConversationParticipantRole = 'admin' | 'moderator' | 'member';
371
- type AXConversationParticipantStatus = 'online' | 'offline' | 'away';
407
+ type AXConversationParticipantRole = 'owner' | 'admin' | 'moderator' | 'member' | 'guest';
372
408
  /** Extended profile fields shown in private-chat info panels. */
373
409
  interface AXConversationUserProfile {
374
410
  bio?: string;
@@ -379,6 +415,18 @@ interface AXConversationUserProfile {
379
415
  company?: string;
380
416
  title?: string;
381
417
  }
418
+ /** Authenticated user profile (includes per-room preferences). */
419
+ interface AXConversationUser {
420
+ id: string;
421
+ name: string;
422
+ description?: string;
423
+ profile?: AXConversationUserProfile;
424
+ avatar?: string;
425
+ icon?: string;
426
+ metadata?: Record<string, unknown>;
427
+ /** User-specific settings per conversation (key = conversationId). */
428
+ conversationPreferences?: AXConversationRoomPreferencesMap;
429
+ }
382
430
  interface AXConversationParticipant {
383
431
  /** Unique identifier for the participant */
384
432
  id: string;
@@ -399,10 +447,6 @@ interface AXConversationParticipant {
399
447
  icon?: string;
400
448
  /** Role in the conversation (for groups/channels) */
401
449
  role?: AXConversationParticipantRole;
402
- /** Current online status */
403
- status?: AXConversationParticipantStatus;
404
- /** Last seen timestamp (when offline/away) */
405
- lastSeen?: Date;
406
450
  /** Custom metadata */
407
451
  metadata?: Record<string, unknown>;
408
452
  }
@@ -413,43 +457,27 @@ interface AXConversationParticipant {
413
457
  */
414
458
 
415
459
  type AXConversationType = 'private' | 'group' | 'channel' | 'bot';
416
- /**
417
- * Conversation status information
418
- */
419
- interface AXConversationStatus {
420
- /** Whether someone is typing */
421
- isTyping: boolean;
422
- /** User IDs currently typing */
423
- typingUsers: string[];
424
- /** Online presence (for private chats) */
425
- presence?: 'online' | 'offline' | 'away';
426
- /** Last seen timestamp (for private chats when offline) */
427
- lastSeen?: Date;
428
- }
429
- /**
430
- * Conversation settings
431
- */
432
- interface AXConversationSettings {
433
- /** Muted until timestamp */
434
- mutedUntil?: Date;
435
- /** Show notifications */
436
- notifications: boolean;
437
- /** Custom notification sound */
438
- notificationSound?: string;
439
- /** Show message preview in notifications */
440
- showPreview: boolean;
441
- /** Custom settings */
442
- custom?: Record<string, unknown>;
460
+ /** Theme-specific CSS `background` values for the message list area. */
461
+ interface AXConversationMessageListThemeBackground {
462
+ light: string;
463
+ dark: string;
443
464
  }
465
+ /** Single CSS value (both themes) or per-theme `{ light, dark }` backgrounds. */
466
+ type AXConversationMessageListBackground = string | AXConversationMessageListThemeBackground;
444
467
  /**
445
468
  * Conversation metadata
446
469
  * Extensible map for app-specific conversation data.
447
470
  */
448
471
  interface AXConversationMetadata extends Record<string, unknown> {
449
- /** Optional custom background CSS for message list */
450
- messageListBackground?: string;
472
+ /** Optional custom background CSS for message list (per light/dark theme). */
473
+ messageListBackground?: AXConversationMessageListBackground;
451
474
  /** Optional custom empty-state component for the message list. */
452
475
  messageListEmptyComponent?: Type<AXConversationMessageListEmptyComponent>;
476
+ /**
477
+ * When `false`, hides reaction UI (add button, bubbles, picker) for this conversation.
478
+ * Defaults to `true` when omitted.
479
+ */
480
+ reactionsEnabled?: boolean;
453
481
  }
454
482
  /** Contract for custom empty-state components rendered by message list. */
455
483
  interface AXConversationMessageListEmptyComponent {
@@ -486,10 +514,6 @@ interface AXConversation {
486
514
  unreadCount: number;
487
515
  /** Number of unread mentions */
488
516
  unreadMentions?: number;
489
- /** Current status (typing, presence, etc.) */
490
- status: AXConversationStatus;
491
- /** User-specific settings */
492
- settings: AXConversationSettings;
493
517
  /** Pinned messages IDs */
494
518
  pinnedMessageIds?: string[];
495
519
  /** Conversation creation timestamp */
@@ -502,13 +526,11 @@ interface AXConversation {
502
526
  pinned?: boolean;
503
527
  /** Whether conversation is archived */
504
528
  archived?: boolean;
505
- /** Draft message text */
506
- draft?: string;
507
529
  /** Custom metadata */
508
530
  metadata?: AXConversationMetadata;
509
531
  }
510
532
  /**
511
- * Typing indicator
533
+ * Typing indicator (realtime event — ephemeral, not stored on the room entity).
512
534
  */
513
535
  interface AXConversationTypingIndicator {
514
536
  /** Conversation ID */
@@ -519,19 +541,8 @@ interface AXConversationTypingIndicator {
519
541
  userName?: string;
520
542
  /** Timestamp */
521
543
  timestamp: Date;
522
- }
523
- /**
524
- * Presence update
525
- */
526
- interface AXConversationPresenceUpdate {
527
- /** User ID */
528
- userId: string;
529
- /** Presence status */
530
- status: 'online' | 'offline' | 'away';
531
- /** Last seen timestamp */
532
- lastSeen?: Date;
533
- /** Custom status text */
534
- statusText?: string;
544
+ /** When false, user stopped typing */
545
+ isTyping?: boolean;
535
546
  }
536
547
  /**
537
548
  * Conversation filter options
@@ -571,6 +582,26 @@ declare const AX_CONVERSATION_MESSAGE_TYPE_FILE_TYPE: Partial<Record<AXConversat
571
582
  /** Resolves {@link AXConversationMessage.fileType} from command or message type. */
572
583
  declare function resolveConversationMessageFileType(type: AXConversationMessageType, fileType?: string): string | undefined;
573
584
 
585
+ /**
586
+ * User presence — global per-user live state (not room-scoped).
587
+ */
588
+ type AXConversationPresenceStatus = 'online' | 'offline' | 'away' | 'busy';
589
+ /** Live presence for a single user. */
590
+ interface AXConversationUserPresence {
591
+ userId: string;
592
+ status: AXConversationPresenceStatus;
593
+ lastSeen?: Date;
594
+ statusText?: string;
595
+ updatedAt?: Date;
596
+ }
597
+ /** Realtime / API presence event payload. */
598
+ interface AXConversationPresenceUpdate {
599
+ userId: string;
600
+ status: AXConversationPresenceStatus;
601
+ lastSeen?: Date;
602
+ statusText?: string;
603
+ }
604
+
574
605
  /**
575
606
  * Abstract Base Registry
576
607
  * Base class for all registries with common functionality
@@ -649,22 +680,17 @@ declare abstract class AXConversationBaseRegistry<T extends AXConversationRegist
649
680
  protected abstract getRegistryName(): string;
650
681
  }
651
682
 
652
- /**
653
- * Active component state in composer
654
- */
655
- interface AXConversationComposerActiveComponent {
656
- /** Action that triggered this component */
657
- action: AXConversationComposerAction;
658
- /** Component to render */
659
- component?: Type<unknown>;
660
- /** Lazy loader for the component */
661
- componentLoader?: () => Promise<Type<unknown>>;
662
- /** Component inputs */
663
- inputs?: Record<string, unknown>;
664
- }
683
+ /** Primary composer button mode (send / cancel / stopping / default action / locked). */
684
+ type AXConversationComposerPrimaryButtonMode = 'send' | 'cancel' | 'stopping' | 'default-action' | 'locked';
665
685
  declare class AXConversationComposerService {
666
686
  private readonly conversationService;
687
+ private readonly generationState;
667
688
  private readonly translation;
689
+ private readonly popupService;
690
+ private readonly actionSheetService;
691
+ private readonly platform;
692
+ private readonly config;
693
+ private readonly _activeActionOverlay;
668
694
  private get registry();
669
695
  private readonly _replyMessage;
670
696
  private readonly _editMessage;
@@ -672,15 +698,10 @@ declare class AXConversationComposerService {
672
698
  readonly editMessage: _angular_core.Signal<AXConversationMessage>;
673
699
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
674
700
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
675
- /** Active component being shown in composer (full-width mode) */
676
- private readonly _activeComponent;
677
- readonly activeComponent: _angular_core.Signal<AXConversationComposerActiveComponent>;
678
701
  /** Draft text */
679
702
  readonly draftText: _angular_core.WritableSignal<string>;
680
703
  /** Attachments */
681
704
  readonly attachments: _angular_core.WritableSignal<File[]>;
682
- /** Show typing indicator */
683
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
684
705
  /** Incremented to request focus on the composer text area (handled by AXConversationComposerComponent). */
685
706
  private readonly _focusRequest;
686
707
  readonly focusRequest: _angular_core.Signal<number>;
@@ -688,22 +709,31 @@ declare class AXConversationComposerService {
688
709
  readonly placeholder: _angular_core.Signal<string>;
689
710
  /** Number of input rows */
690
711
  readonly inputRows: _angular_core.Signal<number>;
691
- /** Can send message */
712
+ /** Can send message (draft has content; does not include generation state). */
692
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>;
693
720
  /** Composer action context */
694
721
  readonly actionContext: _angular_core.Signal<AXConversationComposerActionContext>;
695
- /** Left actions from registry */
696
- readonly leftActions: _angular_core.Signal<AXConversationComposerAction[]>;
697
- /** Right actions from registry */
698
- readonly rightActions: _angular_core.Signal<AXConversationComposerAction[]>;
699
- /** Left inline actions (location = 'inline' or undefined) */
700
- readonly leftInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
701
- /** Left menu actions (location = 'menu') */
702
- readonly leftMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
703
- /** Right inline actions (location = 'inline' or undefined) */
704
- readonly rightInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
705
- /** Right menu actions (location = 'menu') */
706
- readonly rightMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
722
+ /** Start actions from registry */
723
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
724
+ /** End actions from registry */
725
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
726
+ /** Start inline actions (location = 'inline' or undefined) */
727
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
728
+ /** Start menu actions shown in the attachment popup */
729
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
730
+ /** End inline actions inside the input pill (excludes default action) */
731
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
732
+ /** End menu actions (location = 'menu') */
733
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
734
+ /** Default end action (voice/send morph button) */
735
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
736
+ cancelGeneration(): void;
707
737
  startReply(message: AXConversationMessage): void;
708
738
  startEdit(message: AXConversationMessage): void;
709
739
  /** Focus the composer text area when the composer component is mounted. */
@@ -720,21 +750,20 @@ declare class AXConversationComposerService {
720
750
  */
721
751
  clearComposerInput(conversationId?: string): void;
722
752
  /**
723
- * Show a component in the composer (full-width mode)
753
+ * Open a composer action component in a popup (desktop) or action sheet (mobile).
724
754
  */
725
- 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>;
726
759
  /**
727
- * Hide the active component
760
+ * Hide the active action overlay.
728
761
  */
729
762
  hideComponent(): void;
730
- /**
731
- * Toggle component visibility
732
- */
733
- toggleComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>): void;
734
763
  /**
735
764
  * Get actions for the active conversation
736
765
  */
737
- getActionsForPosition(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
766
+ getActionsForPosition(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
738
767
  /**
739
768
  * Execute an action
740
769
  */
@@ -771,6 +800,10 @@ interface AXConversationComposerActionContext {
771
800
  isReplying: boolean;
772
801
  /** Message being replied to (if any) */
773
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;
774
807
  /** Custom context data */
775
808
  custom?: Record<string, unknown>;
776
809
  }
@@ -787,6 +820,15 @@ interface AXConversationComposerActionComponent {
787
820
  readonly initialFiles?: InputSignal<File[]>;
788
821
  /** Set by {@link AXPopupService} when the picker is shown in a popup. */
789
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>;
790
832
  /** Cancel in-flight uploads when the picker is closed or replaced. */
791
833
  abortInProgressUploads?(): void;
792
834
  }
@@ -798,10 +840,15 @@ interface AXConversationComposerAction extends Omit<AXConversationRegistryItem,
798
840
  label: string;
799
841
  /** Icon name/class */
800
842
  icon: string;
801
- /** Position: left or right */
802
- position: 'left' | 'right';
803
- /** Location: inline (show as button) or menu (show in dropdown menu) */
843
+ /** Position: start or end of the composer */
844
+ position: 'start' | 'end';
845
+ /** Location: inline (show as button) or menu (show in attachment popup menu) */
804
846
  location?: 'inline' | 'menu';
847
+ /**
848
+ * Primary end action (e.g. voice record). Only one action may be default.
849
+ * Renders as the circular send-style button and morphs into send when the draft has content.
850
+ */
851
+ default?: boolean;
805
852
  /** Visibility condition */
806
853
  visible: (context: AXConversationComposerActionContext) => boolean;
807
854
  /** Enabled condition */
@@ -817,6 +864,11 @@ interface AXConversationComposerAction extends Omit<AXConversationRegistryItem,
817
864
  * Whether this action is toggleable (shows/hides component)
818
865
  */
819
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;
820
872
  /** Action handler (optional if component is provided) */
821
873
  handler?: (context: AXConversationComposerActionContext) => void | Promise<void>;
822
874
  /** Tooltip text */
@@ -841,26 +893,30 @@ declare class AXConversationComposerActionRegistry {
841
893
  private readonly _actions;
842
894
  private readonly translation;
843
895
  private readonly injector;
844
- private readonly fileTypeRegistry;
896
+ private readonly composerTabRegistry;
845
897
  constructor();
846
898
  /** All registered actions */
847
899
  readonly actions: _angular_core.Signal<AXConversationComposerAction[]>;
848
- /** Left-side actions sorted by priority */
849
- readonly leftActions: _angular_core.Signal<AXConversationComposerAction[]>;
850
- /** Right-side actions sorted by priority */
851
- readonly rightActions: _angular_core.Signal<AXConversationComposerAction[]>;
852
- /** Left-side inline actions (location = 'inline' or undefined) */
853
- readonly leftInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
854
- /** Left-side menu actions (location = 'menu') */
855
- readonly leftMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
856
- /** Right-side inline actions (location = 'inline' or undefined) */
857
- readonly rightInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
858
- /** Right-side menu actions (location = 'menu') */
859
- readonly rightMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
900
+ /** Start-side actions sorted by priority */
901
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
902
+ /** End-side actions sorted by priority */
903
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
904
+ /** Start-side inline actions (location = 'inline' or undefined) */
905
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
906
+ /** Start-side menu actions (location = 'menu') — shown in the attachment popup */
907
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
908
+ /** End-side inline actions inside the input pill (excludes default action) */
909
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
910
+ /** End-side menu actions (location = 'menu') */
911
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
912
+ /** The single default end action (voice/send morph button) */
913
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
860
914
  /**
861
915
  * Register a composer action
862
916
  */
863
917
  register(action: AXConversationComposerAction): void;
918
+ /** Resolved lazily to avoid a DI cycle with {@link AXConversationComposerFileTypesProvider}. */
919
+ private fileTypeRegistry;
864
920
  private ensureFileTypeExists;
865
921
  /**
866
922
  * Unregister a composer action
@@ -869,11 +925,11 @@ declare class AXConversationComposerActionRegistry {
869
925
  /**
870
926
  * Get visible actions for a position
871
927
  */
872
- getVisibleActions(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
928
+ getVisibleActions(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
873
929
  /**
874
930
  * Get enabled actions for a position
875
931
  */
876
- getEnabledActions(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
932
+ getEnabledActions(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
877
933
  isActionEnabled(action: AXConversationComposerAction, context: AXConversationComposerActionContext): boolean;
878
934
  /**
879
935
  * Picker actions for a file catalog (by priority), when visible and enabled.
@@ -935,6 +991,8 @@ declare class AXConversationComposerTabRegistry {
935
991
  readonly tabs: _angular_core.Signal<AXConversationComposerTab[]>;
936
992
  /** Enabled tabs sorted by priority */
937
993
  readonly enabledTabs: _angular_core.Signal<AXConversationComposerTab[]>;
994
+ /** Whether the composer popup has any tabs to show. */
995
+ readonly hasEnabledTabs: _angular_core.Signal<boolean>;
938
996
  /**
939
997
  * Register a composer tab
940
998
  */
@@ -1200,6 +1258,7 @@ declare class AXConversationMessageRendererRegistry {
1200
1258
  private readonly _composerActions;
1201
1259
  constructor();
1202
1260
  private registerBuiltInRenderers;
1261
+ private registerBuiltInRendererIfMissing;
1203
1262
  /** All registered renderers */
1204
1263
  readonly renderers: Signal<AXConversationMessageRenderer[]>;
1205
1264
  /** Renderers sorted by priority (highest first) */
@@ -1289,10 +1348,6 @@ declare class AXConversationInfoBarService {
1289
1348
  * Reset info-bar overlays when the active conversation changes.
1290
1349
  */
1291
1350
  onConversationChanged(): void;
1292
- /**
1293
- * Open the Telegram-style conversation info panel for the active (or given) conversation.
1294
- */
1295
- openConversationInfoPanel(conversation?: AXConversation): Promise<void>;
1296
1351
  /**
1297
1352
  * Get actions for the active conversation
1298
1353
  */
@@ -1396,7 +1451,7 @@ interface AXConversationInfoBarAction extends AXConversationRegistryItem {
1396
1451
  /** Whether this is a divider */
1397
1452
  divider?: boolean;
1398
1453
  /** Display location: 'inline' for toolbar buttons, 'menu' for dropdown menu */
1399
- location?: 'inline' | 'menu';
1454
+ location?: 'inline' | 'menu' | ((context: AXConversationInfoBarActionContext) => 'inline' | 'menu');
1400
1455
  /**
1401
1456
  * Component to show when action is activated (for inline actions)
1402
1457
  * If provided, clicking the action will show this component in the info-bar
@@ -1446,6 +1501,10 @@ declare class AXConversationInfoBarActionRegistry extends AXConversationBaseRegi
1446
1501
  * Get actions for a specific conversation
1447
1502
  */
1448
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;
1449
1508
  /**
1450
1509
  * Get inline actions (toolbar buttons)
1451
1510
  */
@@ -1563,14 +1622,13 @@ declare class AXConversationMessageActionRegistry {
1563
1622
  }
1564
1623
 
1565
1624
  declare class AXConversationComposerComponent implements OnDestroy {
1566
- #private;
1567
1625
  private readonly conversationService;
1568
1626
  private readonly composerService;
1569
1627
  private readonly messageListService;
1570
1628
  private readonly config;
1571
1629
  private readonly translation;
1572
1630
  /** Access registry through conversation service */
1573
- private get registry();
1631
+ protected get composerActionRegistry(): _acorex_components_conversation.AXConversationComposerActionRegistry;
1574
1632
  /** Composer text area reference */
1575
1633
  private readonly textAreaRef;
1576
1634
  /** Draft text - use service */
@@ -1581,10 +1639,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1581
1639
  readonly editingMessage: _angular_core.WritableSignal<any>;
1582
1640
  /** Replying to message */
1583
1641
  readonly replyingToMessage: _angular_core.WritableSignal<AXConversationMessage>;
1584
- /** Show typing indicator - use service */
1585
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
1586
1642
  /** Message sent event */
1587
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>;
1588
1646
  /** Emoji clicked event */
1589
1647
  readonly emojiClick: _angular_core.OutputEmitterRef<void>;
1590
1648
  /** Attach clicked event */
@@ -1594,46 +1652,53 @@ declare class AXConversationComposerComponent implements OnDestroy {
1594
1652
  /** Active conversation */
1595
1653
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
1596
1654
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
1597
- /** Active component from service */
1598
- readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerActiveComponent>;
1599
1655
  /** Emoji popover state */
1600
1656
  private readonly emojiPopoverRef;
1601
1657
  readonly emojiPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1658
+ /** Attachment menu popover state */
1659
+ private readonly attachPopoverRef;
1660
+ private readonly attachMenuButtonRef;
1661
+ readonly attachMenuTarget: _angular_core.Signal<HTMLElement>;
1662
+ private attachMenuCloseTimer?;
1602
1663
  readonly composerPopupLoader: () => Promise<typeof _acorex_components_conversation.AXConversationComposerPopupComponent>;
1603
1664
  /** Input placeholder - use service */
1604
1665
  readonly placeholder: _angular_core.Signal<string>;
1605
- /** Typing indicator subject for rate limiting */
1606
- private readonly typingSubject;
1607
1666
  constructor();
1608
1667
  private draftSaveTimeout?;
1609
1668
  /** Number of input rows - use service */
1610
1669
  readonly inputRows: _angular_core.Signal<number>;
1611
1670
  /** Can send message - use service */
1612
1671
  readonly canSend: _angular_core.Signal<boolean>;
1613
- /** Left actions from registry - use service */
1614
- readonly leftActions: _angular_core.Signal<AXConversationComposerAction[]>;
1615
- /** Right actions from registry - use service */
1616
- readonly rightActions: _angular_core.Signal<AXConversationComposerAction[]>;
1617
- /** Left inline actions (location = 'inline' or undefined) */
1618
- readonly leftInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1619
- /** Left menu actions (location = 'menu') */
1620
- readonly leftMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1621
- /** Right inline actions (location = 'inline' or undefined) */
1622
- readonly rightInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1623
- /** Right menu actions (location = 'menu') */
1624
- readonly rightMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1625
- /** Handle key down */
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>;
1678
+ /** Start actions from registry - use service */
1679
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
1680
+ /** End actions from registry - use service */
1681
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
1682
+ /** Start inline actions */
1683
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1684
+ /** Start menu actions (attachment popup) */
1685
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1686
+ /** End inline actions inside input pill */
1687
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1688
+ /** End menu actions */
1689
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1690
+ /** Default end action (voice/send morph) */
1691
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
1692
+ /** Handle key down (send on Enter; typing is driven by draft changes only). */
1626
1693
  onKeyDown(event: AXHtmlEvent<KeyboardEvent>): void;
1627
- /** Handle input */
1628
- onInput(): void;
1629
- /** Send typing indicator (throttled via RxJS) */
1630
- private sendTypingIndicator;
1694
+ /** Handle draft text changes — throttled typing indicator via conversation service. */
1695
+ onDraftChanged(): void;
1631
1696
  /** Cleanup on destroy */
1632
1697
  ngOnDestroy(): void;
1633
1698
  /** Handle send click */
1634
1699
  onSendClick(): Promise<void>;
1635
1700
  /** Handle emoji click */
1636
- onEmojiClick(event?: MouseEvent): Promise<void>;
1701
+ onEmojiClick(event?: AXClickEvent | MouseEvent): Promise<void>;
1637
1702
  /** Handle emoji popover closed */
1638
1703
  onEmojiPopoverClosed(): void;
1639
1704
  /** Handle emoji/sticker selection from popup */
@@ -1642,8 +1707,26 @@ declare class AXConversationComposerComponent implements OnDestroy {
1642
1707
  private sendSticker;
1643
1708
  /** Get inputs for emoji popup component */
1644
1709
  getEmojiPopupInputs(): Record<string, unknown>;
1645
- /** Handle attach click */
1646
- onAttachClick(): void;
1710
+ /** Handle attach menu hover */
1711
+ onAttachMenuMouseEnter(): void;
1712
+ onAttachMenuMouseLeave(): void;
1713
+ onAttachMenuPanelMouseEnter(): void;
1714
+ onAttachMenuPanelMouseLeave(): void;
1715
+ private scheduleAttachMenuClose;
1716
+ private clearAttachMenuCloseTimer;
1717
+ /** Handle attach menu click */
1718
+ onAttachMenuClick(event: AXClickEvent): void;
1719
+ /** Handle attachment menu action selection */
1720
+ onAttachMenuAction(actionId: string): Promise<void>;
1721
+ /** Handle primary button click (send / cancel / stopping / voice / locked). */
1722
+ onPrimaryButtonClick(): Promise<void>;
1723
+ /** @deprecated Use onPrimaryButtonClick */
1724
+ onDefaultActionClick(): Promise<void>;
1725
+ getPrimaryButtonIcon(): string;
1726
+ getPrimaryButtonLabel(): string;
1727
+ isPrimaryButtonDisabled(): boolean;
1728
+ /** @deprecated Use getPrimaryButtonIcon */
1729
+ getDefaultActionIcon(): string;
1647
1730
  /** Handle voice click */
1648
1731
  onVoiceClick(): void;
1649
1732
  /** Remove attachment */
@@ -1656,8 +1739,9 @@ declare class AXConversationComposerComponent implements OnDestroy {
1656
1739
  startReply(message: AXConversationMessage): void;
1657
1740
  /** Focus the native textarea inside ax-text-area */
1658
1741
  private focusTextArea;
1742
+ private getClickTarget;
1659
1743
  /** Handle action click */
1660
- onActionClick(actionId: string, event?: MouseEvent): Promise<void>;
1744
+ onActionClick(actionId: string, event?: AXClickEvent | MouseEvent, initialFiles?: File[]): Promise<void>;
1661
1745
  /** Check if action is enabled */
1662
1746
  isActionEnabled(action: any): boolean;
1663
1747
  /** Get replying sender name */
@@ -1665,6 +1749,9 @@ declare class AXConversationComposerComponent implements OnDestroy {
1665
1749
  getActionLabel(action: {
1666
1750
  label: string;
1667
1751
  }): string;
1752
+ getActionButtonClass(action: {
1753
+ className?: string;
1754
+ }): string;
1668
1755
  /** Get replying message text */
1669
1756
  getReplyingMessageText(): string;
1670
1757
  /** Preview object for replying banner (type, icon, value) */
@@ -1685,13 +1772,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1685
1772
  }): string;
1686
1773
  /** Handle reply preview click - scroll to original message */
1687
1774
  onReplyPreviewClick(): void;
1688
- /** Inputs for picker / full-width composer components */
1775
+ /** Inputs for picker components opened in popup / action sheet */
1689
1776
  private buildPickerInputs;
1690
- /** Get inputs for dynamic component */
1691
- getComponentInputs(): Record<string, unknown>;
1692
- onEnter(event: AXHtmlEvent<KeyboardEvent>): Promise<void>;
1693
1777
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerComponent, never>;
1694
- 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>;
1695
1779
  }
1696
1780
 
1697
1781
  declare class AXConversationContainerComponent {
@@ -1700,9 +1784,12 @@ declare class AXConversationContainerComponent {
1700
1784
  private readonly fileService;
1701
1785
  private readonly translation;
1702
1786
  private readonly toast;
1787
+ private readonly platform;
1788
+ private readonly actionSheetService;
1703
1789
  private readonly hostRef;
1704
1790
  private readonly platformId;
1705
1791
  protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
1792
+ constructor();
1706
1793
  private get registry();
1707
1794
  /** Custom CSS class */
1708
1795
  readonly customClass: _angular_core.InputSignal<string>;
@@ -1732,7 +1819,10 @@ declare class AXConversationContainerDirective {
1732
1819
  private readonly platformId;
1733
1820
  private readonly translation;
1734
1821
  private readonly toast;
1822
+ private readonly platform;
1823
+ private readonly actionSheetService;
1735
1824
  private readonly config;
1825
+ constructor();
1736
1826
  private get registry();
1737
1827
  /** Active conversation */
1738
1828
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
@@ -1758,59 +1848,51 @@ interface AXConversationDropdownMenuItem {
1758
1848
  declare class AXConversationInfoBarComponent {
1759
1849
  private readonly conversationService;
1760
1850
  private readonly infoBar;
1851
+ private readonly platform;
1852
+ private readonly destroyRef;
1853
+ private readonly customUserAvatarComponent;
1854
+ private readonly layoutTick;
1855
+ constructor();
1761
1856
  protected get registry(): _acorex_components_conversation.AXConversationRegistryService;
1762
- /** Active conversation */
1857
+ readonly hasCustomUserAvatar: _angular_core.Signal<boolean>;
1763
1858
  readonly activeConversation: _angular_core.Signal<AXConversation>;
1764
- /** Active component from service */
1765
1859
  readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveComponent>;
1766
- /** Active banner from service */
1767
1860
  readonly activeBanner: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveBanner>;
1768
- /** Members popover target element — retained for API compatibility */
1769
1861
  readonly membersPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1770
- /** Loading state for async actions */
1771
1862
  readonly actionLoading: _angular_core.WritableSignal<boolean>;
1772
- /** Info area clicked — opens conversation profile panel */
1773
1863
  readonly infoClick: _angular_core.OutputEmitterRef<void>;
1774
- /** @deprecated Use infoClick — kept for backward compatibility */
1775
- readonly avatarClick: _angular_core.OutputEmitterRef<void>;
1776
- /** Search clicked event */
1777
1864
  readonly searchClick: _angular_core.OutputEmitterRef<void>;
1778
- /** Search query changed event */
1779
1865
  readonly searchQuery: _angular_core.OutputEmitterRef<string>;
1780
- /** Menu item clicked event */
1781
1866
  readonly menuItemAction: _angular_core.OutputEmitterRef<string>;
1782
- /** Inline action buttons from registry */
1783
- readonly inlineActions: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarAction[]>;
1784
- /** Dropdown menu items from registry */
1867
+ readonly inlineActions: _angular_core.Signal<AXConversationInfoBarAction[]>;
1785
1868
  readonly menuItems: _angular_core.Signal<AXConversationDropdownMenuItem[]>;
1786
- /** Get conversation status - delegate to utils */
1787
- getStatus(conversation: AXConversation): 'online' | 'offline' | 'away' | undefined;
1788
- /** Get subtitle text - delegate to utils */
1869
+ getStatus(conversation: AXConversation): _acorex_components_conversation.AXConversationPresenceStatus;
1789
1870
  getSubtitle(conversation: AXConversation): string;
1790
- /** Open conversation info panel when the left info area is clicked */
1791
1871
  onInfoLeftClick(): void;
1792
- /** Handle inline action click */
1793
1872
  onInlineActionClick(actionId: string): Promise<void>;
1794
- /** Get inputs for dynamic component */
1873
+ private activateAction;
1795
1874
  getComponentInputs(): Record<string, unknown>;
1796
1875
  getInlineComponentInputs(): Record<string, unknown>;
1797
1876
  isActiveComponentFullWidth(): boolean;
1798
- /** Handle close component */
1799
1877
  onCloseComponent(): void;
1800
1878
  getBannerInputs(): Record<string, unknown>;
1801
1879
  onCloseBanner(): void;
1802
- /** Handle menu item click */
1803
1880
  onMenuItemClick(item: AXConversationDropdownMenuItem): Promise<void>;
1804
1881
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoBarComponent, never>;
1805
- 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>;
1882
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoBarComponent, "ax-conversation-info-bar", never, {}, { "infoClick": "infoClick"; "searchClick": "searchClick"; "searchQuery": "searchQuery"; "menuItemAction": "menuItemAction"; }, never, ["ax-prefix"], true, never>;
1806
1883
  }
1807
1884
 
1808
1885
  /**
1886
+
1809
1887
  * Shared API Types
1888
+
1810
1889
  * Common types used across all API services
1890
+
1811
1891
  */
1812
1892
  /**
1893
+
1813
1894
  * Pagination parameters
1895
+
1814
1896
  */
1815
1897
  interface AXConversationPagination {
1816
1898
  /** Page number (0-based) */
@@ -1825,7 +1907,9 @@ interface AXConversationPagination {
1825
1907
  sortDirection?: 'asc' | 'desc';
1826
1908
  }
1827
1909
  /**
1910
+
1828
1911
  * Paginated response
1912
+
1829
1913
  */
1830
1914
  interface AXConversationPaginatedResult<T> {
1831
1915
  /** Result items */
@@ -1844,7 +1928,9 @@ interface AXConversationPaginatedResult<T> {
1844
1928
  totalPages?: number;
1845
1929
  }
1846
1930
  /**
1931
+
1847
1932
  * Pagination cursor state for a single list (conversations or messages).
1933
+
1848
1934
  */
1849
1935
  interface AXConversationPaginationState {
1850
1936
  page: number;
@@ -1852,11 +1938,15 @@ interface AXConversationPaginationState {
1852
1938
  nextCursor?: string;
1853
1939
  }
1854
1940
  /**
1941
+
1855
1942
  * Connection status
1943
+
1856
1944
  */
1857
1945
  type AXConversationConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
1858
1946
  /**
1947
+
1859
1948
  * API Error with details
1949
+
1860
1950
  */
1861
1951
  interface AXConversationApiError {
1862
1952
  /** Error code */
@@ -1870,19 +1960,24 @@ interface AXConversationApiError {
1870
1960
  /** Timestamp */
1871
1961
  timestamp?: Date;
1872
1962
  }
1873
- /**
1874
- * User presence status
1875
- */
1876
- type AXConversationPresenceStatus = 'online' | 'offline' | 'away' | 'busy' | 'invisible';
1877
- /**
1878
- * User role in conversation
1879
- */
1880
- type AXConversationUserRole = 'owner' | 'admin' | 'member' | 'guest';
1881
1963
 
1882
- /**
1883
- * Abstract Conversation Management API
1884
- * Handle conversation CRUD operations, participants, and settings
1885
- */
1964
+ type AXConversationApiName = 'userApi' | 'conversationApi' | 'messageApi' | 'realtimeApi';
1965
+ interface AXConversationApiLogEntry {
1966
+ /** Public method on AXConversationService that triggered the API call. */
1967
+ serviceMethod: string;
1968
+ /** Injected API instance name. */
1969
+ api: AXConversationApiName;
1970
+ /** Method invoked on the API instance. */
1971
+ apiMethod: string;
1972
+ /** Positional arguments passed to the API method. */
1973
+ context: unknown[];
1974
+ }
1975
+ declare class AXConversationApiLoggerService {
1976
+ private readonly config;
1977
+ log(entry: AXConversationApiLogEntry): void;
1978
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationApiLoggerService, never>;
1979
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationApiLoggerService>;
1980
+ }
1886
1981
 
1887
1982
  /**
1888
1983
  * Conversation creation data
@@ -1907,6 +2002,11 @@ interface AXConversationCreateData {
1907
2002
  icon?: string;
1908
2003
  /** Custom metadata */
1909
2004
  metadata?: Record<string, unknown>;
2005
+ /**
2006
+ * When `true`, create a new private chat even if one already exists with the same participants.
2007
+ * Defaults to `false` for private conversations.
2008
+ */
2009
+ forceCreate?: boolean;
1910
2010
  }
1911
2011
  /**
1912
2012
  * Conversation update data
@@ -1946,20 +2046,9 @@ interface AXConversationFilters {
1946
2046
  custom?: Record<string, unknown>;
1947
2047
  }
1948
2048
  /**
1949
- * Conversation settings update
2049
+ * @deprecated Use {@link AXConversationRoomPreferences} on the user API instead.
1950
2050
  */
1951
- interface AXConversationSettingsUpdate {
1952
- /** Muted until timestamp */
1953
- mutedUntil?: Date;
1954
- /** Show notifications */
1955
- notifications?: boolean;
1956
- /** Custom notification sound */
1957
- notificationSound?: string;
1958
- /** Show message preview in notifications */
1959
- showPreview?: boolean;
1960
- /** Custom settings */
1961
- custom?: Record<string, unknown>;
1962
- }
2051
+ type AXConversationSettingsUpdate = AXConversationRoomPreferences;
1963
2052
  /**
1964
2053
  * Participant update data
1965
2054
  */
@@ -1967,7 +2056,7 @@ interface AXConversationParticipantUpdate {
1967
2056
  /** User ID */
1968
2057
  userId: string;
1969
2058
  /** New role */
1970
- role?: AXConversationUserRole;
2059
+ role?: AXConversationParticipantRole;
1971
2060
  }
1972
2061
  /**
1973
2062
  * Abstract Conversation Management API
@@ -2068,13 +2157,6 @@ declare abstract class AXConversationApi {
2068
2157
  * @throws {AXConversationApiError} If marking fails
2069
2158
  */
2070
2159
  abstract markConversationAsRead(conversationId: string): Promise<void>;
2071
- /**
2072
- * Mark conversation as unread
2073
- *
2074
- * @param conversationId - Conversation ID
2075
- * @throws {AXConversationApiError} If marking fails
2076
- */
2077
- abstract markConversationAsUnread(conversationId: string): Promise<void>;
2078
2160
  /**
2079
2161
  * Search conversations
2080
2162
  *
@@ -2134,37 +2216,6 @@ declare abstract class AXConversationApi {
2134
2216
  * @throws {AXConversationApiError} If update fails
2135
2217
  */
2136
2218
  abstract updateParticipant(conversationId: string, update: AXConversationParticipantUpdate): Promise<AXConversation>;
2137
- /**
2138
- * Get conversation settings
2139
- *
2140
- * @param conversationId - Conversation ID
2141
- * @returns Conversation settings
2142
- * @throws {AXConversationApiError} If request fails
2143
- */
2144
- abstract getConversationSettings(conversationId: string): Promise<AXConversationSettingsUpdate>;
2145
- /**
2146
- * Update conversation settings
2147
- *
2148
- * @param conversationId - Conversation ID
2149
- * @param settings - Settings to update
2150
- * @throws {AXConversationApiError} If update fails
2151
- */
2152
- abstract updateConversationSettings(conversationId: string, settings: AXConversationSettingsUpdate): Promise<void>;
2153
- /**
2154
- * Mute conversation
2155
- *
2156
- * @param conversationId - Conversation ID
2157
- * @param duration - Mute duration in milliseconds (undefined = forever)
2158
- * @throws {AXConversationApiError} If muting fails
2159
- */
2160
- abstract muteConversation(conversationId: string, duration?: number): Promise<void>;
2161
- /**
2162
- * Unmute conversation
2163
- *
2164
- * @param conversationId - Conversation ID
2165
- * @throws {AXConversationApiError} If unmuting fails
2166
- */
2167
- abstract unmuteConversation(conversationId: string): Promise<void>;
2168
2219
  /**
2169
2220
  * Upload conversation avatar
2170
2221
  *
@@ -2583,111 +2634,33 @@ declare abstract class AXConversationMessageApi {
2583
2634
 
2584
2635
  /**
2585
2636
  * Abstract Real-time Events API
2586
- * Handle WebSocket/SSE connections and real-time event subscriptions
2637
+ * Handle WebSocket/SSE event subscriptions for conversation domain updates
2587
2638
  */
2588
2639
 
2589
- /**
2590
- * Connection options
2591
- */
2592
- interface AXConversationConnectionOptions {
2593
- /** WebSocket/SSE endpoint URL */
2594
- url?: string;
2595
- /** Authentication token */
2596
- token?: string;
2597
- /** Reconnect automatically on disconnect */
2598
- autoReconnect?: boolean;
2599
- /** Reconnect delay in milliseconds */
2600
- reconnectDelay?: number;
2601
- /** Maximum reconnect attempts */
2602
- maxReconnectAttempts?: number;
2603
- /** Heartbeat interval in milliseconds */
2604
- heartbeatInterval?: number;
2605
- /** Custom headers */
2606
- headers?: Record<string, string>;
2607
- }
2608
- /**
2609
- * Connection event
2610
- */
2611
- interface AXConversationConnectionEvent {
2612
- /** Event type */
2613
- type: 'connected' | 'disconnected' | 'reconnecting' | 'error';
2614
- /** Timestamp */
2615
- timestamp: Date;
2616
- /** Error message if applicable */
2617
- error?: string;
2618
- /** Attempt number for reconnecting */
2619
- attempt?: number;
2620
- }
2621
- /**
2622
- * Notification event
2623
- */
2624
- interface AXConversationNotificationEvent {
2625
- /** Notification ID */
2626
- id: string;
2627
- /** Notification type */
2628
- type: 'message' | 'mention' | 'reaction' | 'call' | 'system';
2629
- /** Title */
2630
- title: string;
2631
- /** Body text */
2632
- body: string;
2633
- /** Related conversation ID */
2634
- conversationId?: string;
2635
- /** Related message ID */
2636
- messageId?: string;
2637
- /** Icon URL */
2638
- icon?: string;
2639
- /** Timestamp */
2640
- timestamp: Date;
2641
- /** Custom data */
2642
- data?: Record<string, unknown>;
2643
- }
2644
- /**
2645
- * Call event
2646
- */
2647
- interface AXConversationCallEvent {
2648
- /** Call ID */
2649
- callId: string;
2650
- /** Call type */
2651
- type: 'voice' | 'video';
2652
- /** Call status */
2653
- status: 'incoming' | 'outgoing' | 'accepted' | 'rejected' | 'ended' | 'missed';
2654
- /** Caller user ID */
2655
- callerId: string;
2656
- /** Conversation ID */
2657
- conversationId: string;
2658
- /** Timestamp */
2659
- timestamp: Date;
2660
- /** Call duration in seconds (for ended calls) */
2661
- duration?: number;
2662
- }
2663
2640
  /**
2664
2641
  * Abstract Real-time Events API
2665
2642
  *
2666
- * Implement this abstract class to handle real-time event subscriptions.
2667
- * Supports WebSocket, SSE, or any other real-time protocol.
2643
+ * Implement this abstract class to expose domain event streams from your WebSocket/SSE layer.
2644
+ * Connection lifecycle is owned by the implementation — this contract only covers subscriptions.
2645
+ *
2646
+ * Covered domains: message CRUD, conversation (room) CRUD, typing indicators, and presence.
2647
+ * Message updates include edits, reactions, delivery/read status, and other message field changes.
2668
2648
  *
2669
2649
  * @example
2670
2650
  * ```typescript
2671
2651
  * @Injectable()
2672
2652
  * export class MyRealtimeApi extends AXConversationRealtimeApi {
2673
- * private socket: WebSocket;
2674
- * private connectionStatus$ = new BehaviorSubject<AXConversationConnectionStatus>('disconnected');
2653
+ * private readonly messageCreated$ = new Subject<AXConversationMessage>();
2675
2654
  *
2676
- * async connect(options?: AXConversationConnectionOptions): Promise<void> {
2677
- * this.socket = new WebSocket(options?.url || 'ws://localhost:3000');
2678
- * this.socket.onopen = () => this.connectionStatus$.next('connected');
2679
- * // ... handle other events
2655
+ * constructor(private readonly socket: MyChatSocketService) {
2656
+ * super();
2657
+ * this.socket.on('message.created', (message) => this.messageCreated$.next(message));
2680
2658
  * }
2681
2659
  *
2682
2660
  * subscribeToMessages(conversationId: string): Observable<AXConversationMessage> {
2683
- * return new Observable(subscriber => {
2684
- * this.socket.addEventListener('message', (event) => {
2685
- * const data = JSON.parse(event.data);
2686
- * if (data.type === 'message' && data.conversationId === conversationId) {
2687
- * subscriber.next(data.message);
2688
- * }
2689
- * });
2690
- * });
2661
+ * return this.messageCreated$.pipe(
2662
+ * filter((message) => !conversationId || message.conversationId === conversationId),
2663
+ * );
2691
2664
  * }
2692
2665
  *
2693
2666
  * // ... implement other methods
@@ -2695,41 +2668,6 @@ interface AXConversationCallEvent {
2695
2668
  * ```
2696
2669
  */
2697
2670
  declare abstract class AXConversationRealtimeApi {
2698
- /**
2699
- * Current connection status
2700
- * Emit connection status changes through this observable
2701
- */
2702
- abstract readonly connectionStatus$: Observable<AXConversationConnectionStatus>;
2703
- /**
2704
- * Connect to real-time server
2705
- * Establish WebSocket/SSE connection
2706
- *
2707
- * @param options - Connection options
2708
- * @throws {Error} If connection fails
2709
- */
2710
- abstract connect(options?: AXConversationConnectionOptions): Promise<void>;
2711
- /**
2712
- * Disconnect from real-time server
2713
- * Close connection and clean up resources
2714
- */
2715
- abstract disconnect(): Promise<void>;
2716
- /**
2717
- * Check if currently connected
2718
- *
2719
- * @returns True if connected
2720
- */
2721
- abstract isConnected(): boolean;
2722
- /**
2723
- * Reconnect to server
2724
- * Manually trigger reconnection
2725
- */
2726
- abstract reconnect(): Promise<void>;
2727
- /**
2728
- * Subscribe to connection events
2729
- *
2730
- * @returns Observable of connection events
2731
- */
2732
- abstract subscribeToConnectionEvents(): Observable<AXConversationConnectionEvent>;
2733
2671
  /**
2734
2672
  * Subscribe to new messages in a conversation
2735
2673
  *
@@ -2738,7 +2676,7 @@ declare abstract class AXConversationRealtimeApi {
2738
2676
  */
2739
2677
  abstract subscribeToMessages(conversationId: string): Observable<AXConversationMessage>;
2740
2678
  /**
2741
- * Subscribe to message updates (edits, status changes)
2679
+ * Subscribe to message updates (edits, reactions, status changes, metadata, etc.)
2742
2680
  *
2743
2681
  * @param conversationId - Optional conversation ID to filter
2744
2682
  * @returns Observable stream of updated messages
@@ -2752,15 +2690,32 @@ declare abstract class AXConversationRealtimeApi {
2752
2690
  */
2753
2691
  abstract subscribeToMessageDeletions(conversationId?: string): Observable<string>;
2754
2692
  /**
2755
- * Subscribe to message reactions
2693
+ * Subscribe to message status changes
2694
+ * Fires when message status changes (sending -> sent -> delivered -> read)
2695
+ *
2696
+ * @param conversationId - Optional conversation ID to filter
2697
+ * @returns Observable stream of message status updates
2698
+ */
2699
+ abstract subscribeToMessageStatusChanges(conversationId?: string): Observable<{
2700
+ messageId: string;
2701
+ status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
2702
+ timestamp: Date;
2703
+ }>;
2704
+ /**
2705
+ * Subscribe to read receipt updates
2706
+ * Fires when someone reads messages
2756
2707
  *
2757
2708
  * @param conversationId - Optional conversation ID to filter
2758
- * @returns Observable stream of updated messages with reactions
2709
+ * @returns Observable stream of message IDs that were read
2759
2710
  */
2760
- abstract subscribeToMessageReactions(conversationId?: string): Observable<AXConversationMessage>;
2711
+ abstract subscribeToReadReceipts(conversationId?: string): Observable<{
2712
+ messageId: string;
2713
+ userId: string;
2714
+ readAt: Date;
2715
+ }>;
2761
2716
  /**
2762
2717
  * Subscribe to conversation updates
2763
- * Fires when conversation details change (title, avatar, participants, etc.)
2718
+ * Fires when conversation details change (title, avatar, participants, last message, etc.)
2764
2719
  *
2765
2720
  * @returns Observable stream of updated conversations
2766
2721
  */
@@ -2793,97 +2748,6 @@ declare abstract class AXConversationRealtimeApi {
2793
2748
  * @returns Observable stream of presence updates
2794
2749
  */
2795
2750
  abstract subscribeToPresenceUpdates(userIds?: string[]): Observable<AXConversationPresenceUpdate>;
2796
- /**
2797
- * Subscribe to read receipt updates
2798
- * Fires when someone reads messages
2799
- *
2800
- * @param conversationId - Optional conversation ID to filter
2801
- * @returns Observable stream of message IDs that were read
2802
- */
2803
- abstract subscribeToReadReceipts(conversationId?: string): Observable<{
2804
- messageId: string;
2805
- userId: string;
2806
- readAt: Date;
2807
- }>;
2808
- /**
2809
- * Subscribe to push notifications
2810
- * Fires for mentions, calls, and other important events
2811
- *
2812
- * @returns Observable stream of notification events
2813
- */
2814
- abstract subscribeToNotifications(): Observable<AXConversationNotificationEvent>;
2815
- /**
2816
- * Subscribe to call events
2817
- * Fires for incoming/outgoing calls
2818
- *
2819
- * @returns Observable stream of call events
2820
- */
2821
- abstract subscribeToCallEvents?(): Observable<AXConversationCallEvent>;
2822
- /**
2823
- * Subscribe to user blocked/unblocked events
2824
- *
2825
- * @returns Observable stream of user IDs and block status
2826
- */
2827
- abstract subscribeToUserBlockEvents(): Observable<{
2828
- userId: string;
2829
- blocked: boolean;
2830
- }>;
2831
- /**
2832
- * Subscribe to participant added/removed events
2833
- *
2834
- * @param conversationId - Optional conversation ID to filter
2835
- * @returns Observable stream of participant changes
2836
- */
2837
- abstract subscribeToParticipantEvents(conversationId?: string): Observable<{
2838
- conversationId: string;
2839
- userId: string;
2840
- action: 'added' | 'removed';
2841
- }>;
2842
- /**
2843
- * Subscribe to system events
2844
- * Fires for maintenance, updates, or other system-wide events
2845
- *
2846
- * @returns Observable stream of system events
2847
- */
2848
- abstract subscribeToSystemEvents(): Observable<{
2849
- type: string;
2850
- message: string;
2851
- data?: unknown;
2852
- }>;
2853
- /**
2854
- * Subscribe to message status changes
2855
- * Fires when message status changes (sending -> sent -> delivered -> read)
2856
- *
2857
- * @param conversationId - Optional conversation ID to filter
2858
- * @returns Observable stream of message status updates
2859
- */
2860
- abstract subscribeToMessageStatusChanges(conversationId?: string): Observable<{
2861
- messageId: string;
2862
- status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
2863
- timestamp: Date;
2864
- }>;
2865
- /**
2866
- * Subscribe to conversation settings changes
2867
- * Fires when conversation settings are updated
2868
- *
2869
- * @param conversationId - Optional conversation ID to filter
2870
- * @returns Observable stream of settings updates
2871
- */
2872
- abstract subscribeToConversationSettingsChanges(conversationId?: string): Observable<{
2873
- conversationId: string;
2874
- settings: Record<string, unknown>;
2875
- }>;
2876
- /**
2877
- * Subscribe to draft changes
2878
- * Fires when draft is saved/updated in a conversation
2879
- *
2880
- * @param conversationId - Optional conversation ID to filter
2881
- * @returns Observable stream of draft updates
2882
- */
2883
- abstract subscribeToDraftChanges(conversationId?: string): Observable<{
2884
- conversationId: string;
2885
- draft: string | null;
2886
- }>;
2887
2751
  }
2888
2752
 
2889
2753
  /**
@@ -2963,7 +2827,7 @@ declare abstract class AXConversationUserApi {
2963
2827
  * @returns Current user information
2964
2828
  * @throws {AXConversationApiError} If user is not authenticated
2965
2829
  */
2966
- abstract getCurrentUser(): Promise<AXConversationParticipant>;
2830
+ abstract getCurrentUser(): Promise<AXConversationUser>;
2967
2831
  /**
2968
2832
  * Update current user profile
2969
2833
  *
@@ -2971,7 +2835,7 @@ declare abstract class AXConversationUserApi {
2971
2835
  * @returns Updated user information
2972
2836
  * @throws {AXConversationApiError} If update fails
2973
2837
  */
2974
- abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationParticipant>;
2838
+ abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationUser>;
2975
2839
  /**
2976
2840
  * Upload user avatar
2977
2841
  *
@@ -2983,11 +2847,12 @@ declare abstract class AXConversationUserApi {
2983
2847
  /**
2984
2848
  * Get available users for conversation creation
2985
2849
  *
2850
+ * @param pagination - Pagination parameters
2986
2851
  * @param filters - Search filters
2987
- * @returns List of users
2852
+ * @returns Paginated list of users
2988
2853
  * @throws {AXConversationApiError} If request fails
2989
2854
  */
2990
- abstract getUsers(filters?: AXConversationUserSearchFilters): Promise<AXConversationParticipant[]>;
2855
+ abstract getUsers(pagination?: AXConversationPagination, filters?: AXConversationUserSearchFilters): Promise<AXConversationPaginatedResult<AXConversationParticipant>>;
2991
2856
  /**
2992
2857
  * Search users by query
2993
2858
  *
@@ -3020,6 +2885,10 @@ declare abstract class AXConversationUserApi {
3020
2885
  * @throws {AXConversationApiError} If request fails
3021
2886
  */
3022
2887
  abstract getUserPresence(userId: string): Promise<AXConversationPresenceUpdate>;
2888
+ /**
2889
+ * Get presence for multiple users (bulk hydration).
2890
+ */
2891
+ abstract getUsersPresence(userIds: string[]): Promise<AXConversationPresenceUpdate[]>;
3023
2892
  /**
3024
2893
  * Update current user presence
3025
2894
  *
@@ -3072,6 +2941,18 @@ declare abstract class AXConversationUserApi {
3072
2941
  * @throws {AXConversationApiError} If update fails
3073
2942
  */
3074
2943
  abstract updateUserSettings(settings: Record<string, unknown>): Promise<void>;
2944
+ /**
2945
+ * Get all conversation preferences for the current user.
2946
+ */
2947
+ abstract getConversationPreferences(): Promise<AXConversationRoomPreferencesMap>;
2948
+ /**
2949
+ * Get preferences for a single conversation.
2950
+ */
2951
+ abstract getConversationPreferencesForRoom(conversationId: string): Promise<AXConversationRoomPreferences>;
2952
+ /**
2953
+ * Update preferences for a conversation (current user's view).
2954
+ */
2955
+ abstract updateConversationPreferences(conversationId: string, preferences: Partial<AXConversationRoomPreferences>): Promise<AXConversationRoomPreferences>;
3075
2956
  /**
3076
2957
  * Create an API error
3077
2958
  * Helper method for consistent error creation
@@ -3085,6 +2966,27 @@ declare abstract class AXConversationUserApi {
3085
2966
  protected createError(code: string, message: string, statusCode?: number, details?: unknown): AXConversationApiError;
3086
2967
  }
3087
2968
 
2969
+ type AXConversationComposerGenerationPhase = 'idle' | 'generating' | 'stopping';
2970
+ declare class AXConversationComposerGenerationStateService {
2971
+ private readonly _phase;
2972
+ private readonly _cancelled$;
2973
+ /** Current generation lifecycle phase. */
2974
+ readonly phase: _angular_core.Signal<AXConversationComposerGenerationPhase>;
2975
+ /** Whether a background generation (e.g. AI response) is in progress. */
2976
+ readonly isGenerating: _angular_core.Signal<boolean>;
2977
+ /** Whether generation is being cancelled (spinner / locked until API finishes). */
2978
+ readonly isStopping: _angular_core.Signal<boolean>;
2979
+ /** Whether generation or stop-cleanup is in progress. */
2980
+ readonly isBusy: _angular_core.Signal<boolean>;
2981
+ /** Emits when the user presses the composer cancel/stop button. */
2982
+ readonly onCancelled: rxjs.Observable<void>;
2983
+ setGenerating(value: boolean): void;
2984
+ /** User requested cancel — enters `stopping` until {@link setGenerating}(false) is called. */
2985
+ cancel(): void;
2986
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerGenerationStateService, never>;
2987
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationComposerGenerationStateService>;
2988
+ }
2989
+
3088
2990
  /**
3089
2991
  * Central Registry Service
3090
2992
  * Provides unified access to all registries
@@ -3143,6 +3045,7 @@ declare class AXConversationService {
3143
3045
  private readonly fileService;
3144
3046
  private readonly platformId;
3145
3047
  private readonly errorHandler;
3048
+ private readonly apiLogger;
3146
3049
  readonly dialogService: AXDialogService;
3147
3050
  readonly popupService: AXPopupService;
3148
3051
  private readonly translation;
@@ -3150,14 +3053,20 @@ declare class AXConversationService {
3150
3053
  private readonly destroy$;
3151
3054
  /** Registry service - exposed for child services */
3152
3055
  readonly registry: AXConversationRegistryService;
3056
+ private readonly composerGenerationState;
3057
+ /** Whether the composer primary button is in cancel (generation) mode. */
3058
+ readonly isGenerating: _angular_core.Signal<boolean>;
3059
+ /** Whether cancel cleanup is in progress. */
3060
+ readonly isStopping: _angular_core.Signal<boolean>;
3061
+ /** Emits when the user cancels an in-progress generation from the composer. */
3062
+ readonly onGenerationCancelled: rxjs.Observable<void>;
3153
3063
  private readonly _activeConversationId;
3154
3064
  private readonly _loading;
3155
3065
  private readonly _loadingActiveMessages;
3066
+ private readonly _isForwardingMessage;
3156
3067
  private readonly _error;
3157
3068
  private readonly _conversationsPagination;
3158
3069
  private readonly _messagesPaginationByConversation;
3159
- /** Emits when the active conversation changes, cancelling per-conversation subscriptions. */
3160
- private readonly _conversationSwitch$;
3161
3070
  private readonly _messageReceived$;
3162
3071
  private readonly _messageUpdated$;
3163
3072
  private readonly _messageDeleted$;
@@ -3175,14 +3084,14 @@ declare class AXConversationService {
3175
3084
  readonly loading: _angular_core.Signal<boolean>;
3176
3085
  /** Loading state for the active conversation's message history */
3177
3086
  readonly loadingActiveMessages: _angular_core.Signal<boolean>;
3087
+ /** Whether a message forward operation is in progress. */
3088
+ readonly isForwardingMessage: _angular_core.Signal<boolean>;
3178
3089
  /** Sidebar conversation list pagination */
3179
3090
  readonly conversationsPagination: _angular_core.Signal<AXConversationPaginationState>;
3180
3091
  /** Active conversation message pagination */
3181
3092
  readonly activeMessagesPagination: _angular_core.Signal<AXConversationPaginationState>;
3182
3093
  /** Error state */
3183
3094
  readonly error: _angular_core.Signal<Error>;
3184
- /** Connection status */
3185
- readonly connectionStatus$: rxjs.Observable<_acorex_components_conversation.AXConversationConnectionStatus>;
3186
3095
  /** Error stream */
3187
3096
  readonly errors$: rxjs.Observable<_acorex_components_conversation.AXConversationError>;
3188
3097
  readonly onMessageReceived: rxjs.Observable<AXConversationMessage>;
@@ -3190,24 +3099,57 @@ declare class AXConversationService {
3190
3099
  readonly onMessageDeleted: rxjs.Observable<string>;
3191
3100
  readonly onTypingIndicator: rxjs.Observable<AXConversationTypingIndicator>;
3192
3101
  readonly onPresenceChange: rxjs.Observable<AXConversationPresenceUpdate>;
3193
- private readonly _messageCountRefresh$;
3194
- readonly onMessageCountRefresh: rxjs.Observable<{
3195
- messageId: string;
3196
- type: "reply" | "forward";
3197
- }>;
3198
3102
  private _currentUser;
3199
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3103
+ readonly currentUser: _angular_core.Signal<AXConversationUser>;
3104
+ readonly userPresenceMap: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3105
+ readonly presenceTimeTick: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3106
+ readonly typingRevision: _angular_core.Signal<Map<string, Map<string, number>>>;
3107
+ /** One-time async initialization (connect, user, conversations, realtime). */
3108
+ private initPromise;
3109
+ /** Generation counter — stale page-0 loads are ignored after conversation switches. */
3110
+ private messageLoadGeneration;
3111
+ /** Bumps when a conversation is created while a list load is in flight. */
3112
+ private conversationListLoadGeneration;
3113
+ /** Batched read-receipt queue keyed by conversation ID. */
3114
+ private readonly readQueue;
3115
+ private readFlushHandle;
3116
+ private presenceTickHandle?;
3117
+ private typingPruneHandle?;
3118
+ /** Outgoing typing indicator throttle state (composer -> API). */
3119
+ private readonly outgoingTypingLastEmitAt;
3120
+ private readonly outgoingTypingActive;
3121
+ private readonly outgoingTypingStopHandles;
3122
+ /** Session cache for available reaction emojis. */
3123
+ private availableReactionsCache;
3124
+ private availableReactionsPromise;
3200
3125
  constructor();
3126
+ /** Log and invoke an async API method from AXConversationService. */
3127
+ private callApi;
3128
+ /** Log a sync API invocation (e.g. realtime observable subscriptions). */
3129
+ private logApi;
3130
+ /**
3131
+ * Ensures the service is initialized exactly once.
3132
+ * Safe to call from container components or before any public API usage.
3133
+ */
3134
+ ensureInitialized(): Promise<void>;
3201
3135
  /**
3202
3136
  * Initialize the service
3203
3137
  * Connects to API and loads initial data
3204
3138
  */
3205
3139
  private initializeService;
3206
3140
  /**
3207
- * Subscribe to real-time events
3208
- * All subscriptions include error handling to prevent stream termination
3141
+ * Subscribe to real-time events from {@link AXConversationRealtimeApi}.
3142
+ * Binds every abstract subscription: messages (create/update/delete/status/read),
3143
+ * conversations (create/update/delete), typing indicators, and presence.
3209
3144
  */
3210
3145
  private subscribeToEvents;
3146
+ getUserPresence(userId: string): AXConversationUserPresence | undefined;
3147
+ getRoomPreferences(conversationId: string): AXConversationRoomPreferences;
3148
+ isAnyoneTyping(conversationId: string): boolean;
3149
+ getActiveTypingUserIds(conversationId: string): string[];
3150
+ getPeerPresence(conversation: AXConversation): AXConversationUserPresence | undefined;
3151
+ private hydrateUserPresence;
3152
+ private loadRoomPreferences;
3211
3153
  /**
3212
3154
  * Load conversations from server
3213
3155
  * Includes comprehensive error handling
@@ -3219,9 +3161,7 @@ declare class AXConversationService {
3219
3161
  */
3220
3162
  loadMoreConversations(page: number): Promise<boolean>;
3221
3163
  /**
3222
- * Select a conversation
3223
- * Loads messages and subscribes to real-time updates
3224
- * Note: Messages are now marked as read individually via intersection observer when viewed
3164
+ * Select a conversation and load page 0 of its message history.
3225
3165
  */
3226
3166
  selectConversation(conversationId: string): Promise<void>;
3227
3167
  closeActiveConversation(): void;
@@ -3242,6 +3182,7 @@ declare class AXConversationService {
3242
3182
  * Resolve a media reference to a playback/download URL.
3243
3183
  */
3244
3184
  resolveMediaUrl(reference: AXConversationUploaderReference, signal?: AbortSignal): Promise<string>;
3185
+ private resolveReplyTo;
3245
3186
  /**
3246
3187
  * Send a message
3247
3188
  * Uses optimistic UI updates - message appears immediately
@@ -3273,20 +3214,52 @@ declare class AXConversationService {
3273
3214
  */
3274
3215
  getAvailableReactions(): Promise<string[]>;
3275
3216
  /**
3276
- * Mark a single message as read
3277
- * Updates message status locally and syncs with server
3217
+ * Queue a message to be marked as read (batched/debounced API sync).
3218
+ */
3219
+ queueMessageAsRead(messageId: string): void;
3220
+ /**
3221
+ * Mark a single message as read (queues for batched sync).
3278
3222
  */
3279
3223
  markMessageAsRead(messageId: string): Promise<void>;
3224
+ private scheduleReadFlush;
3225
+ /**
3226
+ * Drop queued per-message read receipts without syncing to the API.
3227
+ * Used before conversation-level mark-as-read to avoid duplicate API calls.
3228
+ */
3229
+ private discardReadQueue;
3230
+ private flushReadQueue;
3280
3231
  /**
3281
3232
  * Mark conversation as read
3282
3233
  * Marks messages locally and syncs with server
3283
3234
  */
3284
3235
  markAsRead(conversationId: string): Promise<void>;
3236
+ /**
3237
+ * Set composer generation mode (shows cancel button instead of send/voice).
3238
+ * Call from message APIs while an AI or async response is in progress.
3239
+ */
3240
+ setGenerating(value: boolean): void;
3241
+ /**
3242
+ * Cancel an in-progress generation from the composer UI or programmatically.
3243
+ */
3244
+ cancelGeneration(): void;
3245
+ /**
3246
+ * Notify that the composer has draft content.
3247
+ * Emits typing indicators at most once per {@link AXConversationConfig.typingIndicatorThrottle}.
3248
+ */
3249
+ notifyComposerTyping(conversationId: string): void;
3250
+ /**
3251
+ * Notify that the composer no longer has draft content (or user left the chat).
3252
+ * Sends a single stop event when a typing indicator was previously emitted.
3253
+ */
3254
+ notifyComposerStoppedTyping(conversationId: string): void;
3255
+ private scheduleOutgoingTypingStop;
3256
+ private clearOutgoingTypingStop;
3285
3257
  /**
3286
3258
  * Send typing indicator
3287
3259
  * Non-critical operation, doesn't throw on failure
3288
3260
  */
3289
3261
  sendTypingIndicator(conversationId: string): Promise<void>;
3262
+ stopTypingIndicator(conversationId: string): Promise<void>;
3290
3263
  /**
3291
3264
  * Search conversations
3292
3265
  * Returns empty array on failure
@@ -3301,10 +3274,10 @@ declare class AXConversationService {
3301
3274
  */
3302
3275
  private handleMessageUpdate;
3303
3276
  /**
3304
- * Handle message count update
3305
- * Emits events when a message is a reply or forward so components can refresh counts
3277
+ * Bump reply/forward counts locally when realtime events arrive outside the active message list.
3306
3278
  */
3307
- private handleMessageCountUpdate;
3279
+ private syncMessageCountFromRealtime;
3280
+ private bumpMessageCount;
3308
3281
  /**
3309
3282
  * Handle message deletion
3310
3283
  */
@@ -3322,10 +3295,24 @@ declare class AXConversationService {
3322
3295
  * Updates conversation metadata including unread count, last message, etc.
3323
3296
  */
3324
3297
  private handleConversationUpdate;
3298
+ private handleConversationCreated;
3299
+ private handleConversationDeleted;
3300
+ private handleReadReceipt;
3301
+ private handleMessageStatusChange;
3302
+ /**
3303
+ * Insert or refresh a conversation in the in-memory inbox.
3304
+ * @param promote When true, bumps activity so the chat sorts to the top (create / reopen).
3305
+ */
3306
+ private syncConversationToInbox;
3307
+ private finalizeSentMessage;
3325
3308
  /**
3326
3309
  * Update conversation's last message
3327
3310
  */
3328
3311
  private updateConversationLastMessage;
3312
+ /** Keep sidebar preview in sync when the last cached message is edited or deleted. */
3313
+ private syncLastMessageIfRelevant;
3314
+ /** Recompute conversation preview after a message is removed from the local cache. */
3315
+ private refreshConversationLastMessage;
3329
3316
  /**
3330
3317
  * Update conversation properties
3331
3318
  * @param conversationId - Conversation ID
@@ -3337,7 +3324,7 @@ declare class AXConversationService {
3337
3324
  * @param conversationId - Conversation ID
3338
3325
  * @param settings - Partial settings to update
3339
3326
  */
3340
- updateConversationSettings(conversationId: string, settings: Partial<AXConversation['settings']>): Promise<void>;
3327
+ updateConversationSettings(conversationId: string, settings: Partial<AXConversationRoomPreferences>): Promise<void>;
3341
3328
  /**
3342
3329
  * Update conversation title
3343
3330
  * @param conversationId - Conversation ID
@@ -3361,15 +3348,19 @@ declare class AXConversationService {
3361
3348
  * @param participantIds - Array of participant user IDs
3362
3349
  * @param type - Conversation type (private, group, channel)
3363
3350
  * @param metadata - Optional metadata (title, avatar, etc.)
3364
- * @returns Created conversation
3351
+ * @param options - Optional flags (`forceCreate` recreates private chats even when one exists)
3352
+ * @returns Created or existing conversation
3365
3353
  */
3366
- createConversation(participantIds: string[], type: AXConversationType, metadata?: AXConversationMetadata): Promise<AXConversation>;
3354
+ createConversation(participantIds: string[], type: AXConversationType, metadata?: AXConversationMetadata, options?: {
3355
+ forceCreate?: boolean;
3356
+ }): Promise<AXConversation>;
3367
3357
  /**
3368
3358
  * Get available users for conversation creation
3369
- * @param query - Optional search query
3370
- * @returns List of users
3359
+ * @param filters - Optional search filters (e.g. `query`)
3360
+ * @param pagination - Pagination parameters
3361
+ * @returns Paginated list of users
3371
3362
  */
3372
- getUsers(query?: string): Promise<AXConversationParticipant[]>;
3363
+ getUsers(filters?: AXConversationUserSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationParticipant>>;
3373
3364
  /**
3374
3365
  * Mark entire conversation as read
3375
3366
  * @param conversationId - Conversation ID
@@ -3393,11 +3384,6 @@ declare class AXConversationService {
3393
3384
  * @returns Number of times forwarded
3394
3385
  */
3395
3386
  getForwardCount(messageId: string): Promise<number>;
3396
- /**
3397
- * Disconnect and cleanup
3398
- * Cleanly closes all connections and resources
3399
- */
3400
- disconnect(): Promise<void>;
3401
3387
  /**
3402
3388
  * Archive conversation
3403
3389
  * @param conversationId - Conversation ID
@@ -3476,6 +3462,10 @@ declare class AXConversationService {
3476
3462
  * @param caption - Optional caption
3477
3463
  */
3478
3464
  forwardMessage(messageId: string, conversationIds: string[], caption?: string): Promise<void>;
3465
+ /**
3466
+ * Runs a forward operation while locking all forward actions until it completes.
3467
+ */
3468
+ runWithForwardingLock<T>(task: () => Promise<T>): Promise<T>;
3479
3469
  /**
3480
3470
  * Search messages in conversation
3481
3471
  * @param conversationId - Conversation ID
@@ -3530,7 +3520,7 @@ declare class AXConversationService {
3530
3520
  * @param status - Presence status
3531
3521
  * @param statusText - Optional status text
3532
3522
  */
3533
- updatePresence(status: 'online' | 'offline' | 'away' | 'busy' | 'invisible', statusText?: string): Promise<void>;
3523
+ updatePresence(status: AXConversationPresenceStatus, statusText?: string): Promise<void>;
3534
3524
  /**
3535
3525
  * Validate message content before sending
3536
3526
  * Uses centralized validation utilities for consistency
@@ -3678,6 +3668,7 @@ declare class AXConversationForwardMessageDialogComponent implements OnInit {
3678
3668
  readonly forwardListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
3679
3669
  readonly forwardList: _angular_core.Signal<AXListComponent>;
3680
3670
  readonly forwardListDataSource: AXDataSource<unknown>;
3671
+ readonly isForwarding: _angular_core.Signal<boolean>;
3681
3672
  readonly canForward: _angular_core.Signal<boolean>;
3682
3673
  private readonly _syncPopupTitleEffect;
3683
3674
  ngOnInit(): void;
@@ -3711,18 +3702,21 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3711
3702
  private readonly infoBarService;
3712
3703
  private readonly translation;
3713
3704
  private readonly document;
3705
+ private readonly platform;
3706
+ private readonly actionSheetService;
3714
3707
  protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
3715
3708
  /**
3716
- * Background for the message list scroll area from config, or the built-in soft gradient when unset/empty.
3709
+ * Background for the message list scroll area from config, or the built-in soft wash when unset/empty.
3717
3710
  * Set `messageListBackground` to `transparent` or `none` for a flat look.
3711
+ * Supports `{ light, dark }` for theme-specific backgrounds.
3718
3712
  */
3719
- messageListBackgroundStyle(): string;
3713
+ readonly messageListUsesDefaultWallpaper: _angular_core.Signal<boolean>;
3714
+ readonly messageListWallpaperDark: _angular_core.Signal<boolean>;
3715
+ readonly messageListBackgroundStyle: _angular_core.Signal<string>;
3720
3716
  resolvedEmptyStateComponent(): Type<AXConversationMessageListEmptyComponent>;
3721
3717
  /** Fallback when no conversation is active and no `ax-conversation-message-list-no-active` content is projected. */
3722
3718
  protected readonly noActiveFallbackComponent: typeof AXConversationMessageListNoActiveDefaultComponent;
3723
3719
  private readonly timeouts;
3724
- private readonly replyCounts;
3725
- private readonly forwardCounts;
3726
3720
  readonly reactionPickerTarget: _angular_core.WritableSignal<string>;
3727
3721
  readonly reactionPickerElement: _angular_core.WritableSignal<HTMLElement>;
3728
3722
  readonly reactionPickerPlacement: _angular_core.WritableSignal<AXPlacement>;
@@ -3731,9 +3725,13 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3731
3725
  readonly contextMenuMessageId: _angular_core.WritableSignal<string>;
3732
3726
  /** True while files are dragged over the message list drop zone. */
3733
3727
  readonly messageListDragging: _angular_core.WritableSignal<boolean>;
3728
+ /** True when the message list uses single-column adaptive layout (matches CSS container query). */
3729
+ readonly isAdaptiveWideLayout: _angular_core.WritableSignal<boolean>;
3734
3730
  /** While true, older history is being prepended — do not auto-scroll to the latest message. */
3735
3731
  private restoringScrollAfterPrepend;
3732
+ private adaptiveLayoutResizeObserver?;
3736
3733
  readonly availableReactions: _angular_core.WritableSignal<string[]>;
3734
+ private reactionsLoading;
3737
3735
  private get registry();
3738
3736
  /** Message list element reference */
3739
3737
  private readonly messageListRef;
@@ -3749,6 +3747,11 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3749
3747
  readonly showScrollButton: _angular_core.WritableSignal<boolean>;
3750
3748
  /** Active conversation */
3751
3749
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
3750
+ readonly isGroupConversation: _angular_core.Signal<boolean>;
3751
+ /** Placeholder indices for the initial message list skeleton. */
3752
+ protected readonly loadingSkeletonItems: readonly [0, 1, 2, 3, 4, 5];
3753
+ /** Whether the active conversation allows message reactions. */
3754
+ readonly reactionsEnabled: _angular_core.Signal<boolean>;
3752
3755
  /** Messages */
3753
3756
  readonly messages: _angular_core.Signal<AXConversationMessage[]>;
3754
3757
  /** Message action event */
@@ -3757,7 +3760,7 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3757
3760
  action: string;
3758
3761
  }>;
3759
3762
  /** Current user from service */
3760
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3763
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
3761
3764
  /** Message grouped by date - use service */
3762
3765
  readonly messageGroups: _angular_core.Signal<{
3763
3766
  date: string;
@@ -3766,6 +3769,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3766
3769
  }[]>;
3767
3770
  constructor();
3768
3771
  private intersectionObserver?;
3772
+ private readonly readIntersectionObserver;
3773
+ private readonly observedReadMessageIds;
3769
3774
  /**
3770
3775
  * Setup intersection observer to mark messages as read when visible
3771
3776
  */
@@ -3780,8 +3785,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3780
3785
  getBubbleClasses(message: AXConversationMessage): string;
3781
3786
  /** Check if message is from current user */
3782
3787
  isOwnMessage(message: AXConversationMessage): boolean;
3783
- /** Should show avatar */
3784
- shouldShowAvatar(message: AXConversationMessage): boolean;
3788
+ /** Whether the avatar slot is rendered (visibility is CSS-controlled per layout mode). */
3789
+ shouldRenderAvatar(message: AXConversationMessage): boolean;
3785
3790
  /** Should show sender name */
3786
3791
  shouldShowSenderName(message: AXConversationMessage): boolean;
3787
3792
  /** Get sender name */
@@ -3793,6 +3798,7 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3793
3798
  /** Resolve renderer component for message */
3794
3799
  getRendererComponent(message: AXConversationMessage): Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
3795
3800
  /** Resolve lazy renderer loader for message */
3801
+ private static readonly fallbackRendererLoader;
3796
3802
  getRendererComponentLoader(message: AXConversationMessage): (() => Promise<Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
3797
3803
  /** Provide inputs for the dynamic renderer */
3798
3804
  getRendererInputs(message: AXConversationMessage): {
@@ -3820,6 +3826,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3820
3826
  userIds: string[];
3821
3827
  hasReacted: boolean;
3822
3828
  }): string;
3829
+ /** Whether reactions can be shown or added for a message in the active conversation. */
3830
+ messageSupportsReactions(message: AXConversationMessage): boolean;
3823
3831
  /** Toggle reaction picker */
3824
3832
  toggleReactionPicker(message: AXConversationMessage, event: MouseEvent): void;
3825
3833
  /** Close reaction picker */
@@ -3832,8 +3840,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3832
3840
  onReactionClickById(messageId: string, emoji: string): void;
3833
3841
  /** Get message by ID */
3834
3842
  getMessageById(messageId: string): AXConversationMessage | undefined;
3835
- /** Load available reactions from API */
3836
- private loadAvailableReactions;
3843
+ /** Load available reactions when the picker is opened (session-cached in service). */
3844
+ private ensureAvailableReactions;
3837
3845
  /** Get message actions from registry */
3838
3846
  getMessageActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
3839
3847
  /** Handle reaction click */
@@ -3872,15 +3880,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3872
3880
  /** Get ARIA label for message */
3873
3881
  getMessageAriaLabel(message: AXConversationMessage): string;
3874
3882
  getDateSeparatorAriaLabel(dateLabel: string): string;
3875
- /** Get reply count for a message (fetches from API across all conversations) */
3876
3883
  getReplyCount(message: AXConversationMessage): number;
3877
- /** Get forward count for a message (fetches from API across all conversations) */
3878
3884
  getForwardCount(message: AXConversationMessage): number;
3879
- /**
3880
- * Refresh count for a specific message from API
3881
- * This is called when a new reply or forward is detected globally
3882
- */
3883
- private refreshCount;
3884
3885
  onMessageListDragEnter(): void;
3885
3886
  onMessageListDragLeave(): void;
3886
3887
  /** Open the matching composer picker popup when files are dropped on the message list. */
@@ -3890,30 +3891,16 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3890
3891
  handleMessageContextMenuOpening(event: AXContextMenuOpeningEvent, message: AXConversationMessage): void;
3891
3892
  /** Handle context menu item click for messages */
3892
3893
  handleMessageContextMenuItemClick(event: AXContextMenuItemsClickEvent, message: AXConversationMessage): void;
3893
- /**
3894
- * TrackBy function for message groups.
3895
- * Include the latest message id so new messages in the same date group re-render.
3896
- */
3897
- trackMessageGroup(index: number, group: {
3898
- date: string;
3899
- messages: AXConversationMessage[];
3900
- }): string;
3901
- /**
3902
- * TrackBy function for messages
3903
- * Tracks by ID only to prevent unnecessary re-renders
3904
- */
3905
- trackMessage(index: number, message: AXConversationMessage): string;
3906
3894
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListComponent, never>;
3907
3895
  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>;
3908
3896
  }
3909
3897
 
3910
3898
  declare class AXConversationMessageListService {
3911
3899
  private readonly conversationService;
3912
- private readonly config;
3913
3900
  private get registry();
3914
3901
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
3915
3902
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
3916
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3903
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
3917
3904
  /** Initial message history load (conversation switch) */
3918
3905
  readonly loading: _angular_core.Signal<boolean>;
3919
3906
  /** Loading older messages (scroll-up pagination) */
@@ -3926,9 +3913,19 @@ declare class AXConversationMessageListService {
3926
3913
  readonly scrollRequests: _angular_core.WritableSignal<number>;
3927
3914
  /** Live renderer instances keyed by message id (for message actions). */
3928
3915
  private readonly _rendererInstances;
3916
+ /**
3917
+ * Reply counts merged from API fields and loaded messages.
3918
+ */
3919
+ readonly replyCounts: _angular_core.Signal<Map<string, number>>;
3920
+ /**
3921
+ * Forward counts merged from API fields and loaded messages.
3922
+ */
3923
+ readonly forwardCounts: _angular_core.Signal<Map<string, number>>;
3929
3924
  registerRendererInstance(messageId: string, instance: AXConversationMessageRendererComponent): void;
3930
3925
  unregisterRendererInstance(messageId: string): void;
3931
3926
  getRendererInstance(messageId: string): AXConversationMessageRendererComponent | undefined;
3927
+ getReplyCount(messageId: string): number;
3928
+ getForwardCount(messageId: string): number;
3932
3929
  /** Message grouped by date */
3933
3930
  readonly messageGroups: _angular_core.Signal<{
3934
3931
  date: string;
@@ -3948,13 +3945,111 @@ declare class AXConversationMessageListService {
3948
3945
  reactToMessage(messageId: string, emoji: string): Promise<void>;
3949
3946
  /** Request message list to scroll to bottom */
3950
3947
  requestScrollToBottom(): void;
3948
+ private buildCountMap;
3951
3949
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListService, never>;
3952
3950
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationMessageListService>;
3953
3951
  }
3954
3952
 
3953
+ declare class AXConversationAvatarPickerComponent {
3954
+ readonly fileInput: _angular_core.Signal<ElementRef<HTMLInputElement>>;
3955
+ readonly showClearButton: _angular_core.InputSignal<boolean>;
3956
+ readonly avatarUrl: _angular_core.ModelSignal<string>;
3957
+ readonly onFileSelected: _angular_core.OutputEmitterRef<string>;
3958
+ triggerFileInput(): void;
3959
+ onFileInputChange(event: Event): Promise<void>;
3960
+ clearAvatar(): void;
3961
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarPickerComponent, never>;
3962
+ 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>;
3963
+ }
3964
+
3965
+ /**
3966
+ * Pluggable avatar components for the conversation UI.
3967
+ * Register via `provideConversation({ avatarComponents: { user, conversation } })`.
3968
+ * When only `user` is registered, a built-in conversation avatar host is wired automatically.
3969
+ */
3970
+
3971
+ /** Custom user avatar (e.g. platform `axp-user-avatar`). */
3972
+ interface AXConversationUserAvatarComponent {
3973
+ readonly userId: InputSignal<string>;
3974
+ readonly size: InputSignal<number>;
3975
+ /** Optional resolved display name (e.g. bot/assist peer title). */
3976
+ readonly displayName?: InputSignal<string | undefined>;
3977
+ /** Optional resolved avatar URL when `userId` is not a platform user row. */
3978
+ readonly displayAvatar?: InputSignal<string | undefined>;
3979
+ /** Optional icon class when no avatar image is available. */
3980
+ readonly displayIcon?: InputSignal<string | undefined>;
3981
+ }
3982
+ /** Optional custom group/channel conversation avatar. */
3983
+ interface AXConversationConversationAvatarComponent {
3984
+ readonly conversationId: InputSignal<string>;
3985
+ readonly size: InputSignal<number>;
3986
+ /** Optional resolved display name for the conversation. */
3987
+ readonly displayName?: InputSignal<string | undefined>;
3988
+ /** Optional resolved avatar URL when no platform conversation row exists. */
3989
+ readonly displayAvatar?: InputSignal<string | undefined>;
3990
+ /** Optional icon class when no avatar image is available. */
3991
+ readonly displayIcon?: InputSignal<string | undefined>;
3992
+ }
3993
+ type AXConversationAvatarKind = 'user' | 'conversation' | 'auto';
3994
+ declare const AX_CONVERSATION_USER_AVATAR_COMPONENT: InjectionToken<Type<AXConversationUserAvatarComponent>>;
3995
+ declare const AX_CONVERSATION_CONVERSATION_AVATAR_COMPONENT: InjectionToken<Type<AXConversationConversationAvatarComponent>>;
3996
+ interface AXConversationAvatarComponents {
3997
+ user?: Type<AXConversationUserAvatarComponent>;
3998
+ conversation?: Type<AXConversationConversationAvatarComponent>;
3999
+ }
4000
+
4001
+ declare class AXConversationAvatarComponent {
4002
+ private readonly conversationService;
4003
+ private readonly userAvatarComponent;
4004
+ private readonly conversationAvatarComponent;
4005
+ readonly kind: _angular_core.InputSignal<AXConversationAvatarKind>;
4006
+ readonly userId: _angular_core.InputSignal<string>;
4007
+ readonly conversation: _angular_core.InputSignal<AXConversation>;
4008
+ readonly message: _angular_core.InputSignal<AXConversationMessage>;
4009
+ readonly size: _angular_core.InputSignal<number>;
4010
+ readonly showStatus: _angular_core.InputSignal<boolean>;
4011
+ readonly name: _angular_core.InputSignal<string>;
4012
+ readonly avatar: _angular_core.InputSignal<string>;
4013
+ readonly icon: _angular_core.InputSignal<string>;
4014
+ private readonly currentUserId;
4015
+ readonly resolvedKind: _angular_core.Signal<"user" | "conversation">;
4016
+ readonly resolvedUserId: _angular_core.Signal<string>;
4017
+ readonly customComponent: _angular_core.Signal<Type<unknown>>;
4018
+ readonly customInputs: _angular_core.Signal<Record<string, unknown>>;
4019
+ readonly filteredCustomInputs: _angular_core.Signal<Record<string, unknown>>;
4020
+ readonly fallbackDisplay: _angular_core.Signal<{
4021
+ name: string;
4022
+ avatar: string;
4023
+ icon: string;
4024
+ }>;
4025
+ readonly fallbackInitials: _angular_core.Signal<string>;
4026
+ readonly resolvedStatus: _angular_core.Signal<_acorex_components_conversation.AXConversationPresenceStatus>;
4027
+ readonly statusBadgePresence: _angular_core.Signal<"online" | "offline" | "away" | "busy">;
4028
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarComponent, never>;
4029
+ 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>;
4030
+ }
4031
+
4032
+ interface AXConversationRegistryComponentRef {
4033
+ component?: Type<unknown>;
4034
+ componentLoader?: () => Promise<Type<unknown>>;
4035
+ }
4036
+ declare class AXConversationRegistryComponentOutletComponent {
4037
+ readonly component: _angular_core.InputSignal<Type<unknown>>;
4038
+ readonly componentLoader: _angular_core.InputSignal<() => Promise<Type<unknown>>>;
4039
+ readonly inputs: _angular_core.InputSignal<Record<string, unknown>>;
4040
+ readonly resolvedComponent: _angular_core.WritableSignal<Type<unknown>>;
4041
+ /** Avoid re-loading when the parent re-binds the same lazy loader reference. */
4042
+ private activeLoader;
4043
+ constructor();
4044
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationRegistryComponentOutletComponent, never>;
4045
+ 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; }; }, {}, never, never, true, never>;
4046
+ }
4047
+ /** Resolve a registry component reference, preferring lazy loaders when provided. */
4048
+ declare function hasRegistryComponent(ref?: AXConversationRegistryComponentRef): boolean;
4049
+
3955
4050
  declare class AXConversationSidebarService {
3956
4051
  private readonly conversationService;
3957
- private readonly config;
4052
+ constructor();
3958
4053
  private get registry();
3959
4054
  readonly searchQuery: _angular_core.WritableSignal<string>;
3960
4055
  readonly activeTabId: _angular_core.WritableSignal<string>;
@@ -3963,7 +4058,6 @@ declare class AXConversationSidebarService {
3963
4058
  readonly loading: _angular_core.Signal<boolean>;
3964
4059
  readonly hasMoreConversations: _angular_core.Signal<boolean>;
3965
4060
  readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
3966
- private filterCache;
3967
4061
  readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
3968
4062
  /**
3969
4063
  * Filter and sort conversations
@@ -3995,6 +4089,8 @@ declare class AXConversationSidebarComponent implements OnDestroy {
3995
4089
  private readonly conversationService;
3996
4090
  private readonly popupService;
3997
4091
  private readonly translation;
4092
+ private readonly ngZone;
4093
+ private readonly cdr;
3998
4094
  /** Conversation selected event */
3999
4095
  readonly conversationSelected: _angular_core.OutputEmitterRef<AXConversation>;
4000
4096
  /** Search debouncing */
@@ -4005,6 +4101,8 @@ declare class AXConversationSidebarComponent implements OnDestroy {
4005
4101
  readonly loading: _angular_core.Signal<boolean>;
4006
4102
  readonly loadingMore: _angular_core.WritableSignal<boolean>;
4007
4103
  readonly hasMoreConversations: _angular_core.Signal<boolean>;
4104
+ readonly isSidebarTabsHorizontal: _angular_core.Signal<boolean>;
4105
+ readonly sidebarTabLocation: _angular_core.Signal<AXTabLocation>;
4008
4106
  constructor();
4009
4107
  /** Handle search input change with debouncing */
4010
4108
  onSearchChange(value: string): void;
@@ -4038,6 +4136,10 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4038
4136
  conversationService: AXConversationService;
4039
4137
  private readonly toastService;
4040
4138
  private readonly translation;
4139
+ private readonly config;
4140
+ private readonly destroyRef;
4141
+ private searchDebounceTimer?;
4142
+ constructor();
4041
4143
  /**
4042
4144
  * Injected by {@link AXPopupComponent} when this dialog is opened via {@link AXPopupService}.
4043
4145
  * Required for `setTitle` / dynamic header — {@link AXBasePageComponent#setTitle} is otherwise unset.
@@ -4061,6 +4163,7 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4061
4163
  private readonly _resetWizardWhenSingleEffect;
4062
4164
  private readonly _syncPopupTitleEffect;
4063
4165
  readonly usersListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
4166
+ readonly usersListLoadingTpl: _angular_core.Signal<TemplateRef<unknown>>;
4064
4167
  readonly usersList: _angular_core.Signal<AXListComponent>;
4065
4168
  readonly usersListDataSource: AXDataSource<unknown>;
4066
4169
  onCancel(): void;
@@ -4070,7 +4173,7 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4070
4173
  onSearchChange(value: string): void;
4071
4174
  isUserSelected(id: string): boolean;
4072
4175
  userFromItem(item: unknown): AXConversationParticipant | null;
4073
- private filteredUsers;
4176
+ private mergeUsersCache;
4074
4177
  onCreateConversation(): Promise<void>;
4075
4178
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationNewDialogComponent, never>;
4076
4179
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationNewDialogComponent, "ax-conversation-new-dialog", never, { "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -4104,25 +4207,24 @@ declare class AXConversationInfiniteScrollDirective {
4104
4207
  /**
4105
4208
  * Conversation feature flags for configurable bundle size.
4106
4209
  */
4107
- type AXConversationMediaPickerFeature = 'image' | 'video' | 'audio' | 'file' | 'voice' | 'location';
4108
4210
  type AXConversationComposerTabFeature = 'emoji' | 'sticker';
4109
4211
  interface AXConversationFeatures {
4110
- /** Enabled composer media pickers; defaults to all when omitted. */
4111
- mediaPickers?: AXConversationMediaPickerFeature[];
4112
- /** Enabled composer popup tabs; defaults to all when omitted. */
4212
+ /** Enabled built-in composer popup tabs (`emoji`, `sticker`). Defaults to none when omitted. */
4113
4213
  composerTabs?: AXConversationComposerTabFeature[];
4114
4214
  }
4115
- declare const AX_ALL_CONVERSATION_MEDIA_PICKERS: readonly AXConversationMediaPickerFeature[];
4116
- declare const AX_ALL_CONVERSATION_COMPOSER_TABS: readonly AXConversationComposerTabFeature[];
4117
- declare function resolveConversationMediaPickers(features?: AXConversationFeatures): readonly AXConversationMediaPickerFeature[];
4118
4215
  declare function resolveConversationComposerTabs(features?: AXConversationFeatures): readonly AXConversationComposerTabFeature[];
4119
- declare function isMediaPickerEnabled(picker: AXConversationMediaPickerFeature, features?: AXConversationFeatures): boolean;
4120
4216
  declare function isComposerTabEnabled(tab: AXConversationComposerTabFeature, features?: AXConversationFeatures): boolean;
4121
4217
 
4122
4218
  /**
4123
4219
  * Conversation Configuration Interface
4124
4220
  * Centralized configuration values to avoid magic numbers
4125
4221
  */
4222
+ /**
4223
+ * Sidebar conversation tabs layout.
4224
+ * - `vertical`: horizontal tab strip above the conversation list.
4225
+ * - `horizontal`: vertical tab strip at inline-start beside the list (`ax-tabs` location `start`).
4226
+ */
4227
+ type AXConversationSidebarTabsOrientation = 'vertical' | 'horizontal';
4126
4228
  /**
4127
4229
  * Main configuration interface for the conversation component
4128
4230
  */
@@ -4137,13 +4239,14 @@ interface AXConversationConfig {
4137
4239
  infiniteScrollThreshold?: number;
4138
4240
  /** Typing indicator timeout in milliseconds */
4139
4241
  typingIndicatorTimeout?: number;
4140
- /** Typing indicator throttle in milliseconds (for rate limiting) */
4242
+ /** Typing indicator emit throttle in milliseconds while composing (default: 3000) */
4141
4243
  typingIndicatorThrottle?: number;
4244
+ /** How long to show received typing indicators in the UI (default: 4000) */
4245
+ typingDisplayDuration?: number;
4142
4246
  /** Message highlight duration in milliseconds */
4143
4247
  messageHighlightDuration?: number;
4144
4248
  /** Search debounce delay in milliseconds */
4145
4249
  debounceSearch?: number;
4146
- /** Date separator inactivity fade delay in milliseconds */
4147
4250
  /** Maximum messages per conversation */
4148
4251
  maxMessagesPerConversation?: number;
4149
4252
  /** Maximum total messages in store */
@@ -4156,8 +4259,11 @@ interface AXConversationConfig {
4156
4259
  maxSidebarWidth?: number;
4157
4260
  /** Default sidebar width in pixels */
4158
4261
  defaultSidebarWidth?: number;
4159
- /** Filter cache size */
4160
- filterCacheSize?: number;
4262
+ /**
4263
+ * Sidebar conversation tabs layout.
4264
+ * `vertical` places a horizontal tab strip above the list; `horizontal` places a vertical tab strip at inline-start beside the list.
4265
+ */
4266
+ sidebarTabsOrientation?: AXConversationSidebarTabsOrientation;
4161
4267
  /** Maximum message length in characters */
4162
4268
  maxMessageLength?: number;
4163
4269
  /** Minimum message length in characters */
@@ -4166,14 +4272,24 @@ interface AXConversationConfig {
4166
4272
  maxFilesPerMessage?: number;
4167
4273
  /** Threshold for marking messages as read (0.0 to 1.0, default: 0.3) */
4168
4274
  messageReadThreshold?: number;
4275
+ /** Debounce window (ms) before flushing batched read-receipt API calls (default: 3000) */
4276
+ messageReadDebounce?: number;
4277
+ /**
4278
+ * When true, marks the whole conversation as read once when it is selected (single API call).
4279
+ * Per-message intersection observer still handles new messages received while the chat is open.
4280
+ */
4281
+ markConversationReadOnSelect?: boolean;
4169
4282
  /**
4170
4283
  * CSS `background` for the message list (`ax-conversation-message-list` area, all states: loading, empty, messages).
4171
4284
  * Use full shorthand, or a bare `https://...` / `/path/to.png` (wrapped as `url(...)` with `center/cover`).
4172
- * Empty string = library default soft gradient. `transparent` or `none` = flat background.
4285
+ * Pass a string for the same value in both themes, or `{ light, dark }` for theme-specific backgrounds.
4286
+ * Empty string = Telegram-inspired theme-aware library default (`{ light, dark }`). `transparent` or `none` = flat background.
4173
4287
  */
4174
- messageListBackground?: string;
4288
+ messageListBackground?: AXConversationMessageListBackground;
4175
4289
  /** Optional feature flags to reduce bundle size per app. */
4176
4290
  features?: AXConversationFeatures;
4291
+ /** Log API calls made by AXConversationService to the console (default: false). */
4292
+ debugApiLogging?: boolean;
4177
4293
  }
4178
4294
 
4179
4295
  /**
@@ -4209,29 +4325,6 @@ declare const AX_CONVERSATION_CONFIG: InjectionToken<Required<AXConversationConf
4209
4325
  */
4210
4326
  declare const AX_CONVERSATION_ERROR_HANDLER_CONFIG: InjectionToken<Partial<AXConversationErrorHandlerConfig>>;
4211
4327
 
4212
- /**
4213
- * Pluggable avatar components for the conversation UI.
4214
- * Register via `provideConversation({ avatarComponents: { user, conversation } })`.
4215
- */
4216
-
4217
- /** Custom user avatar (e.g. platform `axp-user-avatar`). */
4218
- interface AXConversationUserAvatarComponent {
4219
- readonly userId: InputSignal<string>;
4220
- readonly size: InputSignal<number>;
4221
- }
4222
- /** Optional custom group/channel conversation avatar. */
4223
- interface AXConversationConversationAvatarComponent {
4224
- readonly conversationId: InputSignal<string>;
4225
- readonly size: InputSignal<number>;
4226
- }
4227
- type AXConversationAvatarKind = 'user' | 'conversation' | 'auto';
4228
- declare const AX_CONVERSATION_USER_AVATAR_COMPONENT: InjectionToken<Type<AXConversationUserAvatarComponent>>;
4229
- declare const AX_CONVERSATION_CONVERSATION_AVATAR_COMPONENT: InjectionToken<Type<AXConversationConversationAvatarComponent>>;
4230
- interface AXConversationAvatarComponents {
4231
- user?: Type<AXConversationUserAvatarComponent>;
4232
- conversation?: Type<AXConversationConversationAvatarComponent>;
4233
- }
4234
-
4235
4328
  /**
4236
4329
  * Registry Configuration Tokens
4237
4330
  * Injection tokens for configuring default registry values
@@ -4246,514 +4339,60 @@ declare const AX_CONVERSATION_DEFAULT_MESSAGE_RENDERERS: InjectionToken<AXConver
4246
4339
  /**
4247
4340
  * Default message actions configuration
4248
4341
  * Provide this token to override default message actions
4249
- */
4250
- declare const AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS: InjectionToken<AXConversationMessageAction[]>;
4251
- /**
4252
- * Default composer tabs configuration
4253
- * Provide this token to override default composer tabs (emoji, stickers, etc.)
4254
- */
4255
- declare const AX_CONVERSATION_DEFAULT_COMPOSER_TABS: InjectionToken<AXConversationComposerTab[]>;
4256
- /**
4257
- * Default composer actions configuration
4258
- * Provide this token to override default composer actions (attach, voice, etc.)
4259
- */
4260
- declare const AX_CONVERSATION_DEFAULT_COMPOSER_ACTIONS: InjectionToken<AXConversationComposerAction[]>;
4261
- /**
4262
- * Default conversation tabs configuration
4263
- * Provide this token to override default conversation tabs (all, private, groups, etc.)
4264
- */
4265
- declare const AX_CONVERSATION_DEFAULT_CONVERSATION_TABS: InjectionToken<AXConversationTab[]>;
4266
- /**
4267
- * Default info bar actions configuration
4268
- * Provide this token to override default info bar actions (mute, archive, block, etc.)
4269
- */
4270
- declare const AX_CONVERSATION_DEFAULT_INFO_BAR_ACTIONS: InjectionToken<AXConversationInfoBarAction[]>;
4271
- /**
4272
- * Default conversation item actions configuration
4273
- * Provide this token to override default conversation item actions (mute, delete, archive, etc.)
4274
- */
4275
- declare const AX_CONVERSATION_DEFAULT_CONVERSATION_ITEM_ACTIONS: InjectionToken<AXConversationItemAction[]>;
4276
- /**
4277
- * Registry configuration interface
4278
- */
4279
- interface AXConversationRegistryConfiguration {
4280
- /**
4281
- * Additional message renderers to register (built-in renderers are automatic).
4282
- * Each {@link AXConversationMessageRenderer} may include optional `composerActions` for co-located send UX.
4283
- */
4284
- messageRenderers?: AXConversationMessageRenderer[];
4285
- /** Message actions to register by default */
4286
- messageActions?: AXConversationMessageAction[];
4287
- /** Composer tabs to register by default */
4288
- composerTabs?: AXConversationComposerTab[];
4289
- /** Composer actions to register by default */
4290
- composerActions?: AXConversationComposerAction[];
4291
- /** Conversation tabs to register by default */
4292
- conversationTabs?: AXConversationTab[];
4293
- /** Info bar actions to register by default */
4294
- infoBarActions?: AXConversationInfoBarAction[];
4295
- /** Conversation item actions to register by default */
4296
- conversationItemActions?: AXConversationItemAction[];
4297
- }
4298
- /**
4299
- * Complete registry configuration token
4300
- * Provide this for comprehensive registry configuration
4301
- */
4302
- declare const AX_CONVERSATION_REGISTRY_CONFIG: InjectionToken<AXConversationRegistryConfiguration>;
4303
-
4304
- /**
4305
- * IndexedDB Storage Wrapper
4306
- * Provides persistent storage for conversation data
4307
- */
4308
-
4309
- declare const AXConversationIndexedDbStores: {
4310
- readonly PARTICIPANTS: "participants";
4311
- readonly CONVERSATIONS: "conversations";
4312
- readonly MESSAGES: "messages";
4313
- readonly MEDIA: "media";
4314
- readonly SETTINGS: "settings";
4315
- };
4316
- /** Blob stored for demo multimedia uploads */
4317
- interface AXConversationIndexedDbMediaRecord {
4318
- id: string;
4319
- conversationId: string;
4320
- mimeType: string;
4321
- size: number;
4322
- fileName?: string;
4323
- blob: Blob;
4324
- createdAt: string;
4325
- }
4326
- declare class AXConversationIndexedDbStorage {
4327
- private db;
4328
- private initPromise;
4329
- /**
4330
- * Initialize IndexedDB
4331
- */
4332
- init(): Promise<void>;
4333
- /**
4334
- * Get a value from a store
4335
- */
4336
- get<T>(storeName: string, key: string): Promise<T | undefined>;
4337
- /**
4338
- * Get all values from a store
4339
- */
4340
- getAll<T>(storeName: string): Promise<T[]>;
4341
- /**
4342
- * Get values by index
4343
- */
4344
- getAllByIndex<T>(storeName: string, indexName: string, query: IDBValidKey): Promise<T[]>;
4345
- /**
4346
- * Put a value into a store
4347
- */
4348
- put<T>(storeName: string, value: T): Promise<void>;
4349
- /**
4350
- * Delete a value from a store
4351
- */
4352
- delete(storeName: string, key: string): Promise<void>;
4353
- /**
4354
- * Clear all data from a store
4355
- */
4356
- clear(storeName: string): Promise<void>;
4357
- getParticipant(id: string): Promise<AXConversationParticipant | undefined>;
4358
- getAllParticipants(): Promise<AXConversationParticipant[]>;
4359
- putParticipant(participant: AXConversationParticipant): Promise<void>;
4360
- getConversation(id: string): Promise<AXConversation | undefined>;
4361
- getAllConversations(): Promise<AXConversation[]>;
4362
- putConversation(conversation: AXConversation): Promise<void>;
4363
- deleteConversation(id: string): Promise<void>;
4364
- getMessage(id: string): Promise<AXConversationMessage | undefined>;
4365
- getAllMessages(): Promise<AXConversationMessage[]>;
4366
- getMessagesByConversation(conversationId: string): Promise<AXConversationMessage[]>;
4367
- putMessage(message: AXConversationMessage): Promise<void>;
4368
- deleteMessage(id: string): Promise<void>;
4369
- getSetting(key: string): Promise<unknown>;
4370
- putSetting(key: string, value: unknown): Promise<void>;
4371
- getMedia(id: string): Promise<AXConversationIndexedDbMediaRecord | undefined>;
4372
- putMedia(record: AXConversationIndexedDbMediaRecord): Promise<void>;
4373
- deleteMedia(id: string): Promise<void>;
4374
- }
4375
- declare const axConversationIndexedDbStorage: AXConversationIndexedDbStorage;
4376
-
4377
- /**
4378
- * Shared In-Memory Storage
4379
- * Internal storage shared between all IndexedDB API implementations
4380
- * This is NOT a service - just a shared data structure
4381
- */
4382
-
4383
- declare class AXConversationSharedStorage {
4384
- readonly connectionStatus$: BehaviorSubject<AXConversationConnectionStatus>;
4385
- readonly participants: Map<string, AXConversationParticipant>;
4386
- readonly conversations: Map<string, AXConversation>;
4387
- readonly messages: Map<string, AXConversationMessage>;
4388
- readonly messagesByConversation: Map<string, string[]>;
4389
- readonly messageStream$: Subject<AXConversationMessage>;
4390
- readonly messageUpdates$: Subject<AXConversationMessage>;
4391
- readonly messageDeletions$: Subject<string>;
4392
- readonly typingIndicators$: Subject<AXConversationTypingIndicator>;
4393
- readonly presenceUpdates$: Subject<AXConversationPresenceUpdate>;
4394
- readonly conversationUpdates$: Subject<AXConversation>;
4395
- readonly currentUserId = "current-user";
4396
- private isSeeded;
4397
- private presenceInterval?;
4398
- private messageSimulationInterval?;
4399
- private isLoadedFromDB;
4400
- /**
4401
- * Load data from IndexedDB
4402
- */
4403
- loadFromIndexedDB(): Promise<void>;
4404
- /**
4405
- * Seed initial data if not already seeded
4406
- */
4407
- seedIfEmpty(): Promise<void>;
4408
- /** @internal Used by demo seed module */
4409
- markSeeded(): void;
4410
- /** @internal Starts demo presence and message simulations */
4411
- startDemoSimulations(): void;
4412
- /**
4413
- * Simulate user presence changes (online/offline/away)
4414
- */
4415
- private startPresenceSimulation;
4416
- /**
4417
- * Simulate random messages from users
4418
- */
4419
- private startMessageSimulation;
4420
- /**
4421
- * Stop presence simulation
4422
- */
4423
- stopPresenceSimulation(): void;
4424
- /**
4425
- * Stop message simulation
4426
- */
4427
- stopMessageSimulation(): void;
4428
- }
4429
- declare const axConversationSharedStorage: AXConversationSharedStorage;
4430
-
4431
- declare function seedSharedStorageInitialData(storage: AXConversationSharedStorage): Promise<void>;
4432
-
4433
- /**
4434
- * Chat-oriented pagination helpers for IndexedDB demo APIs.
4435
- *
4436
- * Convention (matches {@link AXConversationService}):
4437
- * - Page 0: newest items (sidebar: recent chats; messages: latest history window).
4438
- * - Page 1+ or `cursor`: older items before the previous window.
4439
- * - `hasMore`: true when older items remain.
4440
- * - `nextCursor`: id of the oldest item in the current page (use as `pagination.cursor` for the next request).
4441
- */
4442
-
4443
- declare const AX_CONVERSATION_MESSAGE_CURSOR_PREFIX = "msg:";
4444
- declare const AX_CONVERSATION_CURSOR_PREFIX = "conv:";
4445
- type AXConversationChatCursorKind = 'message' | 'conversation';
4446
- interface AXConversationParsedChatCursor {
4447
- kind: AXConversationChatCursorKind;
4448
- id: string;
4449
- }
4450
- declare function encodeMessageCursor(messageId: string): string;
4451
- declare function encodeConversationCursor(conversationId: string): string;
4452
- /** Decode cursor from API pagination (supports prefixed or legacy raw message id). */
4453
- declare function parseChatCursor(cursor?: string): AXConversationParsedChatCursor | null;
4454
- /**
4455
- * Paginate a list sorted newest-first (chats, message history windows).
4456
- */
4457
- declare function paginateChatNewestFirst<T extends {
4458
- id: string;
4459
- }>(sortedNewestFirst: T[], pagination: AXConversationPagination, cursorKind: AXConversationChatCursorKind): AXConversationPaginatedResult<T>;
4460
- /**
4461
- * Paginate a list sorted oldest-first (replies, forward history).
4462
- */
4463
- declare function paginateChatOldestFirst<T extends {
4464
- id: string;
4465
- }>(sortedOldestFirst: T[], pagination: AXConversationPagination): AXConversationPaginatedResult<T>;
4466
-
4467
- /**
4468
- * Extra seed data so sidebar and message-list pagination can be exercised in the demo.
4469
- */
4470
- /**
4471
- * Append demo chats/messages when the DB is too small for default page sizes (30 / 50).
4472
- */
4473
- declare function ensurePaginationDemoData(): Promise<void>;
4474
-
4475
- /**
4476
- * Shared read/write helpers for IndexedDB chat storage (in-memory + persistence).
4477
- */
4478
-
4479
- declare function getConversationLastActivity(conv: AXConversation): number;
4480
- /** Messages for a conversation, newest first (API / pagination order). */
4481
- declare function getConversationMessagesNewestFirst(conversationId: string): AXConversationMessage[];
4482
- /** Keep per-conversation id list sorted ascending by timestamp (store order). */
4483
- declare function sortConversationMessageIds(conversationId: string): void;
4484
- /** Register a message in maps and keep the conversation index sorted. */
4485
- declare function registerChatMessage(message: AXConversationMessage): void;
4486
- /** Remove a message from conversation index and global map. */
4487
- declare function unregisterChatMessage(messageId: string, conversationId: string): void;
4488
- declare function applyConversationFilters(conversations: AXConversation[], filters?: AXConversationFilters): AXConversation[];
4489
- /** Sidebar list order: pinned first, then by last activity (newest first). */
4490
- declare function getSortedConversationsForInbox(filters?: AXConversationFilters): AXConversation[];
4491
- /** Sort all loaded conversation message indexes (after IndexedDB hydration). */
4492
- declare function normalizeAllConversationMessageIndexes(): void;
4493
-
4494
- declare class AXConversationIndexedDbUserApi extends AXConversationUserApi {
4495
- getCurrentUser(): Promise<AXConversationParticipant>;
4496
- updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationParticipant>;
4497
- uploadAvatar(file: File): Promise<string>;
4498
- getUsers(filters?: AXConversationUserSearchFilters): Promise<AXConversationParticipant[]>;
4499
- searchUsers(query: string): Promise<AXConversationParticipant[]>;
4500
- getUserById(userId: string): Promise<AXConversationParticipant>;
4501
- getUsersByIds(userIds: string[]): Promise<AXConversationParticipant[]>;
4502
- getUserPresence(userId: string): Promise<AXConversationPresenceUpdate>;
4503
- updatePresence(_status: AXConversationPresenceStatus, _statusText?: string): Promise<void>;
4504
- blockUser(_userId: string, _reason?: AXConversationBlockReportReason): Promise<void>;
4505
- unblockUser(_userId: string): Promise<void>;
4506
- getBlockedUsers(): Promise<string[]>;
4507
- reportUser(_userId: string, _reason: AXConversationBlockReportReason): Promise<void>;
4508
- getUserSettings(): Promise<Record<string, unknown>>;
4509
- updateUserSettings(_settings: Record<string, unknown>): Promise<void>;
4510
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbUserApi, never>;
4511
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbUserApi>;
4512
- }
4513
-
4514
- declare class AXConversationIndexedDbConversationApi extends AXConversationApi {
4515
- createConversation(data: AXConversationCreateData): Promise<AXConversation>;
4516
- getConversation(conversationId: string): Promise<AXConversation>;
4517
- /**
4518
- * Inbox page (pinned + recent activity, newest first).
4519
- * Page 0 / cursor align with {@link AXConversationService.loadConversations} and sidebar infinite scroll.
4520
- */
4521
- getConversations(pagination: AXConversationPagination, filters?: AXConversationFilters): Promise<AXConversationPaginatedResult<AXConversation>>;
4522
- updateConversation(conversationId: string, updates: AXConversationUpdateData): Promise<AXConversation>;
4523
- deleteConversation(conversationId: string): Promise<boolean>;
4524
- archiveConversation(conversationId: string): Promise<void>;
4525
- unarchiveConversation(conversationId: string): Promise<void>;
4526
- pinConversation(conversationId: string): Promise<void>;
4527
- unpinConversation(conversationId: string): Promise<void>;
4528
- markConversationAsRead(conversationId: string): Promise<void>;
4529
- markConversationAsUnread(conversationId: string): Promise<void>;
4530
- searchConversations(query: string): Promise<AXConversation[]>;
4531
- filterConversations(filters: AXConversationFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversation>>;
4532
- getParticipants(conversationId: string): Promise<AXConversationParticipant[]>;
4533
- addParticipants(_conversationId: string, _userIds: string[]): Promise<AXConversation>;
4534
- removeParticipant(conversationId: string, _userId: string): Promise<AXConversation>;
4535
- leaveConversation(_conversationId: string): Promise<void>;
4536
- updateParticipant(conversationId: string, _update: AXConversationParticipantUpdate): Promise<AXConversation>;
4537
- getConversationSettings(conversationId: string): Promise<AXConversationSettingsUpdate>;
4538
- updateConversationSettings(conversationId: string, settings: AXConversationSettingsUpdate): Promise<void>;
4539
- muteConversation(conversationId: string, duration?: number): Promise<void>;
4540
- unmuteConversation(conversationId: string): Promise<void>;
4541
- uploadConversationAvatar(_conversationId: string, file: File): Promise<string>;
4542
- getConversationMedia(conversationId: string, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<unknown>>;
4543
- addConversationTags(conversationId: string, tags: string[]): Promise<void>;
4544
- removeConversationTags(conversationId: string, tags: string[]): Promise<void>;
4545
- getConversationTags(conversationId: string): Promise<string[]>;
4546
- saveDraft(conversationId: string, draft: string): Promise<void>;
4547
- getDraft(conversationId: string): Promise<string | null>;
4548
- clearDraft(conversationId: string): Promise<void>;
4549
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbConversationApi, never>;
4550
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbConversationApi>;
4551
- }
4552
-
4553
- declare class AXConversationIndexedDbMessageApi extends AXConversationMessageApi {
4554
- sendMessage(command: AXConversationSendMessageCommand): Promise<AXConversationMessage>;
4555
- getMessage(messageId: string): Promise<AXConversationMessage>;
4556
- /**
4557
- * Message history for a chat (newest-first pages).
4558
- * - Page 0: latest `pageSize` messages.
4559
- * - Page 1+ or `pagination.cursor`: older messages before the previous window.
4560
- */
4561
- getMessages(conversationId: string, pagination: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4562
- editMessage(messageId: string, payload: AXConversationMessagePayload): Promise<AXConversationMessage>;
4563
- deleteMessage(messageId: string, _forEveryone?: boolean): Promise<void>;
4564
- deleteMessages(messageIds: string[], forEveryone?: boolean): Promise<void>;
4565
- searchMessages(conversationId: string, filters: AXConversationMessageSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4566
- searchAllMessages(filters: AXConversationMessageSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4567
- addReaction(messageId: string, emoji: string): Promise<void>;
4568
- removeReaction(messageId: string, emoji: string): Promise<void>;
4569
- getAvailableReactions(): Promise<string[]>;
4570
- markAsRead(conversationId: string, messageIds: string[]): Promise<void>;
4571
- markAsUnread(conversationId: string): Promise<void>;
4572
- getReadReceipts(_messageId: string): Promise<AXConversationReadReceipt[]>;
4573
- forwardMessage(_data: AXConversationMessageForwardData): Promise<AXConversationMessage[]>;
4574
- pinMessage(_conversationId: string, _messageId: string): Promise<void>;
4575
- unpinMessage(_conversationId: string, _messageId: string): Promise<void>;
4576
- getPinnedMessages(_conversationId: string): Promise<AXConversationPinnedMessage[]>;
4577
- getMessageReplies(messageId: string, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationMessage>>;
4578
- getReplyCount(messageId: string): Promise<number>;
4579
- getForwardCount(messageId: string): Promise<number>;
4580
- sendTypingIndicator(conversationId: string): Promise<void>;
4581
- stopTypingIndicator(conversationId: string): Promise<void>;
4582
- updateMessageMetadata(messageId: string, metadata: Record<string, unknown>): Promise<void>;
4583
- getMessageMetadata(messageId: string): Promise<Record<string, unknown>>;
4584
- updateMessageStatus(messageId: string, status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed'): Promise<void>;
4585
- getMessageDeliveryStatus(_messageId: string): Promise<{
4586
- delivered: number;
4587
- read: number;
4588
- total: number;
4589
- }>;
4590
- markMessagesAsRead(messageIds: string[]): Promise<void>;
4591
- bulkDeleteMessages(conversationId: string, messageIds: string[], forEveryone?: boolean): Promise<void>;
4592
- exportMessages(conversationId: string, _format: 'json' | 'csv' | 'txt'): Promise<string | Blob>;
4593
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbMessageApi, never>;
4594
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbMessageApi>;
4595
- }
4596
-
4597
- declare class AXConversationIndexedDbRealtimeApi extends AXConversationRealtimeApi {
4598
- readonly connectionStatus$: Observable<AXConversationConnectionStatus>;
4599
- connect(_options?: AXConversationConnectionOptions): Promise<void>;
4600
- disconnect(): Promise<void>;
4601
- isConnected(): boolean;
4602
- reconnect(): Promise<void>;
4603
- subscribeToConnectionEvents(): Observable<AXConversationConnectionEvent>;
4604
- subscribeToMessages(conversationId: string): Observable<AXConversationMessage>;
4605
- subscribeToMessageUpdates(_conversationId?: string): Observable<AXConversationMessage>;
4606
- subscribeToMessageDeletions(_conversationId?: string): Observable<string>;
4607
- subscribeToMessageReactions(_conversationId?: string): Observable<AXConversationMessage>;
4608
- subscribeToConversationUpdates(): Observable<AXConversation>;
4609
- subscribeToConversationCreated(): Observable<AXConversation>;
4610
- subscribeToConversationDeleted(): Observable<string>;
4611
- subscribeToTypingIndicators(conversationId: string): Observable<AXConversationTypingIndicator>;
4612
- subscribeToPresenceUpdates(_userIds?: string[]): Observable<AXConversationPresenceUpdate>;
4613
- subscribeToReadReceipts(_conversationId?: string): Observable<{
4614
- messageId: string;
4615
- userId: string;
4616
- readAt: Date;
4617
- }>;
4618
- subscribeToNotifications(): Observable<AXConversationNotificationEvent>;
4619
- subscribeToCallEvents(): Observable<AXConversationCallEvent>;
4620
- subscribeToUserBlockEvents(): Observable<{
4621
- userId: string;
4622
- blocked: boolean;
4623
- }>;
4624
- subscribeToParticipantEvents(_conversationId?: string): Observable<{
4625
- conversationId: string;
4626
- userId: string;
4627
- action: 'added' | 'removed';
4628
- }>;
4629
- subscribeToSystemEvents(): Observable<{
4630
- type: string;
4631
- message: string;
4632
- data?: any;
4633
- }>;
4634
- subscribeToMessageStatusChanges(_conversationId?: string): Observable<{
4635
- messageId: string;
4636
- status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
4637
- timestamp: Date;
4638
- }>;
4639
- subscribeToConversationSettingsChanges(_conversationId?: string): Observable<{
4640
- conversationId: string;
4641
- settings: Record<string, unknown>;
4642
- }>;
4643
- subscribeToDraftChanges(_conversationId?: string): Observable<{
4644
- conversationId: string;
4645
- draft: string | null;
4646
- }>;
4647
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbRealtimeApi, never>;
4648
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbRealtimeApi>;
4649
- }
4650
-
4651
- /**
4652
- * AI Responder Service
4653
- * Provides AI-powered automatic responses using Google Gemini API
4654
- *
4655
- * @security API key should be provided via injection token in production
4656
- * @example
4657
- * ```typescript
4658
- * export const AX_CONVERSATION_AI_API_KEY = new InjectionToken<string>('AX_CONVERSATION_AI_API_KEY');
4659
- *
4660
- * providers: [
4661
- * { provide: AX_CONVERSATION_AI_API_KEY, useValue: environment.geminiApiKey }
4662
- * ]
4663
- * ```
4664
- */
4665
-
4666
- /**
4667
- * Injection token for AI API key
4668
- * Provide this in your app config to avoid hardcoding the API key
4669
- */
4670
- declare const AX_CONVERSATION_AI_API_KEY: InjectionToken<string>;
4671
- /**
4672
- * Configuration for AI Responder
4673
- */
4674
- interface AXConversationAiResponderConfig {
4675
- /** Maximum retry attempts for failed requests */
4676
- maxRetries?: number;
4677
- /** Timeout for API requests in milliseconds */
4678
- timeout?: number;
4679
- /** Enable fallback to random replies on error */
4680
- useFallbackReplies?: boolean;
4681
- }
4682
- declare class AXConversationAiResponderService {
4683
- private readonly injectedApiKey;
4684
- private readonly config;
4685
- /**
4686
- * Get API key from injection token
4687
- * Returns undefined if not configured - service will use fallback responses
4688
- */
4689
- private getApiKey;
4690
- /**
4691
- * Get AI-powered response for a given prompt
4692
- * @param prompt - The user's message to respond to
4693
- * @param retryCount - Current retry attempt (internal use)
4694
- * @returns AI-generated response or fallback message
4695
- */
4696
- getAIResponse(prompt: string, retryCount?: number): Promise<string>;
4697
- /**
4698
- * Fetch with timeout
4699
- */
4700
- private fetchWithTimeout;
4701
- /**
4702
- * Delay helper for retry logic
4703
- */
4704
- private delay;
4705
- /**
4706
- * Get a random fallback reply when AI is unavailable
4707
- */
4708
- private getFallbackReply;
4709
- /**
4710
- * Check if AI service is available
4711
- * @returns true if API key is configured
4712
- */
4713
- isAvailable(): boolean;
4714
- /**
4715
- * Update configuration
4716
- */
4717
- configure(config: Partial<AXConversationAiResponderConfig>): void;
4718
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAiResponderService, never>;
4719
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationAiResponderService>;
4720
- }
4721
-
4722
- declare class AXConversationIndexedDbMessageAiApi extends AXConversationIndexedDbMessageApi {
4723
- private readonly aiResponder;
4724
- private readonly AI_TYPING_INDICATOR_DELAY;
4725
- private readonly AI_RESPONSE_DELAY;
4726
- /**
4727
- * Override sendMessage to trigger AI auto-response
4728
- */
4729
- sendMessage(command: AXConversationSendMessageCommand): Promise<AXConversationMessage>;
4730
- /**
4731
- * Extract context from different message types for AI processing
4732
- */
4733
- private extractMessageContext;
4734
- /**
4735
- * Generate AI response to user message
4736
- */
4737
- private generateAIResponse;
4738
- /**
4739
- * Get conversation for AI response
4740
- */
4741
- private getConversationForAI;
4742
- /**
4743
- * Get conversation history (last N messages)
4744
- */
4745
- private getConversationHistory;
4746
- /**
4747
- * Create AI message directly in storage
4748
- */
4749
- private createAIMessage;
4342
+ */
4343
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS: InjectionToken<AXConversationMessageAction[]>;
4344
+ /**
4345
+ * Default composer tabs configuration
4346
+ * Provide this token to override default composer tabs (emoji, stickers, etc.)
4347
+ */
4348
+ declare const AX_CONVERSATION_DEFAULT_COMPOSER_TABS: InjectionToken<AXConversationComposerTab[]>;
4349
+ /**
4350
+ * Default composer actions configuration
4351
+ * Provide this token to override default composer actions (attach, voice, etc.)
4352
+ */
4353
+ declare const AX_CONVERSATION_DEFAULT_COMPOSER_ACTIONS: InjectionToken<AXConversationComposerAction[]>;
4354
+ /**
4355
+ * Default conversation tabs configuration
4356
+ * Provide this token to override default conversation tabs (all, private, groups, etc.)
4357
+ */
4358
+ declare const AX_CONVERSATION_DEFAULT_CONVERSATION_TABS: InjectionToken<AXConversationTab[]>;
4359
+ /**
4360
+ * Default info bar actions configuration
4361
+ * Provide this token to override default info bar actions (mute, archive, block, etc.)
4362
+ */
4363
+ declare const AX_CONVERSATION_DEFAULT_INFO_BAR_ACTIONS: InjectionToken<AXConversationInfoBarAction[]>;
4364
+ /**
4365
+ * Default conversation item actions configuration
4366
+ * Provide this token to override default conversation item actions (mute, delete, archive, etc.)
4367
+ */
4368
+ declare const AX_CONVERSATION_DEFAULT_CONVERSATION_ITEM_ACTIONS: InjectionToken<AXConversationItemAction[]>;
4369
+ /**
4370
+ * Registry configuration interface
4371
+ */
4372
+ interface AXConversationRegistryConfiguration {
4750
4373
  /**
4751
- * Delay helper
4374
+ * Additional message renderers to register (built-in renderers are automatic).
4375
+ * Each {@link AXConversationMessageRenderer} may include optional `composerActions` for co-located send UX.
4752
4376
  */
4753
- private delay;
4754
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbMessageAiApi, never>;
4755
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbMessageAiApi>;
4377
+ messageRenderers?: AXConversationMessageRenderer[];
4378
+ /** Message actions to register by default */
4379
+ messageActions?: AXConversationMessageAction[];
4380
+ /** Composer tabs to register by default */
4381
+ composerTabs?: AXConversationComposerTab[];
4382
+ /** Composer actions to register by default */
4383
+ composerActions?: AXConversationComposerAction[];
4384
+ /** Conversation tabs to register by default */
4385
+ conversationTabs?: AXConversationTab[];
4386
+ /** Info bar actions to register by default */
4387
+ infoBarActions?: AXConversationInfoBarAction[];
4388
+ /** Conversation item actions to register by default */
4389
+ conversationItemActions?: AXConversationItemAction[];
4756
4390
  }
4391
+ /**
4392
+ * Complete registry configuration token
4393
+ * Provide this for comprehensive registry configuration
4394
+ */
4395
+ declare const AX_CONVERSATION_REGISTRY_CONFIG: InjectionToken<AXConversationRegistryConfiguration>;
4757
4396
 
4758
4397
  declare const AX_CONVERSATION_AUDIO_PRESENTATION: {
4759
4398
  readonly icon: "fa-light fa-music text-amber-500";
@@ -4777,7 +4416,10 @@ declare function applyAudioLocalPreview(payload: AXConversationMessagePayload, l
4777
4416
  * Shared upload state and helpers for composer media pickers.
4778
4417
  */
4779
4418
 
4419
+ /** Stable id for `@for` tracking while upload state is patched immutably. */
4420
+ declare function createPickerUploadItemId(): string;
4780
4421
  interface AXConversationComposerPickerUploadItem {
4422
+ id: string;
4781
4423
  file: File;
4782
4424
  preview?: string;
4783
4425
  duration?: number;
@@ -4827,16 +4469,14 @@ declare function notifyPickerValidationErrors(toast: AXToastService, translation
4827
4469
  file: File;
4828
4470
  errors: AXValidationRuleResult[];
4829
4471
  }[]): void;
4830
- /** Load files dropped onto the message list after the picker is mounted in a popup. */
4831
- declare function seedPickerInitialFiles(initialFiles: InputSignal<File[]>, handleFiles: (files: File[]) => void | Promise<void>): void;
4832
- /** Close inline composer shell or popup host after send/cancel. */
4833
- declare function dismissComposerPickerHost(composerService: AXConversationComposerService, popupRef?: AXPopupRef | null): void;
4472
+ /** Close popup/action-sheet host or inline composer shell after send/cancel. */
4473
+ declare function dismissComposerPickerHost(composerService: AXConversationComposerService, popupRef?: AXPopupRef | null, actionSheetRef?: AXActionSheetRef | null): void;
4834
4474
 
4835
4475
  interface AXConversationAudioFile extends AXConversationComposerPickerUploadItem {
4836
4476
  duration?: number;
4837
4477
  dataUrl?: string;
4838
4478
  }
4839
- declare class AXConversationAudioPickerComponent implements OnDestroy {
4479
+ declare class AXConversationAudioPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
4840
4480
  private uploadsDismissed;
4841
4481
  private retainUploadedOnDismiss;
4842
4482
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -4851,16 +4491,20 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4851
4491
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4852
4492
  readonly maxFiles: _angular_core.InputSignal<number>;
4853
4493
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4494
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4854
4495
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4496
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
4855
4497
  readonly catalogFileType: "conversation-audio";
4856
4498
  readonly audioFiles: _angular_core.WritableSignal<AXConversationAudioFile[]>;
4857
4499
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4500
+ private readonly pickerShell;
4858
4501
  readonly typeIconClass: "fa-light fa-music text-amber-500";
4859
4502
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-music text-amber-500" | "fa-light fa-cloud-arrow-up">;
4860
4503
  private catalogFileTypeDef?;
4861
4504
  caption: string;
4862
4505
  readonly allowMultiple: _angular_core.Signal<boolean>;
4863
4506
  constructor();
4507
+ activate(): Promise<void>;
4864
4508
  private createUtilityContext;
4865
4509
  private getCatalogFileTypeDef;
4866
4510
  private runUtility;
@@ -4872,6 +4516,8 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4872
4516
  canSend(): boolean;
4873
4517
  getUploadingLabel(progress: number): string;
4874
4518
  getCancelUploadLabel(): string;
4519
+ getHeaderTitle(): string;
4520
+ onAddMoreFiles(): void;
4875
4521
  cancel(): void;
4876
4522
  ngOnDestroy(): void;
4877
4523
  private dismissPicker;
@@ -4882,11 +4528,13 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4882
4528
  getSelectedCountText(): string;
4883
4529
  getSendText(): string;
4884
4530
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAudioPickerComponent, never>;
4885
- 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>;
4531
+ 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>;
4886
4532
  }
4887
4533
 
4888
4534
  declare const AX_CONVERSATION_COMPOSER_EMOJI_TAB: AXConversationComposerTab;
4889
4535
  declare const AX_CONVERSATION_COMPOSER_STICKER_TAB: AXConversationComposerTab;
4536
+ /** Built-in composer popup tabs keyed by {@link AXConversationComposerTabFeature}. */
4537
+ declare const AX_CONVERSATION_BUILTIN_COMPOSER_TABS: Record<AXConversationComposerTabFeature, AXConversationComposerTab>;
4890
4538
 
4891
4539
  interface AXConversationEmoji {
4892
4540
  char: string;
@@ -4942,20 +4590,16 @@ declare function fileItemFromUpload(file: File, result: AXConversationUploaderRe
4942
4590
  declare function mergeFileUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
4943
4591
  declare function applyFileLocalPreview(payload: AXConversationMessagePayload, localUrl: string, mimeType?: string): AXConversationMessagePayload;
4944
4592
 
4945
- interface AXConversationAttachedFile {
4946
- file: File;
4947
- preview?: string;
4593
+ interface AXConversationPickerFileBadge {
4594
+ ext: string;
4595
+ color: string;
4596
+ }
4597
+
4598
+ interface AXConversationAttachedFile extends AXConversationComposerPickerUploadItem {
4948
4599
  icon: string;
4949
4600
  type: 'image' | 'video' | 'audio' | 'file';
4950
- uploadProgress?: number;
4951
- uploading?: boolean;
4952
- uploaded?: boolean;
4953
- uploadedUrl?: string;
4954
- mediaId?: string;
4955
- error?: string;
4956
- abortController?: AbortController;
4957
4601
  }
4958
- declare class AXConversationFilePickerComponent implements OnDestroy {
4602
+ declare class AXConversationFilePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
4959
4603
  private uploadsDismissed;
4960
4604
  private retainUploadedOnDismiss;
4961
4605
  private readonly uploader;
@@ -4970,16 +4614,20 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
4970
4614
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4971
4615
  readonly maxFiles: _angular_core.InputSignal<number>;
4972
4616
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4617
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4973
4618
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4619
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
4974
4620
  readonly catalogFileType: "conversation-file";
4975
4621
  readonly allowMultiple: _angular_core.Signal<boolean>;
4976
4622
  readonly files: _angular_core.WritableSignal<AXConversationAttachedFile[]>;
4977
4623
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4978
4624
  readonly isUploading: _angular_core.WritableSignal<boolean>;
4625
+ private readonly pickerShell;
4979
4626
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-file text-neutral-500" | "fa-light fa-cloud-arrow-up">;
4980
4627
  private catalogFileTypeDef?;
4981
4628
  caption: string;
4982
4629
  constructor();
4630
+ activate(): Promise<void>;
4983
4631
  private createUtilityContext;
4984
4632
  private getCatalogFileTypeDef;
4985
4633
  private pickerKind;
@@ -4992,6 +4640,9 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
4992
4640
  cancel(): void;
4993
4641
  ngOnDestroy(): void;
4994
4642
  private dismissPicker;
4643
+ getHeaderTitle(): string;
4644
+ getFileBadge(fileName: string): AXConversationPickerFileBadge;
4645
+ onAddMoreFiles(): void;
4995
4646
  getCancelUploadLabel(): string;
4996
4647
  formatFileSize(bytes: number): string;
4997
4648
  canSend(): boolean;
@@ -5001,7 +4652,7 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
5001
4652
  getSelectedCountText(): string;
5002
4653
  getUploadingLabel(progress: number): string;
5003
4654
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationFilePickerComponent, never>;
5004
- 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>;
4655
+ 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>;
5005
4656
  }
5006
4657
 
5007
4658
  declare const AX_CONVERSATION_IMAGE_PRESENTATION: {
@@ -5021,7 +4672,7 @@ declare class AXConversationImageFileTypeProvider extends AXFileTypeInfoProvider
5021
4672
  interface AXConversationImageFile extends AXConversationComposerPickerUploadItem {
5022
4673
  preview: string;
5023
4674
  }
5024
- declare class AXConversationImagePickerComponent implements OnDestroy {
4675
+ declare class AXConversationImagePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5025
4676
  private uploadsDismissed;
5026
4677
  /** Uploaded blobs are referenced by the sent message — do not delete on dismiss. */
5027
4678
  private retainUploadedOnDismiss;
@@ -5038,14 +4689,18 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5038
4689
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5039
4690
  readonly maxFiles: _angular_core.InputSignal<number>;
5040
4691
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4692
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5041
4693
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4694
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5042
4695
  readonly images: _angular_core.WritableSignal<AXConversationImageFile[]>;
4696
+ private readonly pickerShell;
5043
4697
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5044
4698
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-image text-purple-500" | "fa-light fa-cloud-arrow-up">;
5045
4699
  caption: string;
5046
4700
  readonly allowMultiple: _angular_core.Signal<boolean>;
5047
4701
  private imageFileType?;
5048
4702
  constructor();
4703
+ activate(): Promise<void>;
5049
4704
  private createUtilityContext;
5050
4705
  private loadImageFileType;
5051
4706
  handleFiles(files: File[]): Promise<void>;
@@ -5056,6 +4711,8 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5056
4711
  canSend(): boolean;
5057
4712
  getUploadingLabel(progress: number): string;
5058
4713
  getCancelUploadLabel(): string;
4714
+ getHeaderTitle(): string;
4715
+ onAddMoreFiles(): void;
5059
4716
  cancel(): void;
5060
4717
  ngOnDestroy(): void;
5061
4718
  private dismissPicker;
@@ -5064,20 +4721,23 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5064
4721
  getSelectedCountText(): string;
5065
4722
  getSendText(): string;
5066
4723
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationImagePickerComponent, never>;
5067
- 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>;
4724
+ 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>;
5068
4725
  }
5069
4726
 
5070
4727
  declare class AXConversationLocationPickerComponent {
5071
- private readonly composerService;
5072
- private readonly conversationService;
4728
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
4729
+ private readonly composerServiceFromInjector;
4730
+ private get composerService();
5073
4731
  readonly translation: AXTranslationService;
5074
4732
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4733
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4734
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5075
4735
  readonly currentLocation: _angular_core.WritableSignal<AXConversationLocationPayload>;
5076
4736
  onMarkerAdded(event: AXMapMarker): void;
5077
4737
  sendLocation(): Promise<void>;
5078
4738
  cancel(): void;
5079
4739
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationLocationPickerComponent, never>;
5080
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationLocationPickerComponent, "ax-conversation-location-picker", never, { "conversation": { "alias": "conversation"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
4740
+ 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>;
5081
4741
  }
5082
4742
 
5083
4743
  declare class AXConversationPickerFooterComponent {
@@ -5091,9 +4751,12 @@ declare class AXConversationPickerFooterComponent {
5091
4751
 
5092
4752
  declare class AXConversationPickerHeaderComponent {
5093
4753
  readonly title: _angular_core.InputSignal<string>;
4754
+ readonly showMenu: _angular_core.InputSignal<boolean>;
4755
+ readonly addMoreLabel: _angular_core.InputSignal<string>;
5094
4756
  readonly onClose: _angular_core.OutputEmitterRef<void>;
4757
+ readonly onAddMore: _angular_core.OutputEmitterRef<void>;
5095
4758
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerHeaderComponent, never>;
5096
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerHeaderComponent, "ax-conversation-picker-header", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; }, { "onClose": "onClose"; }, never, never, true, never>;
4759
+ 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>;
5097
4760
  }
5098
4761
 
5099
4762
  declare function formatFileSize(bytes: number): string;
@@ -5108,12 +4771,14 @@ declare function resolvePersistableMediaUrl(url: string | undefined): string | u
5108
4771
  /** First non-empty URL for img/video/audio at runtime (includes resolved blob: URLs). */
5109
4772
  declare function pickDisplayMediaUrl(...candidates: (string | null | undefined)[]): string;
5110
4773
 
5111
- /** Optional caption field shared by composer media pickers. */
4774
+ /** Telegram-style caption row with emoji affordance and circular send button. */
5112
4775
  declare class AXConversationPickerCaptionComponent {
5113
4776
  readonly translation: AXTranslationService;
5114
4777
  readonly caption: _angular_core.ModelSignal<string>;
4778
+ readonly sendDisabled: _angular_core.InputSignal<boolean>;
4779
+ readonly onSend: _angular_core.OutputEmitterRef<void>;
5115
4780
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerCaptionComponent, never>;
5116
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerCaptionComponent, "ax-conversation-picker-caption", never, { "caption": { "alias": "caption"; "required": false; "isSignal": true; }; }, { "caption": "captionChange"; }, never, never, true, never>;
4781
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerCaptionComponent, "ax-conversation-picker-caption", never, { "caption": { "alias": "caption"; "required": false; "isSignal": true; }; "sendDisabled": { "alias": "sendDisabled"; "required": false; "isSignal": true; }; }, { "caption": "captionChange"; "onSend": "onSend"; }, never, never, true, never>;
5117
4782
  }
5118
4783
 
5119
4784
  /** Shared drag-and-drop handlers for composer pickers. */
@@ -5135,29 +4800,21 @@ declare class AXConversationPickerEmptyComponent {
5135
4800
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationPickerEmptyComponent, "ax-conversation-picker-empty", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "hint": { "alias": "hint"; "required": true; "isSignal": true; }; "iconClass": { "alias": "iconClass"; "required": true; "isSignal": true; }; "dragOver": { "alias": "dragOver"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5136
4801
  }
5137
4802
 
5138
- /**
5139
- * Shell flex + max-height (on {@link AXConversationPickerShellComponent}).
5140
- * Styles here target projected content inside the shell.
5141
- */
5142
- declare const AX_CONVERSATION_PICKER_SHELL_STYLES = "\n :host {\n display: block;\n width: 100%;\n max-width: 100%;\n min-height: 0;\n container-type: inline-size;\n container-name: picker;\n }\n\n .ax-conversation-picker {\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 100%;\n max-height: min(32rem, 85dvh);\n background: rgb(var(--ax-sys-color-lightest-surface));\n border-radius: var(--ax-sys-border-radius, 0.5rem);\n overflow: hidden;\n }\n\n .ax-conversation-picker__content {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n }\n\n @container picker (max-width: 480px) {\n .ax-conversation-picker {\n max-height: min(28rem, 90dvh);\n border-radius: 0;\n }\n }\n";
5143
- /**
5144
- * Shared layout and surface styles for composer media pickers.
5145
- * Uses ACoreX system color tokens only.
5146
- */
5147
- declare const AX_CONVERSATION_PICKER_SHARED_STYLES = "\n :host {\n display: block;\n width: 100%;\n max-width: 100%;\n min-height: 0;\n }\n\n .ax-conversation-picker__scroll {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n -webkit-overflow-scrolling: touch;\n }\n\n .ax-conversation-picker__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n min-height: 8.5rem;\n margin: 0.75rem;\n padding: 1rem 0.75rem;\n border: 1px dashed rgb(var(--ax-sys-color-border-surface));\n border-radius: var(--ax-sys-border-radius, 0.5rem);\n cursor: pointer;\n transition: border-color 0.15s ease, background-color 0.15s ease;\n text-align: center;\n touch-action: manipulation;\n }\n\n .ax-conversation-picker__empty:hover,\n .ax-conversation-picker__empty--drag {\n border-color: rgb(var(--ax-sys-color-primary-500));\n background: rgba(var(--ax-sys-color-primary-500), 0.06);\n }\n\n .ax-conversation-picker__empty-icon {\n font-size: 1.75rem;\n line-height: 1;\n color: rgba(var(--ax-sys-color-on-surface), 0.55);\n }\n\n .ax-conversation-picker__empty-title {\n margin: 0;\n font-size: 0.8125rem;\n font-weight: 600;\n color: rgb(var(--ax-sys-color-on-surface));\n }\n\n .ax-conversation-picker__empty-hint {\n margin: 0;\n font-size: 0.75rem;\n color: rgba(var(--ax-sys-color-on-surface), 0.6);\n }\n\n .ax-conversation-picker__body {\n padding: 0 0.75rem 0.75rem;\n }\n\n .ax-conversation-picker__list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding-top: 0.5rem;\n }\n\n .ax-conversation-picker__row {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.5rem 0.625rem;\n border: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n border-radius: var(--ax-sys-border-radius, 0.375rem);\n background: rgb(var(--ax-sys-color-surface));\n transition: background-color 0.15s ease;\n }\n\n @media (hover: hover) {\n .ax-conversation-picker__row:hover {\n background: rgb(var(--ax-sys-color-light-surface));\n }\n }\n\n .ax-conversation-picker__thumb {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n flex-shrink: 0;\n border-radius: var(--ax-sys-border-radius, 0.375rem);\n background: rgba(var(--ax-sys-color-primary-500), 0.08);\n color: rgb(var(--ax-sys-color-primary-500));\n font-size: 1.125rem;\n overflow: hidden;\n }\n\n .ax-conversation-picker__thumb img,\n .ax-conversation-picker__thumb video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n pointer-events: none;\n }\n\n .ax-conversation-picker__thumb-badge {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgb(0 0 0 / 0.32);\n color: rgb(var(--ax-sys-color-light));\n font-size: 0.625rem;\n pointer-events: none;\n }\n\n .ax-conversation-picker__details {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n }\n\n .ax-conversation-picker__name {\n font-size: 0.8125rem;\n font-weight: 500;\n color: rgb(var(--ax-sys-color-on-surface));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ax-conversation-picker__status {\n display: flex;\n flex-wrap: wrap;\n gap: 0.375rem;\n font-size: 0.6875rem;\n color: rgba(var(--ax-sys-color-on-surface), 0.65);\n }\n\n .ax-conversation-picker__status--ok {\n color: rgb(var(--ax-sys-color-success-600));\n font-weight: 500;\n }\n\n .ax-conversation-picker__status--err {\n color: rgb(var(--ax-sys-color-danger-600));\n font-weight: 500;\n }\n\n .ax-conversation-picker__progress {\n width: 100%;\n margin-top: 0.125rem;\n }\n\n .ax-conversation-picker__remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n flex-shrink: 0;\n border: none;\n border-radius: var(--ax-sys-border-radius, 0.25rem);\n background: transparent;\n color: rgba(var(--ax-sys-color-on-surface), 0.55);\n font-size: 1rem;\n cursor: pointer;\n touch-action: manipulation;\n transition: background-color 0.15s ease, color 0.15s ease;\n }\n\n .ax-conversation-picker__remove:hover,\n .ax-conversation-picker__remove:focus-visible {\n background: rgba(var(--ax-sys-color-danger-500), 0.1);\n color: rgb(var(--ax-sys-color-danger-500));\n outline: none;\n }\n\n .ax-conversation-picker__grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(5.25rem, 1fr));\n gap: 0.5rem;\n }\n\n .ax-conversation-picker__tile {\n position: relative;\n aspect-ratio: 1;\n border-radius: var(--ax-sys-border-radius, 0.375rem);\n overflow: hidden;\n border: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n background: rgb(var(--ax-sys-color-light-surface));\n }\n\n .ax-conversation-picker__tile img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n\n .ax-conversation-picker__tile-remove {\n position: absolute;\n top: 0.25rem;\n inset-inline-end: 0.25rem;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border: none;\n border-radius: 50%;\n background: rgb(var(--ax-sys-color-danger-500));\n color: rgb(var(--ax-sys-color-light));\n font-size: 0.6875rem;\n cursor: pointer;\n touch-action: manipulation;\n box-shadow: 0 1px 3px rgb(0 0 0 / 0.2);\n }\n\n .ax-conversation-picker__tile-overlay {\n position: absolute;\n inset-inline: 0;\n bottom: 0;\n padding: 0.25rem;\n background: linear-gradient(transparent, rgb(0 0 0 / 0.55));\n }\n\n .ax-conversation-picker__tile-status {\n font-size: 0.625rem;\n color: rgb(var(--ax-sys-color-light));\n line-height: 1.2;\n }\n\n .ax-conversation-picker__caption-slot {\n flex-shrink: 0;\n padding: 0.5rem 0.75rem;\n border-top: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n background: rgb(var(--ax-sys-color-lightest-surface));\n }\n\n .ax-conversation-picker__input-hidden {\n display: none;\n }\n\n @container picker (max-width: 480px) {\n .ax-conversation-picker__grid {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.375rem;\n }\n\n .ax-conversation-picker__row {\n padding: 0.4375rem 0.5rem;\n gap: 0.5rem;\n }\n\n .ax-conversation-picker__thumb {\n width: 2.25rem;\n height: 2.25rem;\n }\n\n .ax-conversation-picker__empty {\n min-height: 7.5rem;\n margin: 0.5rem;\n }\n\n .ax-conversation-picker__body {\n padding-inline: 0.5rem;\n padding-bottom: 0.5rem;\n }\n }\n";
5148
-
5149
4803
  /**
5150
4804
  * Wraps composer pickers with {@link AXUploaderZoneDirective} for browse, drop, and validation.
5151
4805
  */
5152
4806
  declare class AXConversationPickerShellComponent {
5153
4807
  private readonly toast;
5154
4808
  private readonly translation;
4809
+ private readonly zone;
5155
4810
  readonly fileType: _angular_core.InputSignal<string>;
5156
4811
  readonly multiple: _angular_core.InputSignal<boolean>;
5157
4812
  readonly filesSelected: _angular_core.OutputEmitterRef<File[]>;
5158
4813
  readonly dragEnter: _angular_core.OutputEmitterRef<DragEvent>;
5159
4814
  readonly dragLeave: _angular_core.OutputEmitterRef<DragEvent>;
5160
4815
  readonly dragOver: _angular_core.OutputEmitterRef<DragEvent>;
4816
+ /** Open the OS file picker for this shell's catalog. */
4817
+ browse(): Promise<void>;
5161
4818
  protected onZoneFileChange(event: AXUploaderFileChangeEvent): void;
5162
4819
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerShellComponent, never>;
5163
4820
  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>;
@@ -5227,7 +4884,7 @@ interface AXConversationVideoFile extends AXConversationComposerPickerUploadItem
5227
4884
  preview?: string;
5228
4885
  duration?: number;
5229
4886
  }
5230
- declare class AXConversationVideoPickerComponent implements OnDestroy {
4887
+ declare class AXConversationVideoPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5231
4888
  private uploadsDismissed;
5232
4889
  private retainUploadedOnDismiss;
5233
4890
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -5242,16 +4899,20 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5242
4899
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5243
4900
  readonly maxFiles: _angular_core.InputSignal<number>;
5244
4901
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4902
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5245
4903
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4904
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5246
4905
  readonly catalogFileType: "conversation-video";
5247
4906
  readonly videos: _angular_core.WritableSignal<AXConversationVideoFile[]>;
5248
4907
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4908
+ private readonly pickerShell;
5249
4909
  caption: string;
5250
4910
  readonly allowMultiple: _angular_core.Signal<boolean>;
5251
4911
  readonly typeIconClass: "fa-light fa-video ax-text-blue-500";
5252
4912
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-video ax-text-blue-500" | "fa-light fa-cloud-arrow-up">;
5253
4913
  private catalogFileTypeDef?;
5254
4914
  constructor();
4915
+ activate(): Promise<void>;
5255
4916
  private createUtilityContext;
5256
4917
  private getCatalogFileTypeDef;
5257
4918
  private runUtility;
@@ -5263,6 +4924,8 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5263
4924
  canSend(): boolean;
5264
4925
  getUploadingLabel(progress: number): string;
5265
4926
  getCancelUploadLabel(): string;
4927
+ getHeaderTitle(): string;
4928
+ onAddMoreFiles(): void;
5266
4929
  cancel(): void;
5267
4930
  ngOnDestroy(): void;
5268
4931
  private dismissPicker;
@@ -5273,7 +4936,7 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5273
4936
  getSelectedCountText(): string;
5274
4937
  getSendText(): string;
5275
4938
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationVideoPickerComponent, never>;
5276
- 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>;
4939
+ 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>;
5277
4940
  }
5278
4941
 
5279
4942
  declare const AX_CONVERSATION_VOICE_PRESENTATION: {
@@ -5293,14 +4956,21 @@ declare class AXConversationVoiceFileTypeProvider extends AXFileTypeInfoProvider
5293
4956
  declare function mergeVoiceUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
5294
4957
  declare function applyVoiceLocalPreview(payload: AXConversationMessagePayload, localUrl: string): AXConversationMessagePayload;
5295
4958
 
5296
- declare class AXConversationVoiceRecorderComponent {
4959
+ declare class AXConversationVoiceRecorderComponent implements AXConversationComposerActionComponent {
5297
4960
  private readonly platformId;
5298
4961
  private readonly destroyRef;
5299
- private readonly composerService;
4962
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
4963
+ private readonly composerServiceFromInjector;
4964
+ private get composerService();
5300
4965
  private readonly uploader;
4966
+ private readonly fileTypeRegistry;
5301
4967
  private readonly toast;
5302
4968
  readonly translation: AXTranslationService;
5303
4969
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4970
+ readonly initialFiles: _angular_core.InputSignal<File[]>;
4971
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4972
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4973
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5304
4974
  readonly recordingComplete: _angular_core.OutputEmitterRef<Blob>;
5305
4975
  readonly recordingCancelled: _angular_core.OutputEmitterRef<void>;
5306
4976
  readonly isRecording: _angular_core.WritableSignal<boolean>;
@@ -5316,7 +4986,9 @@ declare class AXConversationVoiceRecorderComponent {
5316
4986
  private uploadAbortController?;
5317
4987
  readonly formattedTime: _angular_core.Signal<string>;
5318
4988
  constructor();
4989
+ activate(): Promise<void>;
5319
4990
  startRecording(): Promise<void>;
4991
+ private dismissHost;
5320
4992
  /** Stop recording and send */
5321
4993
  stopRecording(): void;
5322
4994
  cancelRecording(): void;
@@ -5330,7 +5002,7 @@ declare class AXConversationVoiceRecorderComponent {
5330
5002
  private sendVoiceMessage;
5331
5003
  private stopAndCleanup;
5332
5004
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationVoiceRecorderComponent, never>;
5333
- 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>;
5005
+ 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>;
5334
5006
  }
5335
5007
 
5336
5008
  declare const AX_CONVERSATION_COMPOSER_EMOJI_ACTION: AXConversationComposerAction;
@@ -5349,13 +5021,17 @@ declare const AX_CONVERSATION_COMPOSER_LOCATION_ACTION: AXConversationComposerAc
5349
5021
 
5350
5022
  /** Ensures built-in conversation catalogs exist on the root file-type registry. */
5351
5023
  declare const AX_CONVERSATION_FILE_TYPES_READY: InjectionToken<boolean>;
5352
- /** Registers validation rules and lazy conversation file-type catalogs for enabled pickers. */
5353
- declare function provideConversationComposerFileTypes(_features?: AXConversationFeatures): Provider[];
5024
+ /** Registers validation rules and lazy conversation file-type catalogs for composer actions. */
5025
+ declare function provideConversationComposerFileTypes(): Provider[];
5354
5026
 
5355
- /** Lazy-loads conversation file catalogs only for enabled media pickers. */
5027
+ /** Ensure a built-in conversation catalog is registered before pre-overlay file selection. */
5028
+ declare function ensureConversationFileCatalogRegistered(registry: AXFileTypeRegistryService, catalogName: string): Promise<void>;
5029
+ /**
5030
+ * Lazy-loads conversation file catalogs for the root file-type registry.
5031
+ * Must not inject {@link AXConversationComposerActionRegistry} — that registry
5032
+ * depends on {@link AXFileTypeRegistryService}, which would create a circular DI cycle.
5033
+ */
5356
5034
  declare class AXConversationComposerFileTypesProvider extends AXFileTypeInfoProvider {
5357
- private readonly config;
5358
- private cache;
5359
5035
  items(): Promise<AXFileType[]>;
5360
5036
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerFileTypesProvider, never>;
5361
5037
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationComposerFileTypesProvider>;
@@ -5370,149 +5046,12 @@ declare function createLocalPreviewUrl(fileService: AXFileService, platformId: o
5370
5046
 
5371
5047
  declare function resolveComposerMaxFiles(action: Pick<AXConversationComposerAction, 'maxFiles'> | undefined, config: Pick<Required<AXConversationConfig>, 'maxFilesPerMessage'>): number;
5372
5048
 
5373
- interface AXConversationInfoProfileField {
5374
- id: string;
5375
- labelKey: string;
5376
- value: string;
5377
- icon: string;
5378
- }
5379
- type AXConversationMediaCategoryId = 'image' | 'video' | 'file' | 'audio' | 'voice' | 'sticker' | 'location' | 'link';
5380
- interface AXConversationMediaCategory {
5381
- id: AXConversationMediaCategoryId;
5382
- labelKey: string;
5383
- countLabelKey: string;
5384
- icon: string;
5385
- count: number;
5386
- }
5387
- declare function messageContainsLink(message: AXConversationMessage): boolean;
5388
- declare function getPrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
5389
- declare function getConversationProfileFields(conversation: AXConversation, currentUserId?: string): AXConversationInfoProfileField[];
5390
- declare function getConversationMediaCategories(messages: AXConversationMessage[]): AXConversationMediaCategory[];
5391
- declare function filterMessagesByMediaCategory(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMessage[];
5392
- declare function isGridMediaCategory(categoryId: AXConversationMediaCategoryId): boolean;
5393
- declare function isAttachmentListCategory(categoryId: AXConversationMediaCategoryId): boolean;
5394
- interface AXConversationMediaGalleryTile {
5395
- key: string;
5396
- message: AXConversationMessage;
5397
- kind: 'image' | 'video' | 'sticker';
5398
- image?: AXConversationImageMediaItem;
5399
- video?: AXConversationVideoMediaItem;
5400
- stickerUrl?: string;
5401
- stickerAlt?: string;
5402
- }
5403
- declare function buildMediaGalleryTiles(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMediaGalleryTile[];
5404
- declare function resolveVideoThumbnailUrl(video: AXConversationVideoMediaItem): string | undefined;
5405
- declare function resolveGalleryImageUrl(image: AXConversationImageMediaItem): string | undefined;
5406
- declare function getMessageVideoItems(message: AXConversationMessage): AXConversationVideoMediaItem[];
5407
- declare function getMessageAudioItems(message: AXConversationMessage): AXConversationAudioMediaItem[];
5408
- declare function fetchAllConversationMessages(messageApi: AXConversationMessageApi, conversationId: string, pageSize: number): Promise<AXConversationMessage[]>;
5409
-
5410
- interface AXInfoPanelQuickAction {
5411
- id: string;
5412
- labelKey: string;
5413
- icon: string;
5414
- danger?: boolean;
5415
- }
5416
- declare class AXConversationInfoPanelComponent extends AXClosableComponent implements OnInit, OnDestroy {
5417
- private readonly toastService;
5418
- readonly translation: AXTranslationService;
5419
- private readonly injectedConversationService;
5420
- readonly onClosed: _angular_core.OutputEmitterRef<AXComponentCloseEvent>;
5421
- conversation: AXConversation;
5422
- conversationService: AXConversationService;
5423
- readonly activeTab: _angular_core.WritableSignal<"profile" | "manage">;
5424
- readonly showMemberSearch: _angular_core.WritableSignal<boolean>;
5425
- readonly panelView: _angular_core.WritableSignal<"main" | "media">;
5426
- readonly selectedMediaCategory: _angular_core.WritableSignal<AXConversationMediaCategory>;
5427
- readonly mediaViewLoader: () => Promise<typeof _acorex_components_conversation.AXConversationInfoMediaViewComponent>;
5428
- readonly conversationMessages: _angular_core.WritableSignal<AXConversationMessage[]>;
5429
- readonly loadingMessages: _angular_core.WritableSignal<boolean>;
5430
- readonly memberSearchQuery: _angular_core.WritableSignal<string>;
5431
- archived: boolean;
5432
- private initialNotifications;
5433
- private initialArchived;
5434
- editTitle: string;
5435
- editAvatar: string;
5436
- private groupTitleSaveTimer;
5437
- private groupDetailsSaveInFlight;
5438
- readonly backgroundPresets: Array<{
5439
- id: string;
5440
- label: string;
5441
- value: string;
5442
- }>;
5443
- readonly heroSubtitle: _angular_core.Signal<string>;
5444
- readonly liveConversation: _angular_core.Signal<AXConversation>;
5445
- readonly isConversationMuted: _angular_core.Signal<boolean>;
5446
- readonly profileFields: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoProfileField[]>;
5447
- readonly mediaCategories: _angular_core.Signal<AXConversationMediaCategory[]>;
5448
- readonly quickActions: _angular_core.Signal<AXInfoPanelQuickAction[]>;
5449
- readonly filteredMembers: _angular_core.Signal<AXConversationParticipant[]>;
5450
- ngOnInit(): void;
5451
- private loadConversationMessages;
5452
- isPrivateConversation(): boolean;
5453
- isGroupConversation(): boolean;
5454
- membersSectionTitle(): string;
5455
- getMemberRoleLabel(participant: AXConversationParticipant): string | null;
5456
- onMemberSearchChange(value: string | null | undefined): void;
5457
- setActiveTab(tab: 'profile' | 'manage'): void;
5458
- toggleMemberSearch(): void;
5459
- openMediaCategory(category: AXConversationMediaCategory): void;
5460
- closeMediaView(): void;
5461
- getMediaViewInputs(category: AXConversationMediaCategory): Record<string, unknown>;
5462
- getMediaRowLabel(category: AXConversationMediaCategory): string;
5463
- getMemberSubtitle(participant: AXConversationParticipant): string;
5464
- onQuickAction(actionId: string): void;
5465
- toggleConversationMute(): Promise<void>;
5466
- onNotificationsChange(value: boolean): Promise<void>;
5467
- onArchivedChange(value: boolean): Promise<void>;
5468
- close(data?: unknown): void;
5469
- closeAll(): void;
5470
- onLeave(): Promise<void>;
5471
- onGroupTitleChange(value: string): void;
5472
- onGroupAvatarChange(value: string): void;
5473
- private persistGroupDetails;
5474
- isBackgroundSelected(value: string): boolean;
5475
- applyMessageListBackground(value: string): Promise<void>;
5476
- getBackgroundAriaLabel(label: string): string;
5477
- ngOnDestroy(): void;
5478
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoPanelComponent, never>;
5479
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationInfoPanelComponent, "ax-conversation-info-panel", never, {}, { "onClosed": "onClosed"; }, never, never, true, never>;
5480
- }
5481
-
5482
- declare class AXConversationInfoMediaViewComponent {
5483
- private readonly translation;
5484
- private readonly parentInjector;
5485
- readonly category: _angular_core.InputSignal<AXConversationMediaCategory>;
5486
- readonly messages: _angular_core.InputSignal<AXConversationMessage[]>;
5487
- readonly conversation: _angular_core.InputSignal<AXConversation>;
5488
- readonly conversationServiceInput: _angular_core.InputSignal<AXConversationService>;
5489
- /** Callback for lazy outlet wiring (alternative to the `back` output). */
5490
- readonly onBack: _angular_core.InputSignal<() => void>;
5491
- readonly back: _angular_core.OutputEmitterRef<void>;
5492
- readonly items: _angular_core.Signal<AXConversationMessage[]>;
5493
- readonly isGrid: _angular_core.Signal<boolean>;
5494
- readonly isAttachmentList: _angular_core.Signal<boolean>;
5495
- readonly galleryTiles: _angular_core.Signal<_acorex_components_conversation.AXConversationMediaGalleryTile[]>;
5496
- readonly rendererInjector: _angular_core.Signal<_angular_core.DestroyableInjector>;
5497
- readonly titleLabel: _angular_core.Signal<string>;
5498
- readonly getMessageVideoItems: typeof getMessageVideoItems;
5499
- readonly getMessageAudioItems: typeof getMessageAudioItems;
5500
- getRendererComponent(message: AXConversationMessage): _angular_core.Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
5501
- getRendererComponentLoader(message: AXConversationMessage): (() => Promise<_angular_core.Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
5502
- getRendererInputs(message: AXConversationMessage): {
5503
- message: AXConversationMessage;
5504
- };
5505
- formatTimestamp(message: AXConversationMessage): string;
5506
- handleBack(): void;
5507
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationInfoMediaViewComponent, never>;
5508
- 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; }; "onBack": { "alias": "onBack"; "required": false; "isSignal": true; }; }, { "back": "back"; }, never, never, true, never>;
5509
- }
5510
-
5511
5049
  declare class AXConversationInfoBarSearchComponent {
5512
5050
  private readonly platformId;
5513
5051
  private readonly destroyRef;
5514
5052
  private readonly infoBarService;
5515
5053
  private readonly conversationService;
5054
+ private readonly config;
5516
5055
  /** Conversation input */
5517
5056
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5518
5057
  /** Service input */
@@ -5523,13 +5062,14 @@ declare class AXConversationInfoBarSearchComponent {
5523
5062
  readonly resultsCount: _angular_core.Signal<number>;
5524
5063
  /** Current index from service */
5525
5064
  readonly currentIndex: _angular_core.Signal<number>;
5526
- /** Messages from conversation */
5527
- readonly messages: _angular_core.Signal<_acorex_components_conversation.AXConversationMessage[]>;
5065
+ private readonly searchResults;
5066
+ private searchDebounceTimer?;
5528
5067
  private scrollTimer?;
5068
+ private searchRequestId;
5529
5069
  constructor();
5530
5070
  /** Handle search input change */
5531
5071
  onSearchChange(value: string): void;
5532
- /** Perform search in messages */
5072
+ /** Perform server-side search in messages */
5533
5073
  private performSearch;
5534
5074
  /** Navigate to next result */
5535
5075
  onNext(): void;
@@ -5548,7 +5088,7 @@ declare class AXConversationInfoBarSearchComponent {
5548
5088
  */
5549
5089
 
5550
5090
  /**
5551
- * Search in conversation action (inline)
5091
+ * Search in conversation action (inline on desktop, menu on mobile)
5552
5092
  */
5553
5093
  declare const AX_CONVERSATION_INFO_BAR_SEARCH_ACTION: AXConversationInfoBarAction;
5554
5094
  /**
@@ -5734,11 +5274,6 @@ declare function syncPlaybackInfoBarBanner(infoBar: AXConversationInfoBarService
5734
5274
  forceOpen?: boolean;
5735
5275
  }): void;
5736
5276
 
5737
- /**
5738
- * Shared layout tokens for conversation message renderers.
5739
- */
5740
- declare const AX_CONVERSATION_RENDERER_SHARED_STYLES = "\n :host {\n display: block;\n max-width: 100%;\n }\n\n .ax-conversation-msg {\n display: flex;\n flex-direction: column;\n gap: 0.375rem;\n }\n\n .ax-conversation-msg__stack {\n display: flex;\n flex-direction: column;\n gap: 0.375rem;\n }\n\n .ax-conversation-msg__grid {\n display: grid;\n gap: 2px;\n width: 100%;\n border-radius: var(--ax-sys-border-radius, 0.5rem);\n overflow: hidden;\n background: rgb(var(--ax-sys-color-border-light-surface));\n }\n\n .ax-conversation-msg__grid--single {\n grid-template-columns: 1fr;\n }\n\n .ax-conversation-msg__grid--single ::ng-deep .ax-conversation-image-attachment {\n max-height: min(50dvh, 20rem);\n }\n\n .ax-conversation-msg__grid--dual {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .ax-conversation-msg__grid--multi {\n grid-template-columns: repeat(3, 1fr);\n grid-auto-rows: 10rem;\n }\n\n @container (max-width: 380px) {\n .ax-conversation-msg__grid--multi {\n grid-template-columns: repeat(2, 1fr);\n grid-auto-rows: 10rem;\n }\n }\n\n .ax-conversation-msg__caption {\n margin: 0;\n padding: 0 0.125rem;\n font-size: 0.8125rem;\n line-height: 1.4;\n word-break: break-word;\n opacity: 0.88;\n }\n\n /* Flush layout: media fills the message bubble edge-to-edge (image / video). */\n .ax-conversation-msg--flush {\n width: 100%;\n max-width: 100%;\n gap: 0;\n }\n\n .ax-conversation-msg--flush .ax-conversation-msg__caption {\n padding: 0.375rem 0.625rem 0;\n }\n\n .ax-conversation-msg--flush .ax-conversation-msg__grid {\n border-radius: 0;\n background: transparent;\n }\n\n .ax-conversation-msg--flush .ax-conversation-msg__stack {\n gap: 2px;\n }\n\n .ax-conversation-msg--flush ::ng-deep .ax-conversation-video {\n border-radius: 0;\n }\n\n .ax-conversation-msg__card {\n border-radius: var(--ax-sys-border-radius, 0.5rem);\n border: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n background: rgb(var(--ax-sys-color-surface));\n overflow: hidden;\n }\n";
5741
-
5742
5277
  declare class AXConversationVideoAttachmentComponent {
5743
5278
  readonly item: _angular_core.InputSignal<AXConversationVideoMediaItem>;
5744
5279
  readonly playingChange: _angular_core.OutputEmitterRef<boolean>;
@@ -6028,14 +5563,6 @@ declare const AX_CONVERSATION_MESSAGE_DELETE_ACTION: AXConversationMessageAction
6028
5563
  */
6029
5564
  declare const AX_CONVERSATION_MESSAGE_FORWARD_ACTION: AXConversationMessageAction;
6030
5565
 
6031
- /** Normalize payload; loads media normalizers on demand. */
6032
- declare function normalizeMessagePayloadAsync(payload: AXConversationMessagePayload): Promise<AXConversationMessagePayload>;
6033
- /**
6034
- * Sync normalize — uses cached normalizers when available.
6035
- * Media payloads pass through until a normalizer chunk has loaded (renderers normalize on display).
6036
- */
6037
- declare function normalizeMessagePayload(payload: AXConversationMessagePayload): AXConversationMessagePayload;
6038
-
6039
5566
  declare const AX_CONVERSATION_TEXT_RENDERER: AXConversationMessageRenderer;
6040
5567
 
6041
5568
  declare const AX_CONVERSATION_IMAGE_RENDERER: AXConversationMessageRenderer;
@@ -6101,6 +5628,29 @@ declare const AX_CONVERSATION_TAB_BOT: AXConversationTab;
6101
5628
  declare const AX_CONVERSATION_TAB_UNREAD: AXConversationTab;
6102
5629
  declare const AX_CONVERSATION_TAB_ARCHIVED: AXConversationTab;
6103
5630
 
5631
+ declare class AXConversationDefaultConversationAvatarComponent {
5632
+ private readonly conversationService;
5633
+ private readonly userAvatarComponent;
5634
+ readonly conversationId: _angular_core.InputSignal<string>;
5635
+ readonly size: _angular_core.InputSignal<number>;
5636
+ private readonly currentUserId;
5637
+ private readonly conversation;
5638
+ readonly peerUserId: _angular_core.Signal<string>;
5639
+ readonly useUserAvatar: _angular_core.Signal<_angular_core.Type<_acorex_components_conversation.AXConversationUserAvatarComponent>>;
5640
+ readonly userAvatarInputs: _angular_core.Signal<{
5641
+ userId: string;
5642
+ size: number;
5643
+ displayName: string;
5644
+ displayAvatar: string;
5645
+ displayIcon: string;
5646
+ }>;
5647
+ readonly filteredUserAvatarInputs: _angular_core.Signal<Record<string, unknown>>;
5648
+ readonly fallbackDisplay: _angular_core.Signal<_acorex_components_conversation.AXConversationAvatarDisplay>;
5649
+ readonly fallbackInitials: _angular_core.Signal<string>;
5650
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationDefaultConversationAvatarComponent, never>;
5651
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationDefaultConversationAvatarComponent, "ax-conversation-default-conversation-avatar", never, { "conversationId": { "alias": "conversationId"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5652
+ }
5653
+
6104
5654
  /**
6105
5655
  * Configuration options for conversation module
6106
5656
  */
@@ -6132,7 +5682,7 @@ declare class AXConversationModule {
6132
5682
  */
6133
5683
  static forChild(options?: Omit<AXConversationOptions, 'userApi' | 'conversationApi' | 'messageApi' | 'realtimeApi'>): ModuleWithProviders<AXConversationModule>;
6134
5684
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationModule, never>;
6135
- static ɵmod: _angular_core.ɵɵNgModuleDeclaration<AXConversationModule, never, [typeof i1.CommonModule, typeof i2.FormsModule, typeof AXConversationContainerComponent, typeof AXConversationSidebarComponent, typeof AXConversationInfoBarComponent, typeof AXConversationMessageListComponent, typeof AXConversationComposerComponent, typeof AXConversationInfiniteScrollDirective], [typeof AXConversationContainerComponent, typeof AXConversationSidebarComponent, typeof AXConversationInfoBarComponent, typeof AXConversationMessageListComponent, typeof AXConversationComposerComponent, typeof AXConversationInfiniteScrollDirective]>;
5685
+ static ɵmod: _angular_core.ɵɵNgModuleDeclaration<AXConversationModule, never, [typeof i1.CommonModule, typeof i2.FormsModule, typeof AXConversationContainerComponent, typeof AXConversationSidebarComponent, typeof AXConversationInfoBarComponent, typeof AXConversationMessageListComponent, typeof AXConversationComposerComponent, typeof AXConversationInfiniteScrollDirective, typeof AXConversationDefaultConversationAvatarComponent], [typeof AXConversationContainerComponent, typeof AXConversationSidebarComponent, typeof AXConversationInfoBarComponent, typeof AXConversationMessageListComponent, typeof AXConversationComposerComponent, typeof AXConversationInfiniteScrollDirective]>;
6136
5686
  static ɵinj: _angular_core.ɵɵInjectorDeclaration<AXConversationModule>;
6137
5687
  }
6138
5688
  /**
@@ -6169,27 +5719,71 @@ interface AXConversationAvatarDisplay {
6169
5719
  avatar?: string;
6170
5720
  icon?: string;
6171
5721
  }
5722
+ /** Conversation types that resolve a single peer participant for viewer-scoped avatar/title. */
5723
+ declare const AX_CONVERSATION_PEER_AVATAR_TYPES: ReadonlySet<AXConversationType>;
5724
+ /**
5725
+ * Other participant in a peer-scoped conversation (excludes the current viewer).
5726
+ * Applies to private 1:1 and bot assist chats with exactly one non-viewer participant.
5727
+ */
5728
+ declare function resolveConversationPeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6172
5729
  /** Other participant in a private chat (excludes the current user). */
6173
5730
  declare function resolvePrivatePeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6174
- /** Whether `auto` kind should render a user avatar for this conversation. */
5731
+ /** Peer participant for private and bot conversations. */
5732
+ declare function resolveConversationPeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
5733
+ /** Whether `auto` kind should render a registered user avatar for this conversation. */
6175
5734
  declare function shouldUseUserAvatarForConversation(conversation: AXConversation, currentUserId?: string): boolean;
6176
5735
  declare function resolveUserAvatarDisplay(userId: string, conversation: AXConversation | undefined, message?: AXConversationMessage): AXConversationAvatarDisplay;
6177
5736
  declare function resolveConversationAvatarDisplay(conversation: AXConversation, currentUserId?: string): AXConversationAvatarDisplay;
6178
5737
 
5738
+ interface AXConversationMessageListBackgroundPreset {
5739
+ id: string;
5740
+ value: AXConversationMessageListThemeBackground;
5741
+ }
5742
+ /** Library default when no per-conversation or global background is set (pattern-5 tile + gradient wash). */
5743
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND: AXConversationMessageListThemeBackground;
5744
+ /** Predefined chat-area backgrounds for the info panel (light + dark variants). */
5745
+ declare const AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS: AXConversationMessageListBackgroundPreset[];
5746
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID = "solid-default";
5747
+
5748
+ /** Subtle Telegram-style chat-area wash when `messageListBackground` is not set (theme-aware). */
5749
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND: string;
5750
+ declare function isMessageListThemeBackground(value: unknown): value is AXConversationMessageListThemeBackground;
5751
+ /** Pick the raw CSS string for the active theme; `undefined` when unset. */
5752
+ declare function resolveMessageListBackgroundRaw(value: AXConversationMessageListBackground | undefined, isDark: boolean): string | undefined;
5753
+ /** Turn bare `https://...` or `/path` into valid CSS `background` for images. */
5754
+ declare function normalizeMessageListBackgroundValue(raw: string): string;
5755
+ /** Whether the built-in pattern-5 wallpaper (gradient + tiled SVG) should be used. */
5756
+ declare function usesDefaultMessageListWallpaper(value: AXConversationMessageListBackground | undefined): boolean;
5757
+ /** Resolve config/metadata background for the active theme, with library default fallback. */
5758
+ declare function resolveMessageListBackgroundStyle(value: AXConversationMessageListBackground | undefined, isDark: boolean): string;
5759
+ /** Whether two stored backgrounds represent the same preset (supports legacy string values). */
5760
+ declare function isSameMessageListBackground(a: AXConversationMessageListBackground | undefined, b: AXConversationMessageListThemeBackground, isDark: boolean): boolean;
5761
+
5762
+ /** Default Font Awesome icon for group conversations without a custom avatar image. */
5763
+ declare const AX_CONVERSATION_DEFAULT_GROUP_ICON = "fa-light fa-users";
5764
+ /** Default Font Awesome icon for private/bot conversations without a custom avatar image. */
5765
+ declare const AX_CONVERSATION_DEFAULT_USER_ICON = "fa-light fa-user";
6179
5766
  /** True when the stored title is a placeholder, not a user-defined name. */
6180
5767
  declare function isGenericPrivateConversationTitle(title: string | undefined): boolean;
5768
+ /**
5769
+ * Find an existing private 1:1 conversation between the current user and a peer.
5770
+ * Matches conversations with exactly those two participants.
5771
+ */
5772
+ declare function findExistingPrivateConversation(conversations: AXConversation[], currentUserId: string, peerUserId: string): AXConversation | undefined;
6181
5773
  /** Other participant in a private 1v1 chat (excludes the current viewer). */
6182
5774
  declare function resolvePrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
6183
5775
  /**
6184
5776
  * Resolves the display title for the current viewer.
6185
- * Private 1v1 chats show the other participant's name when no custom title is set.
5777
+ * Private and bot peer-scoped chats show the other participant's name when no custom title is set.
6186
5778
  */
6187
5779
  declare function resolveConversationTitleForViewer(conversation: AXConversation, currentUserId?: string): string;
6188
5780
  /**
6189
- * Returns a viewer-scoped copy of a conversation with dynamic private title/avatar/icon.
5781
+ * Returns a viewer-scoped copy of a conversation with dynamic peer title/avatar/icon.
6190
5782
  * Does not mutate the source object.
6191
5783
  */
6192
5784
  declare function resolveConversationForViewer(conversation: AXConversation, currentUserId?: string): AXConversation;
5785
+ /** Whether message reactions are enabled for a conversation. Defaults to `true` when omitted. */
5786
+ declare function isConversationReactionsEnabled(conversation?: AXConversation | null): boolean;
6193
5787
 
6194
5788
  /** Resolves typed `profile`, falling back to legacy `metadata.profile`. */
6195
5789
  declare function resolveParticipantProfile(participant?: AXConversationParticipant): AXConversationUserProfile;
@@ -6217,85 +5811,38 @@ declare class AXConversationDateUtilsService {
6217
5811
  static formatTime(date: Date): string;
6218
5812
  }
6219
5813
 
5814
+ /**
5815
+ * Message Utilities Service
5816
+ * Helper functions for message formatting and display
5817
+ */
5818
+
6220
5819
  declare class AXConversationMessageUtilsService {
6221
- /**
6222
- * Normalize optional avatar/icon values so empty or whitespace-only strings
6223
- * are treated as missing data.
6224
- */
6225
- private static normalizeOptionalMediaValue;
6226
- /**
6227
- * Get conversation avatar image URL.
6228
- */
6229
- static getConversationAvatar(conversation: AXConversation): string | undefined;
6230
- /**
6231
- * Font Awesome icon class(es) for a conversation when there is no avatar image.
6232
- */
6233
- static getConversationAvatarIcon(conversation: AXConversation): string | undefined;
6234
- /**
6235
- * Get sender name from message
6236
- */
6237
- static getSenderName(message: AXConversationMessage, conversation: AXConversation): string;
6238
- /**
6239
- * Get sender avatar image URL (takes precedence over {@link getSenderAvatarIcon}).
6240
- */
6241
- static getSenderAvatar(message: AXConversationMessage, conversation: AXConversation): string | undefined;
6242
- /**
6243
- * Font Awesome icon class(es) for the sender when there is no avatar image:
6244
- * participant `icon` first, then conversation-level `icon`.
6245
- */
6246
- static getSenderAvatarIcon(message: AXConversationMessage, conversation: AXConversation): string | undefined;
6247
- /**
6248
- * Get initials from name
6249
- */
6250
5820
  static getInitials(name: string): string;
6251
- /**
6252
- * Type guard for text payload
6253
- */
6254
- static isTextPayload(payload: AXConversationMessagePayload): payload is AXConversationTextPayload;
6255
- /**
6256
- * Get message text content
6257
- */
6258
5821
  static getMessageText(message: AXConversationMessage): string;
6259
- /**
6260
- * Format message preview text
6261
- */
6262
5822
  static getPreviewText(message: AXConversationMessage, maxLength?: number): {
6263
5823
  value: string;
6264
5824
  type: string;
6265
5825
  icon: string;
6266
5826
  };
6267
- /**
6268
- * Check if message is from current user
6269
- */
6270
5827
  static isOwnMessage(message: AXConversationMessage, currentUserId: string): boolean;
6271
- /**
6272
- * Get message status icon class (Font Awesome)
6273
- */
5828
+ static getSenderName(message: AXConversationMessage, conversation: AXConversation): string;
5829
+ static getSenderAvatar(message: AXConversationMessage, conversation: AXConversation): string | undefined;
5830
+ static getSenderAvatarIcon(message: AXConversationMessage, conversation: AXConversation): string | undefined;
5831
+ static getConversationAvatar(conversation: AXConversation): string | undefined;
5832
+ static getConversationAvatarIcon(conversation: AXConversation): string | undefined;
6274
5833
  static getStatusIcon(message: AXConversationMessage): string;
6275
- /**
6276
- * Check if message should show avatar
6277
- */
6278
- static shouldShowAvatar(message: AXConversationMessage, previousMessage: AXConversationMessage | undefined, conversation: AXConversation): boolean;
6279
- /**
6280
- * Group messages by sender for consecutive messages
6281
- */
6282
- static shouldGroupWithPrevious(message: AXConversationMessage, previousMessage: AXConversationMessage | undefined): boolean;
6283
- /**
6284
- * Get conversation status for avatar (private conversations only)
6285
- */
6286
- static getConversationStatus(conversation: AXConversation): 'online' | 'offline' | 'away' | undefined;
6287
- /**
6288
- * Get typing indicator text for conversation
6289
- */
6290
- static getTypingText(conversation: AXConversation): string;
6291
- /**
6292
- * Format last seen time
6293
- */
5834
+ static getConversationStatus(conversation: AXConversation, presence?: AXConversationUserPresence): AXConversationPresenceStatus | undefined;
5835
+ static getDeliveryStatusIcon(status: AXConversationMessage['status']): string;
5836
+ static shouldGroupMessages(message: AXConversationMessage, previousMessage?: AXConversationMessage): boolean;
5837
+ static getUserPresenceStatus(presence?: AXConversationUserPresence): AXConversationPresenceStatus | undefined;
5838
+ static getTypingText(conversation: AXConversation, typingUserIds: string[]): string;
6294
5839
  static formatLastSeen(date: Date): string;
6295
- /**
6296
- * Get conversation subtitle (status or member count)
6297
- */
6298
- static getConversationSubtitle(conversation: AXConversation): string;
5840
+ static getPrivateChatSubtitle(conversation: AXConversation, presence?: AXConversationUserPresence, currentUserId?: string): string;
5841
+ static getConversationSubtitle(conversation: AXConversation, options?: {
5842
+ typingUserIds?: string[];
5843
+ peerPresence?: AXConversationUserPresence;
5844
+ currentUserId?: string;
5845
+ }): string;
6299
5846
  }
6300
5847
 
6301
5848
  /**
@@ -6393,6 +5940,52 @@ declare function copyWithFileTypeFallback(message: AXConversationMessage, regist
6393
5940
  /** Use file-type `open` on the message when `message.fileType` is set. */
6394
5941
  declare function openWithFileType(message: AXConversationMessage, registry: AXFileTypeRegistryService, ctx: AXFileTypeOpenContext): Promise<boolean>;
6395
5942
 
5943
+ interface AXConversationInfoProfileField {
5944
+ id: string;
5945
+ labelKey: string;
5946
+ value: string;
5947
+ icon: string;
5948
+ }
5949
+ type AXConversationMediaCategoryId = 'image' | 'video' | 'file' | 'audio' | 'voice' | 'sticker' | 'location' | 'link';
5950
+ interface AXConversationMediaCategory {
5951
+ id: AXConversationMediaCategoryId;
5952
+ labelKey: string;
5953
+ countLabelKey: string;
5954
+ icon: string;
5955
+ count: number;
5956
+ }
5957
+ declare function messageContainsLink(message: AXConversationMessage): boolean;
5958
+ declare function getPrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
5959
+ declare function getConversationProfileFields(conversation: AXConversation, currentUserId?: string): AXConversationInfoProfileField[];
5960
+ declare function getConversationMediaCategories(messages: AXConversationMessage[]): AXConversationMediaCategory[];
5961
+ declare function filterMessagesByMediaCategory(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMessage[];
5962
+ declare function isGridMediaCategory(categoryId: AXConversationMediaCategoryId): boolean;
5963
+ declare function isAttachmentListCategory(categoryId: AXConversationMediaCategoryId): boolean;
5964
+ interface AXConversationMediaGalleryTile {
5965
+ key: string;
5966
+ message: AXConversationMessage;
5967
+ kind: 'image' | 'video' | 'sticker';
5968
+ image?: AXConversationImageMediaItem;
5969
+ video?: AXConversationVideoMediaItem;
5970
+ stickerUrl?: string;
5971
+ stickerAlt?: string;
5972
+ }
5973
+ declare function buildMediaGalleryTiles(messages: AXConversationMessage[], categoryId: AXConversationMediaCategoryId): AXConversationMediaGalleryTile[];
5974
+ declare function resolveVideoThumbnailUrl(video: AXConversationVideoMediaItem): string | undefined;
5975
+ declare function resolveGalleryImageUrl(image: AXConversationImageMediaItem): string | undefined;
5976
+ declare function getMessageVideoItems(message: AXConversationMessage): AXConversationVideoMediaItem[];
5977
+ declare function getMessageAudioItems(message: AXConversationMessage): AXConversationAudioMediaItem[];
5978
+ interface AXConversationMediaPageResult {
5979
+ items: AXConversationMessage[];
5980
+ hasMore: boolean;
5981
+ nextCursor?: string;
5982
+ page: number;
5983
+ }
5984
+ declare function fetchConversationMediaPage(conversationApi: AXConversationApi, conversationId: string, page: number, pageSize?: number, cursor?: string): Promise<AXConversationMediaPageResult>;
5985
+ /** Merge media API results with in-memory messages needed for link/sticker/voice/location tabs. */
5986
+ declare function mergeInfoPanelMessages(mediaMessages: AXConversationMessage[], supplemental: AXConversationMessage[]): AXConversationMessage[];
5987
+ declare function filterSupplementalInfoPanelMessages(messages: AXConversationMessage[]): AXConversationMessage[];
5988
+
6396
5989
  /**
6397
5990
  * Error Message Constants
6398
5991
  * Centralized error messages with i18n support structure
@@ -6785,5 +6378,5 @@ declare function getErrorMessage(code: string, params?: Record<string, string |
6785
6378
  */
6786
6379
  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'];
6787
6380
 
6788
- export { AXConversationAiResponderService, AXConversationApi, 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_ALL_CONVERSATION_COMPOSER_TABS, AX_ALL_CONVERSATION_MEDIA_PICKERS, AX_CONVERSATION_AI_API_KEY, AX_CONVERSATION_AUDIO_CATALOG, AX_CONVERSATION_AUDIO_PRESENTATION, AX_CONVERSATION_AUDIO_RENDERER, 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_INFO_BAR_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS, AX_CONVERSATION_DEFAULT_MESSAGE_RENDERERS, 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_REPLY_ACTION, AX_CONVERSATION_MESSAGE_TYPE_FILE_TYPE, AX_CONVERSATION_PICKER_SHARED_STYLES, AX_CONVERSATION_PICKER_SHELL_STYLES, AX_CONVERSATION_REGISTRY_CONFIG, AX_CONVERSATION_RENDERER_SHARED_STYLES, 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, 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, fetchAllConversationMessages, fileItemFromUpload, filterMessagesByMediaCategory, formatDuration, formatErrorMessage, formatFileByteSize, formatFileSize, formatMediaDuration, formatPickerValidationMessage, getConversationLastActivity, getConversationMediaCategories, getConversationMessagesNewestFirst, getConversationProfileFields, getErrorMessage, getMessageAudioItems, getMessageVideoItems, getPickerCancelUploadLabel, getPrivatePeerParticipant, getSortedConversationsForInbox, inferFileExtensionHintFromMessage, isAttachmentListCategory, isComposerTabEnabled, isGenericPrivateConversationTitle, isGridMediaCategory, isMediaPickerEnabled, isMessageDeliveryPending, isNonPersistableMediaUrl, isPickerItemReadyToSend, isUploadAborted, limitFilesToCapacity, mediaCopyText, mergeAudioUploadResult, mergeFileUploadResult, mergeUploadResult, mergeVideoUploadResult, mergeVoiceUploadResult, mergeWithDefaults, messageContainsLink, normalizeAllConversationMessageIndexes, normalizeAudioPayload, normalizeFilePayload, normalizeImagePayload, normalizeMessagePayload, normalizeMessagePayloadAsync, normalizeVideoPayload, notifyMaxFilesCapacityExceeded, notifyPickerValidationErrors, openWithFileType, paginateChatNewestFirst, paginateChatOldestFirst, parseChatCursor, pickDisplayMediaUrl, pickerItemToMediaReference, pickerItemToUploadResult, provideConversation, provideConversationComposerFileTypes, provideConversationFileCatalog, registerChatMessage, reportMediaLoadError, resolveComposerMaxFiles, resolveConversationAvatarDisplay, resolveConversationComposerTabs, resolveConversationForViewer, resolveConversationMediaPickers, resolveConversationMessageFileType, resolveConversationTitleForViewer, resolveGalleryImageUrl, resolveImageDisplayUrl, 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 };
6789
- export type { AXConversation, AXConversationAiResponderConfig, AXConversationApiError, 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, AXConversationMediaPickerFeature, AXConversationMention, AXConversationMessage, AXConversationMessageAction, AXConversationMessageActionContext, AXConversationMessageForwardData, AXConversationMessageInfoBarBannerComponent, AXConversationMessageListEmptyComponent, 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 };
6381
+ 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, 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 };
6382
+ 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, 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, AXConversationMessageForwardData, AXConversationMessageInfoBarBannerComponent, AXConversationMessageListBackground, AXConversationMessageListBackgroundPreset, AXConversationMessageListEmptyComponent, AXConversationMessageListThemeBackground, AXConversationMessagePayload, AXConversationMessageRenderer, AXConversationMessageRendererCapabilities, AXConversationMessageRendererComponent, AXConversationMessageRendererContentState, AXConversationMessageRendererState, AXConversationMessageSearchFilters, AXConversationMessageStatus, AXConversationMessageType, AXConversationMetadata, AXConversationOptions, 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 };