@acorex/components 22.0.0-next.9 → 22.0.1

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 (119) 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 +8966 -16359
  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 +27 -27
  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 +40 -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-grid-layout-builder.d.ts +34 -2
  102. package/types/acorex-components-loading-dialog.d.ts +12 -4
  103. package/types/acorex-components-lookup.d.ts +831 -0
  104. package/types/acorex-components-menu.d.ts +28 -4
  105. package/types/acorex-components-notification.d.ts +11 -1
  106. package/types/acorex-components-number-box.d.ts +3 -1
  107. package/types/acorex-components-popover.d.ts +12 -1
  108. package/types/acorex-components-popup.d.ts +9 -1
  109. package/types/acorex-components-scheduler.d.ts +2 -4
  110. package/types/acorex-components-select-box.d.ts +21 -4
  111. package/types/acorex-components-toast.d.ts +10 -1
  112. package/types/acorex-components-tree-view.d.ts +9 -1
  113. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-CNHiM1Sp.mjs +0 -106
  114. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-CNHiM1Sp.mjs.map +0 -1
  115. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-Hh5Oyp3p.mjs.map +0 -1
  116. package/fesm2022/acorex-components-selection-list-2.mjs +0 -168
  117. package/fesm2022/acorex-components-selection-list-2.mjs.map +0 -1
  118. package/selection-list-2/README.md +0 -3
  119. 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,15 @@ 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 config;
691
+ private readonly _activeActionOverlay;
668
692
  private get registry();
669
693
  private readonly _replyMessage;
670
694
  private readonly _editMessage;
@@ -672,15 +696,10 @@ declare class AXConversationComposerService {
672
696
  readonly editMessage: _angular_core.Signal<AXConversationMessage>;
673
697
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
674
698
  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
699
  /** Draft text */
679
700
  readonly draftText: _angular_core.WritableSignal<string>;
680
701
  /** Attachments */
681
702
  readonly attachments: _angular_core.WritableSignal<File[]>;
682
- /** Show typing indicator */
683
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
684
703
  /** Incremented to request focus on the composer text area (handled by AXConversationComposerComponent). */
685
704
  private readonly _focusRequest;
686
705
  readonly focusRequest: _angular_core.Signal<number>;
@@ -688,22 +707,31 @@ declare class AXConversationComposerService {
688
707
  readonly placeholder: _angular_core.Signal<string>;
689
708
  /** Number of input rows */
690
709
  readonly inputRows: _angular_core.Signal<number>;
691
- /** Can send message */
710
+ /** Can send message (draft has content; does not include generation state). */
692
711
  readonly canSend: _angular_core.Signal<boolean>;
712
+ /** Whether a background generation (e.g. AI response) is in progress. */
713
+ readonly isGenerating: _angular_core.Signal<boolean>;
714
+ /** Whether cancel cleanup is in progress (spinner on primary button). */
715
+ readonly isStopping: _angular_core.Signal<boolean>;
716
+ /** Primary end-button mode for send / cancel / stopping / voice / locked. */
717
+ readonly primaryButtonMode: _angular_core.Signal<AXConversationComposerPrimaryButtonMode>;
693
718
  /** Composer action context */
694
719
  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[]>;
720
+ /** Start actions from registry */
721
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
722
+ /** End actions from registry */
723
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
724
+ /** Start inline actions (location = 'inline' or undefined) */
725
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
726
+ /** Start menu actions shown in the attachment popup */
727
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
728
+ /** End inline actions inside the input pill (excludes default action) */
729
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
730
+ /** End menu actions (location = 'menu') */
731
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
732
+ /** Default end action (voice/send morph button) */
733
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
734
+ cancelGeneration(): void;
707
735
  startReply(message: AXConversationMessage): void;
708
736
  startEdit(message: AXConversationMessage): void;
709
737
  /** Focus the composer text area when the composer component is mounted. */
@@ -720,21 +748,20 @@ declare class AXConversationComposerService {
720
748
  */
721
749
  clearComposerInput(conversationId?: string): void;
722
750
  /**
723
- * Show a component in the composer (full-width mode)
751
+ * Open a composer action component in a popup (desktop) or action sheet (mobile).
724
752
  */
725
- showComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>): void;
753
+ openActionComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>, options?: {
754
+ toggleable?: boolean;
755
+ initialFiles?: File[];
756
+ }): Promise<void>;
726
757
  /**
727
- * Hide the active component
758
+ * Hide the active action overlay.
728
759
  */
729
760
  hideComponent(): void;
730
- /**
731
- * Toggle component visibility
732
- */
733
- toggleComponent(action: AXConversationComposerAction, inputs?: Record<string, unknown>): void;
734
761
  /**
735
762
  * Get actions for the active conversation
736
763
  */
737
- getActionsForPosition(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
764
+ getActionsForPosition(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
738
765
  /**
739
766
  * Execute an action
740
767
  */
@@ -771,6 +798,10 @@ interface AXConversationComposerActionContext {
771
798
  isReplying: boolean;
772
799
  /** Message being replied to (if any) */
773
800
  replyingToMessageId?: string;
801
+ /** Whether a background generation (e.g. AI response) is in progress */
802
+ isGenerating?: boolean;
803
+ /** Whether cancel cleanup is in progress */
804
+ isStopping?: boolean;
774
805
  /** Custom context data */
775
806
  custom?: Record<string, unknown>;
776
807
  }
@@ -787,6 +818,15 @@ interface AXConversationComposerActionComponent {
787
818
  readonly initialFiles?: InputSignal<File[]>;
788
819
  /** Set by {@link AXPopupService} when the picker is shown in a popup. */
789
820
  readonly __popup__?: InputSignal<_acorex_components_popup.AXPopupRef | undefined>;
821
+ /** Set by {@link AXActionSheetService} when the picker is shown in an action sheet. */
822
+ readonly __actionSheet__?: InputSignal<_acorex_components_action_sheet.AXActionSheetRef | undefined>;
823
+ /**
824
+ * When true (from action {@link AXConversationComposerAction.autoRun}), runs {@link activate}
825
+ * once after the component is mounted.
826
+ */
827
+ readonly autoRun?: InputSignal<boolean>;
828
+ /** Primary action when opened from the composer (record, browse files, etc.). */
829
+ activate?(): void | Promise<void>;
790
830
  /** Cancel in-flight uploads when the picker is closed or replaced. */
791
831
  abortInProgressUploads?(): void;
792
832
  }
@@ -798,10 +838,15 @@ interface AXConversationComposerAction extends Omit<AXConversationRegistryItem,
798
838
  label: string;
799
839
  /** Icon name/class */
800
840
  icon: string;
801
- /** Position: left or right */
802
- position: 'left' | 'right';
803
- /** Location: inline (show as button) or menu (show in dropdown menu) */
841
+ /** Position: start or end of the composer */
842
+ position: 'start' | 'end';
843
+ /** Location: inline (show as button) or menu (show in attachment popup menu) */
804
844
  location?: 'inline' | 'menu';
845
+ /**
846
+ * Primary end action (e.g. voice record). Only one action may be default.
847
+ * Renders as the circular send-style button and morphs into send when the draft has content.
848
+ */
849
+ default?: boolean;
805
850
  /** Visibility condition */
806
851
  visible: (context: AXConversationComposerActionContext) => boolean;
807
852
  /** Enabled condition */
@@ -817,6 +862,11 @@ interface AXConversationComposerAction extends Omit<AXConversationRegistryItem,
817
862
  * Whether this action is toggleable (shows/hides component)
818
863
  */
819
864
  toggleable?: boolean;
865
+ /**
866
+ * When true, runs {@link AXConversationComposerActionComponent.activate} in
867
+ * {@link afterNextRender} after the upload panel is mounted.
868
+ */
869
+ autoRun?: boolean;
820
870
  /** Action handler (optional if component is provided) */
821
871
  handler?: (context: AXConversationComposerActionContext) => void | Promise<void>;
822
872
  /** Tooltip text */
@@ -841,26 +891,30 @@ declare class AXConversationComposerActionRegistry {
841
891
  private readonly _actions;
842
892
  private readonly translation;
843
893
  private readonly injector;
844
- private readonly fileTypeRegistry;
894
+ private readonly composerTabRegistry;
845
895
  constructor();
846
896
  /** All registered actions */
847
897
  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[]>;
898
+ /** Start-side actions sorted by priority */
899
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
900
+ /** End-side actions sorted by priority */
901
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
902
+ /** Start-side inline actions (location = 'inline' or undefined) */
903
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
904
+ /** Start-side menu actions (location = 'menu') — shown in the attachment popup */
905
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
906
+ /** End-side inline actions inside the input pill (excludes default action) */
907
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
908
+ /** End-side menu actions (location = 'menu') */
909
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
910
+ /** The single default end action (voice/send morph button) */
911
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
860
912
  /**
861
913
  * Register a composer action
862
914
  */
863
915
  register(action: AXConversationComposerAction): void;
916
+ /** Resolved lazily to avoid a DI cycle with {@link AXConversationComposerFileTypesProvider}. */
917
+ private fileTypeRegistry;
864
918
  private ensureFileTypeExists;
865
919
  /**
866
920
  * Unregister a composer action
@@ -869,11 +923,11 @@ declare class AXConversationComposerActionRegistry {
869
923
  /**
870
924
  * Get visible actions for a position
871
925
  */
872
- getVisibleActions(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
926
+ getVisibleActions(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
873
927
  /**
874
928
  * Get enabled actions for a position
875
929
  */
876
- getEnabledActions(position: 'left' | 'right', context: AXConversationComposerActionContext): AXConversationComposerAction[];
930
+ getEnabledActions(position: 'start' | 'end', context: AXConversationComposerActionContext): AXConversationComposerAction[];
877
931
  isActionEnabled(action: AXConversationComposerAction, context: AXConversationComposerActionContext): boolean;
878
932
  /**
879
933
  * Picker actions for a file catalog (by priority), when visible and enabled.
@@ -935,6 +989,8 @@ declare class AXConversationComposerTabRegistry {
935
989
  readonly tabs: _angular_core.Signal<AXConversationComposerTab[]>;
936
990
  /** Enabled tabs sorted by priority */
937
991
  readonly enabledTabs: _angular_core.Signal<AXConversationComposerTab[]>;
992
+ /** Whether the composer popup has any tabs to show. */
993
+ readonly hasEnabledTabs: _angular_core.Signal<boolean>;
938
994
  /**
939
995
  * Register a composer tab
940
996
  */
@@ -1200,6 +1256,7 @@ declare class AXConversationMessageRendererRegistry {
1200
1256
  private readonly _composerActions;
1201
1257
  constructor();
1202
1258
  private registerBuiltInRenderers;
1259
+ private registerBuiltInRendererIfMissing;
1203
1260
  /** All registered renderers */
1204
1261
  readonly renderers: Signal<AXConversationMessageRenderer[]>;
1205
1262
  /** Renderers sorted by priority (highest first) */
@@ -1289,10 +1346,6 @@ declare class AXConversationInfoBarService {
1289
1346
  * Reset info-bar overlays when the active conversation changes.
1290
1347
  */
1291
1348
  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
1349
  /**
1297
1350
  * Get actions for the active conversation
1298
1351
  */
@@ -1396,7 +1449,7 @@ interface AXConversationInfoBarAction extends AXConversationRegistryItem {
1396
1449
  /** Whether this is a divider */
1397
1450
  divider?: boolean;
1398
1451
  /** Display location: 'inline' for toolbar buttons, 'menu' for dropdown menu */
1399
- location?: 'inline' | 'menu';
1452
+ location?: 'inline' | 'menu' | ((context: AXConversationInfoBarActionContext) => 'inline' | 'menu');
1400
1453
  /**
1401
1454
  * Component to show when action is activated (for inline actions)
1402
1455
  * If provided, clicking the action will show this component in the info-bar
@@ -1446,6 +1499,10 @@ declare class AXConversationInfoBarActionRegistry extends AXConversationBaseRegi
1446
1499
  * Get actions for a specific conversation
1447
1500
  */
1448
1501
  getActionsForConversation(conversation: AXConversation, location?: 'inline' | 'menu'): AXConversationInfoBarAction[];
1502
+ /**
1503
+ * Resolve the display location for an action (supports dynamic location factories).
1504
+ */
1505
+ getActionLocation(action: AXConversationInfoBarAction, conversation: AXConversation): 'inline' | 'menu' | undefined;
1449
1506
  /**
1450
1507
  * Get inline actions (toolbar buttons)
1451
1508
  */
@@ -1563,14 +1620,13 @@ declare class AXConversationMessageActionRegistry {
1563
1620
  }
1564
1621
 
1565
1622
  declare class AXConversationComposerComponent implements OnDestroy {
1566
- #private;
1567
1623
  private readonly conversationService;
1568
1624
  private readonly composerService;
1569
1625
  private readonly messageListService;
1570
1626
  private readonly config;
1571
1627
  private readonly translation;
1572
1628
  /** Access registry through conversation service */
1573
- private get registry();
1629
+ protected get composerActionRegistry(): _acorex_components_conversation.AXConversationComposerActionRegistry;
1574
1630
  /** Composer text area reference */
1575
1631
  private readonly textAreaRef;
1576
1632
  /** Draft text - use service */
@@ -1581,10 +1637,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1581
1637
  readonly editingMessage: _angular_core.WritableSignal<any>;
1582
1638
  /** Replying to message */
1583
1639
  readonly replyingToMessage: _angular_core.WritableSignal<AXConversationMessage>;
1584
- /** Show typing indicator - use service */
1585
- readonly showTypingIndicator: _angular_core.WritableSignal<boolean>;
1586
1640
  /** Message sent event */
1587
1641
  readonly messageSent: _angular_core.OutputEmitterRef<AXConversationSendMessageCommand>;
1642
+ /** Emitted when the user cancels an in-progress generation from the composer. */
1643
+ readonly generationCancelled: _angular_core.OutputEmitterRef<void>;
1588
1644
  /** Emoji clicked event */
1589
1645
  readonly emojiClick: _angular_core.OutputEmitterRef<void>;
1590
1646
  /** Attach clicked event */
@@ -1594,46 +1650,53 @@ declare class AXConversationComposerComponent implements OnDestroy {
1594
1650
  /** Active conversation */
1595
1651
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
1596
1652
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
1597
- /** Active component from service */
1598
- readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerActiveComponent>;
1599
1653
  /** Emoji popover state */
1600
1654
  private readonly emojiPopoverRef;
1601
1655
  readonly emojiPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1656
+ /** Attachment menu popover state */
1657
+ private readonly attachPopoverRef;
1658
+ private readonly attachMenuButtonRef;
1659
+ readonly attachMenuTarget: _angular_core.Signal<HTMLElement>;
1660
+ private attachMenuCloseTimer?;
1602
1661
  readonly composerPopupLoader: () => Promise<typeof _acorex_components_conversation.AXConversationComposerPopupComponent>;
1603
1662
  /** Input placeholder - use service */
1604
1663
  readonly placeholder: _angular_core.Signal<string>;
1605
- /** Typing indicator subject for rate limiting */
1606
- private readonly typingSubject;
1607
1664
  constructor();
1608
1665
  private draftSaveTimeout?;
1609
1666
  /** Number of input rows - use service */
1610
1667
  readonly inputRows: _angular_core.Signal<number>;
1611
1668
  /** Can send message - use service */
1612
1669
  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 */
1670
+ /** Whether AI/generation is in progress */
1671
+ readonly isGenerating: _angular_core.Signal<boolean>;
1672
+ /** Whether cancel cleanup is in progress */
1673
+ readonly isStopping: _angular_core.Signal<boolean>;
1674
+ /** Primary button mode */
1675
+ readonly primaryButtonMode: _angular_core.Signal<_acorex_components_conversation.AXConversationComposerPrimaryButtonMode>;
1676
+ /** Start actions from registry - use service */
1677
+ readonly startActions: _angular_core.Signal<AXConversationComposerAction[]>;
1678
+ /** End actions from registry - use service */
1679
+ readonly endActions: _angular_core.Signal<AXConversationComposerAction[]>;
1680
+ /** Start inline actions */
1681
+ readonly startInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1682
+ /** Start menu actions (attachment popup) */
1683
+ readonly startMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1684
+ /** End inline actions inside input pill */
1685
+ readonly endInlineActions: _angular_core.Signal<AXConversationComposerAction[]>;
1686
+ /** End menu actions */
1687
+ readonly endMenuActions: _angular_core.Signal<AXConversationComposerAction[]>;
1688
+ /** Default end action (voice/send morph) */
1689
+ readonly defaultAction: _angular_core.Signal<AXConversationComposerAction>;
1690
+ /** Handle key down (send on Enter; typing is driven by draft changes only). */
1626
1691
  onKeyDown(event: AXHtmlEvent<KeyboardEvent>): void;
1627
- /** Handle input */
1628
- onInput(): void;
1629
- /** Send typing indicator (throttled via RxJS) */
1630
- private sendTypingIndicator;
1692
+ /** Handle draft text changes — throttled typing indicator via conversation service. */
1693
+ onDraftChanged(): void;
1631
1694
  /** Cleanup on destroy */
1632
1695
  ngOnDestroy(): void;
1633
1696
  /** Handle send click */
1634
1697
  onSendClick(): Promise<void>;
1635
1698
  /** Handle emoji click */
1636
- onEmojiClick(event?: MouseEvent): Promise<void>;
1699
+ onEmojiClick(event?: AXClickEvent | MouseEvent): Promise<void>;
1637
1700
  /** Handle emoji popover closed */
1638
1701
  onEmojiPopoverClosed(): void;
1639
1702
  /** Handle emoji/sticker selection from popup */
@@ -1642,8 +1705,26 @@ declare class AXConversationComposerComponent implements OnDestroy {
1642
1705
  private sendSticker;
1643
1706
  /** Get inputs for emoji popup component */
1644
1707
  getEmojiPopupInputs(): Record<string, unknown>;
1645
- /** Handle attach click */
1646
- onAttachClick(): void;
1708
+ /** Handle attach menu hover */
1709
+ onAttachMenuMouseEnter(): void;
1710
+ onAttachMenuMouseLeave(): void;
1711
+ onAttachMenuPanelMouseEnter(): void;
1712
+ onAttachMenuPanelMouseLeave(): void;
1713
+ private scheduleAttachMenuClose;
1714
+ private clearAttachMenuCloseTimer;
1715
+ /** Handle attach menu click */
1716
+ onAttachMenuClick(event: AXClickEvent): void;
1717
+ /** Handle attachment menu action selection */
1718
+ onAttachMenuAction(actionId: string): Promise<void>;
1719
+ /** Handle primary button click (send / cancel / stopping / voice / locked). */
1720
+ onPrimaryButtonClick(): Promise<void>;
1721
+ /** @deprecated Use onPrimaryButtonClick */
1722
+ onDefaultActionClick(): Promise<void>;
1723
+ getPrimaryButtonIcon(): string;
1724
+ getPrimaryButtonLabel(): string;
1725
+ isPrimaryButtonDisabled(): boolean;
1726
+ /** @deprecated Use getPrimaryButtonIcon */
1727
+ getDefaultActionIcon(): string;
1647
1728
  /** Handle voice click */
1648
1729
  onVoiceClick(): void;
1649
1730
  /** Remove attachment */
@@ -1656,8 +1737,9 @@ declare class AXConversationComposerComponent implements OnDestroy {
1656
1737
  startReply(message: AXConversationMessage): void;
1657
1738
  /** Focus the native textarea inside ax-text-area */
1658
1739
  private focusTextArea;
1740
+ private getClickTarget;
1659
1741
  /** Handle action click */
1660
- onActionClick(actionId: string, event?: MouseEvent): Promise<void>;
1742
+ onActionClick(actionId: string, event?: AXClickEvent | MouseEvent, initialFiles?: File[]): Promise<void>;
1661
1743
  /** Check if action is enabled */
1662
1744
  isActionEnabled(action: any): boolean;
1663
1745
  /** Get replying sender name */
@@ -1665,6 +1747,9 @@ declare class AXConversationComposerComponent implements OnDestroy {
1665
1747
  getActionLabel(action: {
1666
1748
  label: string;
1667
1749
  }): string;
1750
+ getActionButtonClass(action: {
1751
+ className?: string;
1752
+ }): string;
1668
1753
  /** Get replying message text */
1669
1754
  getReplyingMessageText(): string;
1670
1755
  /** Preview object for replying banner (type, icon, value) */
@@ -1685,13 +1770,10 @@ declare class AXConversationComposerComponent implements OnDestroy {
1685
1770
  }): string;
1686
1771
  /** Handle reply preview click - scroll to original message */
1687
1772
  onReplyPreviewClick(): void;
1688
- /** Inputs for picker / full-width composer components */
1773
+ /** Inputs for picker components opened in popup / action sheet */
1689
1774
  private buildPickerInputs;
1690
- /** Get inputs for dynamic component */
1691
- getComponentInputs(): Record<string, unknown>;
1692
- onEnter(event: AXHtmlEvent<KeyboardEvent>): Promise<void>;
1693
1775
  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>;
1776
+ 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
1777
  }
1696
1778
 
1697
1779
  declare class AXConversationContainerComponent {
@@ -1700,9 +1782,12 @@ declare class AXConversationContainerComponent {
1700
1782
  private readonly fileService;
1701
1783
  private readonly translation;
1702
1784
  private readonly toast;
1785
+ private readonly platform;
1786
+ private readonly actionSheetService;
1703
1787
  private readonly hostRef;
1704
1788
  private readonly platformId;
1705
1789
  protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
1790
+ constructor();
1706
1791
  private get registry();
1707
1792
  /** Custom CSS class */
1708
1793
  readonly customClass: _angular_core.InputSignal<string>;
@@ -1732,7 +1817,10 @@ declare class AXConversationContainerDirective {
1732
1817
  private readonly platformId;
1733
1818
  private readonly translation;
1734
1819
  private readonly toast;
1820
+ private readonly platform;
1821
+ private readonly actionSheetService;
1735
1822
  private readonly config;
1823
+ constructor();
1736
1824
  private get registry();
1737
1825
  /** Active conversation */
1738
1826
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
@@ -1758,59 +1846,51 @@ interface AXConversationDropdownMenuItem {
1758
1846
  declare class AXConversationInfoBarComponent {
1759
1847
  private readonly conversationService;
1760
1848
  private readonly infoBar;
1849
+ private readonly platform;
1850
+ private readonly destroyRef;
1851
+ private readonly customUserAvatarComponent;
1852
+ private readonly layoutTick;
1853
+ constructor();
1761
1854
  protected get registry(): _acorex_components_conversation.AXConversationRegistryService;
1762
- /** Active conversation */
1855
+ readonly hasCustomUserAvatar: _angular_core.Signal<boolean>;
1763
1856
  readonly activeConversation: _angular_core.Signal<AXConversation>;
1764
- /** Active component from service */
1765
1857
  readonly activeComponent: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveComponent>;
1766
- /** Active banner from service */
1767
1858
  readonly activeBanner: _angular_core.Signal<_acorex_components_conversation.AXConversationInfoBarActiveBanner>;
1768
- /** Members popover target element — retained for API compatibility */
1769
1859
  readonly membersPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
1770
- /** Loading state for async actions */
1771
1860
  readonly actionLoading: _angular_core.WritableSignal<boolean>;
1772
- /** Info area clicked — opens conversation profile panel */
1773
1861
  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
1862
  readonly searchClick: _angular_core.OutputEmitterRef<void>;
1778
- /** Search query changed event */
1779
1863
  readonly searchQuery: _angular_core.OutputEmitterRef<string>;
1780
- /** Menu item clicked event */
1781
1864
  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 */
1865
+ readonly inlineActions: _angular_core.Signal<AXConversationInfoBarAction[]>;
1785
1866
  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 */
1867
+ getStatus(conversation: AXConversation): _acorex_components_conversation.AXConversationPresenceStatus;
1789
1868
  getSubtitle(conversation: AXConversation): string;
1790
- /** Open conversation info panel when the left info area is clicked */
1791
1869
  onInfoLeftClick(): void;
1792
- /** Handle inline action click */
1793
1870
  onInlineActionClick(actionId: string): Promise<void>;
1794
- /** Get inputs for dynamic component */
1871
+ private activateAction;
1795
1872
  getComponentInputs(): Record<string, unknown>;
1796
1873
  getInlineComponentInputs(): Record<string, unknown>;
1797
1874
  isActiveComponentFullWidth(): boolean;
1798
- /** Handle close component */
1799
1875
  onCloseComponent(): void;
1800
1876
  getBannerInputs(): Record<string, unknown>;
1801
1877
  onCloseBanner(): void;
1802
- /** Handle menu item click */
1803
1878
  onMenuItemClick(item: AXConversationDropdownMenuItem): Promise<void>;
1804
1879
  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>;
1880
+ 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
1881
  }
1807
1882
 
1808
1883
  /**
1884
+
1809
1885
  * Shared API Types
1886
+
1810
1887
  * Common types used across all API services
1888
+
1811
1889
  */
1812
1890
  /**
1891
+
1813
1892
  * Pagination parameters
1893
+
1814
1894
  */
1815
1895
  interface AXConversationPagination {
1816
1896
  /** Page number (0-based) */
@@ -1825,7 +1905,9 @@ interface AXConversationPagination {
1825
1905
  sortDirection?: 'asc' | 'desc';
1826
1906
  }
1827
1907
  /**
1908
+
1828
1909
  * Paginated response
1910
+
1829
1911
  */
1830
1912
  interface AXConversationPaginatedResult<T> {
1831
1913
  /** Result items */
@@ -1844,7 +1926,9 @@ interface AXConversationPaginatedResult<T> {
1844
1926
  totalPages?: number;
1845
1927
  }
1846
1928
  /**
1929
+
1847
1930
  * Pagination cursor state for a single list (conversations or messages).
1931
+
1848
1932
  */
1849
1933
  interface AXConversationPaginationState {
1850
1934
  page: number;
@@ -1852,11 +1936,15 @@ interface AXConversationPaginationState {
1852
1936
  nextCursor?: string;
1853
1937
  }
1854
1938
  /**
1939
+
1855
1940
  * Connection status
1941
+
1856
1942
  */
1857
1943
  type AXConversationConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
1858
1944
  /**
1945
+
1859
1946
  * API Error with details
1947
+
1860
1948
  */
1861
1949
  interface AXConversationApiError {
1862
1950
  /** Error code */
@@ -1870,19 +1958,24 @@ interface AXConversationApiError {
1870
1958
  /** Timestamp */
1871
1959
  timestamp?: Date;
1872
1960
  }
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
1961
 
1882
- /**
1883
- * Abstract Conversation Management API
1884
- * Handle conversation CRUD operations, participants, and settings
1885
- */
1962
+ type AXConversationApiName = 'userApi' | 'conversationApi' | 'messageApi' | 'realtimeApi';
1963
+ interface AXConversationApiLogEntry {
1964
+ /** Public method on AXConversationService that triggered the API call. */
1965
+ serviceMethod: string;
1966
+ /** Injected API instance name. */
1967
+ api: AXConversationApiName;
1968
+ /** Method invoked on the API instance. */
1969
+ apiMethod: string;
1970
+ /** Positional arguments passed to the API method. */
1971
+ context: unknown[];
1972
+ }
1973
+ declare class AXConversationApiLoggerService {
1974
+ private readonly config;
1975
+ log(entry: AXConversationApiLogEntry): void;
1976
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationApiLoggerService, never>;
1977
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationApiLoggerService>;
1978
+ }
1886
1979
 
1887
1980
  /**
1888
1981
  * Conversation creation data
@@ -1907,6 +2000,11 @@ interface AXConversationCreateData {
1907
2000
  icon?: string;
1908
2001
  /** Custom metadata */
1909
2002
  metadata?: Record<string, unknown>;
2003
+ /**
2004
+ * When `true`, create a new private chat even if one already exists with the same participants.
2005
+ * Defaults to `false` for private conversations.
2006
+ */
2007
+ forceCreate?: boolean;
1910
2008
  }
1911
2009
  /**
1912
2010
  * Conversation update data
@@ -1946,20 +2044,9 @@ interface AXConversationFilters {
1946
2044
  custom?: Record<string, unknown>;
1947
2045
  }
1948
2046
  /**
1949
- * Conversation settings update
2047
+ * @deprecated Use {@link AXConversationRoomPreferences} on the user API instead.
1950
2048
  */
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
- }
2049
+ type AXConversationSettingsUpdate = AXConversationRoomPreferences;
1963
2050
  /**
1964
2051
  * Participant update data
1965
2052
  */
@@ -1967,7 +2054,7 @@ interface AXConversationParticipantUpdate {
1967
2054
  /** User ID */
1968
2055
  userId: string;
1969
2056
  /** New role */
1970
- role?: AXConversationUserRole;
2057
+ role?: AXConversationParticipantRole;
1971
2058
  }
1972
2059
  /**
1973
2060
  * Abstract Conversation Management API
@@ -2068,13 +2155,6 @@ declare abstract class AXConversationApi {
2068
2155
  * @throws {AXConversationApiError} If marking fails
2069
2156
  */
2070
2157
  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
2158
  /**
2079
2159
  * Search conversations
2080
2160
  *
@@ -2134,37 +2214,6 @@ declare abstract class AXConversationApi {
2134
2214
  * @throws {AXConversationApiError} If update fails
2135
2215
  */
2136
2216
  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
2217
  /**
2169
2218
  * Upload conversation avatar
2170
2219
  *
@@ -2583,111 +2632,33 @@ declare abstract class AXConversationMessageApi {
2583
2632
 
2584
2633
  /**
2585
2634
  * Abstract Real-time Events API
2586
- * Handle WebSocket/SSE connections and real-time event subscriptions
2635
+ * Handle WebSocket/SSE event subscriptions for conversation domain updates
2587
2636
  */
2588
2637
 
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
2638
  /**
2664
2639
  * Abstract Real-time Events API
2665
2640
  *
2666
- * Implement this abstract class to handle real-time event subscriptions.
2667
- * Supports WebSocket, SSE, or any other real-time protocol.
2641
+ * Implement this abstract class to expose domain event streams from your WebSocket/SSE layer.
2642
+ * Connection lifecycle is owned by the implementation — this contract only covers subscriptions.
2643
+ *
2644
+ * Covered domains: message CRUD, conversation (room) CRUD, typing indicators, and presence.
2645
+ * Message updates include edits, reactions, delivery/read status, and other message field changes.
2668
2646
  *
2669
2647
  * @example
2670
2648
  * ```typescript
2671
2649
  * @Injectable()
2672
2650
  * export class MyRealtimeApi extends AXConversationRealtimeApi {
2673
- * private socket: WebSocket;
2674
- * private connectionStatus$ = new BehaviorSubject<AXConversationConnectionStatus>('disconnected');
2651
+ * private readonly messageCreated$ = new Subject<AXConversationMessage>();
2675
2652
  *
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
2653
+ * constructor(private readonly socket: MyChatSocketService) {
2654
+ * super();
2655
+ * this.socket.on('message.created', (message) => this.messageCreated$.next(message));
2680
2656
  * }
2681
2657
  *
2682
2658
  * 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
- * });
2659
+ * return this.messageCreated$.pipe(
2660
+ * filter((message) => !conversationId || message.conversationId === conversationId),
2661
+ * );
2691
2662
  * }
2692
2663
  *
2693
2664
  * // ... implement other methods
@@ -2695,41 +2666,6 @@ interface AXConversationCallEvent {
2695
2666
  * ```
2696
2667
  */
2697
2668
  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
2669
  /**
2734
2670
  * Subscribe to new messages in a conversation
2735
2671
  *
@@ -2738,7 +2674,7 @@ declare abstract class AXConversationRealtimeApi {
2738
2674
  */
2739
2675
  abstract subscribeToMessages(conversationId: string): Observable<AXConversationMessage>;
2740
2676
  /**
2741
- * Subscribe to message updates (edits, status changes)
2677
+ * Subscribe to message updates (edits, reactions, status changes, metadata, etc.)
2742
2678
  *
2743
2679
  * @param conversationId - Optional conversation ID to filter
2744
2680
  * @returns Observable stream of updated messages
@@ -2752,15 +2688,32 @@ declare abstract class AXConversationRealtimeApi {
2752
2688
  */
2753
2689
  abstract subscribeToMessageDeletions(conversationId?: string): Observable<string>;
2754
2690
  /**
2755
- * Subscribe to message reactions
2691
+ * Subscribe to message status changes
2692
+ * Fires when message status changes (sending -> sent -> delivered -> read)
2693
+ *
2694
+ * @param conversationId - Optional conversation ID to filter
2695
+ * @returns Observable stream of message status updates
2696
+ */
2697
+ abstract subscribeToMessageStatusChanges(conversationId?: string): Observable<{
2698
+ messageId: string;
2699
+ status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
2700
+ timestamp: Date;
2701
+ }>;
2702
+ /**
2703
+ * Subscribe to read receipt updates
2704
+ * Fires when someone reads messages
2756
2705
  *
2757
2706
  * @param conversationId - Optional conversation ID to filter
2758
- * @returns Observable stream of updated messages with reactions
2707
+ * @returns Observable stream of message IDs that were read
2759
2708
  */
2760
- abstract subscribeToMessageReactions(conversationId?: string): Observable<AXConversationMessage>;
2709
+ abstract subscribeToReadReceipts(conversationId?: string): Observable<{
2710
+ messageId: string;
2711
+ userId: string;
2712
+ readAt: Date;
2713
+ }>;
2761
2714
  /**
2762
2715
  * Subscribe to conversation updates
2763
- * Fires when conversation details change (title, avatar, participants, etc.)
2716
+ * Fires when conversation details change (title, avatar, participants, last message, etc.)
2764
2717
  *
2765
2718
  * @returns Observable stream of updated conversations
2766
2719
  */
@@ -2793,97 +2746,6 @@ declare abstract class AXConversationRealtimeApi {
2793
2746
  * @returns Observable stream of presence updates
2794
2747
  */
2795
2748
  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
2749
  }
2888
2750
 
2889
2751
  /**
@@ -2963,7 +2825,7 @@ declare abstract class AXConversationUserApi {
2963
2825
  * @returns Current user information
2964
2826
  * @throws {AXConversationApiError} If user is not authenticated
2965
2827
  */
2966
- abstract getCurrentUser(): Promise<AXConversationParticipant>;
2828
+ abstract getCurrentUser(): Promise<AXConversationUser>;
2967
2829
  /**
2968
2830
  * Update current user profile
2969
2831
  *
@@ -2971,7 +2833,7 @@ declare abstract class AXConversationUserApi {
2971
2833
  * @returns Updated user information
2972
2834
  * @throws {AXConversationApiError} If update fails
2973
2835
  */
2974
- abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationParticipant>;
2836
+ abstract updateProfile(updates: AXConversationUserProfileUpdate): Promise<AXConversationUser>;
2975
2837
  /**
2976
2838
  * Upload user avatar
2977
2839
  *
@@ -2983,11 +2845,12 @@ declare abstract class AXConversationUserApi {
2983
2845
  /**
2984
2846
  * Get available users for conversation creation
2985
2847
  *
2848
+ * @param pagination - Pagination parameters
2986
2849
  * @param filters - Search filters
2987
- * @returns List of users
2850
+ * @returns Paginated list of users
2988
2851
  * @throws {AXConversationApiError} If request fails
2989
2852
  */
2990
- abstract getUsers(filters?: AXConversationUserSearchFilters): Promise<AXConversationParticipant[]>;
2853
+ abstract getUsers(pagination?: AXConversationPagination, filters?: AXConversationUserSearchFilters): Promise<AXConversationPaginatedResult<AXConversationParticipant>>;
2991
2854
  /**
2992
2855
  * Search users by query
2993
2856
  *
@@ -3020,6 +2883,10 @@ declare abstract class AXConversationUserApi {
3020
2883
  * @throws {AXConversationApiError} If request fails
3021
2884
  */
3022
2885
  abstract getUserPresence(userId: string): Promise<AXConversationPresenceUpdate>;
2886
+ /**
2887
+ * Get presence for multiple users (bulk hydration).
2888
+ */
2889
+ abstract getUsersPresence(userIds: string[]): Promise<AXConversationPresenceUpdate[]>;
3023
2890
  /**
3024
2891
  * Update current user presence
3025
2892
  *
@@ -3072,6 +2939,18 @@ declare abstract class AXConversationUserApi {
3072
2939
  * @throws {AXConversationApiError} If update fails
3073
2940
  */
3074
2941
  abstract updateUserSettings(settings: Record<string, unknown>): Promise<void>;
2942
+ /**
2943
+ * Get all conversation preferences for the current user.
2944
+ */
2945
+ abstract getConversationPreferences(): Promise<AXConversationRoomPreferencesMap>;
2946
+ /**
2947
+ * Get preferences for a single conversation.
2948
+ */
2949
+ abstract getConversationPreferencesForRoom(conversationId: string): Promise<AXConversationRoomPreferences>;
2950
+ /**
2951
+ * Update preferences for a conversation (current user's view).
2952
+ */
2953
+ abstract updateConversationPreferences(conversationId: string, preferences: Partial<AXConversationRoomPreferences>): Promise<AXConversationRoomPreferences>;
3075
2954
  /**
3076
2955
  * Create an API error
3077
2956
  * Helper method for consistent error creation
@@ -3085,6 +2964,27 @@ declare abstract class AXConversationUserApi {
3085
2964
  protected createError(code: string, message: string, statusCode?: number, details?: unknown): AXConversationApiError;
3086
2965
  }
3087
2966
 
2967
+ type AXConversationComposerGenerationPhase = 'idle' | 'generating' | 'stopping';
2968
+ declare class AXConversationComposerGenerationStateService {
2969
+ private readonly _phase;
2970
+ private readonly _cancelled$;
2971
+ /** Current generation lifecycle phase. */
2972
+ readonly phase: _angular_core.Signal<AXConversationComposerGenerationPhase>;
2973
+ /** Whether a background generation (e.g. AI response) is in progress. */
2974
+ readonly isGenerating: _angular_core.Signal<boolean>;
2975
+ /** Whether generation is being cancelled (spinner / locked until API finishes). */
2976
+ readonly isStopping: _angular_core.Signal<boolean>;
2977
+ /** Whether generation or stop-cleanup is in progress. */
2978
+ readonly isBusy: _angular_core.Signal<boolean>;
2979
+ /** Emits when the user presses the composer cancel/stop button. */
2980
+ readonly onCancelled: rxjs.Observable<void>;
2981
+ setGenerating(value: boolean): void;
2982
+ /** User requested cancel — enters `stopping` until {@link setGenerating}(false) is called. */
2983
+ cancel(): void;
2984
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerGenerationStateService, never>;
2985
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationComposerGenerationStateService>;
2986
+ }
2987
+
3088
2988
  /**
3089
2989
  * Central Registry Service
3090
2990
  * Provides unified access to all registries
@@ -3143,6 +3043,7 @@ declare class AXConversationService {
3143
3043
  private readonly fileService;
3144
3044
  private readonly platformId;
3145
3045
  private readonly errorHandler;
3046
+ private readonly apiLogger;
3146
3047
  readonly dialogService: AXDialogService;
3147
3048
  readonly popupService: AXPopupService;
3148
3049
  private readonly translation;
@@ -3150,14 +3051,20 @@ declare class AXConversationService {
3150
3051
  private readonly destroy$;
3151
3052
  /** Registry service - exposed for child services */
3152
3053
  readonly registry: AXConversationRegistryService;
3054
+ private readonly composerGenerationState;
3055
+ /** Whether the composer primary button is in cancel (generation) mode. */
3056
+ readonly isGenerating: _angular_core.Signal<boolean>;
3057
+ /** Whether cancel cleanup is in progress. */
3058
+ readonly isStopping: _angular_core.Signal<boolean>;
3059
+ /** Emits when the user cancels an in-progress generation from the composer. */
3060
+ readonly onGenerationCancelled: rxjs.Observable<void>;
3153
3061
  private readonly _activeConversationId;
3154
3062
  private readonly _loading;
3155
3063
  private readonly _loadingActiveMessages;
3064
+ private readonly _isForwardingMessage;
3156
3065
  private readonly _error;
3157
3066
  private readonly _conversationsPagination;
3158
3067
  private readonly _messagesPaginationByConversation;
3159
- /** Emits when the active conversation changes, cancelling per-conversation subscriptions. */
3160
- private readonly _conversationSwitch$;
3161
3068
  private readonly _messageReceived$;
3162
3069
  private readonly _messageUpdated$;
3163
3070
  private readonly _messageDeleted$;
@@ -3175,14 +3082,14 @@ declare class AXConversationService {
3175
3082
  readonly loading: _angular_core.Signal<boolean>;
3176
3083
  /** Loading state for the active conversation's message history */
3177
3084
  readonly loadingActiveMessages: _angular_core.Signal<boolean>;
3085
+ /** Whether a message forward operation is in progress. */
3086
+ readonly isForwardingMessage: _angular_core.Signal<boolean>;
3178
3087
  /** Sidebar conversation list pagination */
3179
3088
  readonly conversationsPagination: _angular_core.Signal<AXConversationPaginationState>;
3180
3089
  /** Active conversation message pagination */
3181
3090
  readonly activeMessagesPagination: _angular_core.Signal<AXConversationPaginationState>;
3182
3091
  /** Error state */
3183
3092
  readonly error: _angular_core.Signal<Error>;
3184
- /** Connection status */
3185
- readonly connectionStatus$: rxjs.Observable<_acorex_components_conversation.AXConversationConnectionStatus>;
3186
3093
  /** Error stream */
3187
3094
  readonly errors$: rxjs.Observable<_acorex_components_conversation.AXConversationError>;
3188
3095
  readonly onMessageReceived: rxjs.Observable<AXConversationMessage>;
@@ -3190,24 +3097,57 @@ declare class AXConversationService {
3190
3097
  readonly onMessageDeleted: rxjs.Observable<string>;
3191
3098
  readonly onTypingIndicator: rxjs.Observable<AXConversationTypingIndicator>;
3192
3099
  readonly onPresenceChange: rxjs.Observable<AXConversationPresenceUpdate>;
3193
- private readonly _messageCountRefresh$;
3194
- readonly onMessageCountRefresh: rxjs.Observable<{
3195
- messageId: string;
3196
- type: "reply" | "forward";
3197
- }>;
3198
3100
  private _currentUser;
3199
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3101
+ readonly currentUser: _angular_core.Signal<AXConversationUser>;
3102
+ readonly userPresenceMap: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3103
+ readonly presenceTimeTick: _angular_core.Signal<Map<string, AXConversationUserPresence>>;
3104
+ readonly typingRevision: _angular_core.Signal<Map<string, Map<string, number>>>;
3105
+ /** One-time async initialization (connect, user, conversations, realtime). */
3106
+ private initPromise;
3107
+ /** Generation counter — stale page-0 loads are ignored after conversation switches. */
3108
+ private messageLoadGeneration;
3109
+ /** Bumps when a conversation is created while a list load is in flight. */
3110
+ private conversationListLoadGeneration;
3111
+ /** Batched read-receipt queue keyed by conversation ID. */
3112
+ private readonly readQueue;
3113
+ private readFlushHandle;
3114
+ private presenceTickHandle?;
3115
+ private typingPruneHandle?;
3116
+ /** Outgoing typing indicator throttle state (composer -> API). */
3117
+ private readonly outgoingTypingLastEmitAt;
3118
+ private readonly outgoingTypingActive;
3119
+ private readonly outgoingTypingStopHandles;
3120
+ /** Session cache for available reaction emojis. */
3121
+ private availableReactionsCache;
3122
+ private availableReactionsPromise;
3200
3123
  constructor();
3124
+ /** Log and invoke an async API method from AXConversationService. */
3125
+ private callApi;
3126
+ /** Log a sync API invocation (e.g. realtime observable subscriptions). */
3127
+ private logApi;
3128
+ /**
3129
+ * Ensures the service is initialized exactly once.
3130
+ * Safe to call from container components or before any public API usage.
3131
+ */
3132
+ ensureInitialized(): Promise<void>;
3201
3133
  /**
3202
3134
  * Initialize the service
3203
3135
  * Connects to API and loads initial data
3204
3136
  */
3205
3137
  private initializeService;
3206
3138
  /**
3207
- * Subscribe to real-time events
3208
- * All subscriptions include error handling to prevent stream termination
3139
+ * Subscribe to real-time events from {@link AXConversationRealtimeApi}.
3140
+ * Binds every abstract subscription: messages (create/update/delete/status/read),
3141
+ * conversations (create/update/delete), typing indicators, and presence.
3209
3142
  */
3210
3143
  private subscribeToEvents;
3144
+ getUserPresence(userId: string): AXConversationUserPresence | undefined;
3145
+ getRoomPreferences(conversationId: string): AXConversationRoomPreferences;
3146
+ isAnyoneTyping(conversationId: string): boolean;
3147
+ getActiveTypingUserIds(conversationId: string): string[];
3148
+ getPeerPresence(conversation: AXConversation): AXConversationUserPresence | undefined;
3149
+ private hydrateUserPresence;
3150
+ private loadRoomPreferences;
3211
3151
  /**
3212
3152
  * Load conversations from server
3213
3153
  * Includes comprehensive error handling
@@ -3219,9 +3159,7 @@ declare class AXConversationService {
3219
3159
  */
3220
3160
  loadMoreConversations(page: number): Promise<boolean>;
3221
3161
  /**
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
3162
+ * Select a conversation and load page 0 of its message history.
3225
3163
  */
3226
3164
  selectConversation(conversationId: string): Promise<void>;
3227
3165
  closeActiveConversation(): void;
@@ -3242,6 +3180,7 @@ declare class AXConversationService {
3242
3180
  * Resolve a media reference to a playback/download URL.
3243
3181
  */
3244
3182
  resolveMediaUrl(reference: AXConversationUploaderReference, signal?: AbortSignal): Promise<string>;
3183
+ private resolveReplyTo;
3245
3184
  /**
3246
3185
  * Send a message
3247
3186
  * Uses optimistic UI updates - message appears immediately
@@ -3273,20 +3212,52 @@ declare class AXConversationService {
3273
3212
  */
3274
3213
  getAvailableReactions(): Promise<string[]>;
3275
3214
  /**
3276
- * Mark a single message as read
3277
- * Updates message status locally and syncs with server
3215
+ * Queue a message to be marked as read (batched/debounced API sync).
3216
+ */
3217
+ queueMessageAsRead(messageId: string): void;
3218
+ /**
3219
+ * Mark a single message as read (queues for batched sync).
3278
3220
  */
3279
3221
  markMessageAsRead(messageId: string): Promise<void>;
3222
+ private scheduleReadFlush;
3223
+ /**
3224
+ * Drop queued per-message read receipts without syncing to the API.
3225
+ * Used before conversation-level mark-as-read to avoid duplicate API calls.
3226
+ */
3227
+ private discardReadQueue;
3228
+ private flushReadQueue;
3280
3229
  /**
3281
3230
  * Mark conversation as read
3282
3231
  * Marks messages locally and syncs with server
3283
3232
  */
3284
3233
  markAsRead(conversationId: string): Promise<void>;
3234
+ /**
3235
+ * Set composer generation mode (shows cancel button instead of send/voice).
3236
+ * Call from message APIs while an AI or async response is in progress.
3237
+ */
3238
+ setGenerating(value: boolean): void;
3239
+ /**
3240
+ * Cancel an in-progress generation from the composer UI or programmatically.
3241
+ */
3242
+ cancelGeneration(): void;
3243
+ /**
3244
+ * Notify that the composer has draft content.
3245
+ * Emits typing indicators at most once per {@link AXConversationConfig.typingIndicatorThrottle}.
3246
+ */
3247
+ notifyComposerTyping(conversationId: string): void;
3248
+ /**
3249
+ * Notify that the composer no longer has draft content (or user left the chat).
3250
+ * Sends a single stop event when a typing indicator was previously emitted.
3251
+ */
3252
+ notifyComposerStoppedTyping(conversationId: string): void;
3253
+ private scheduleOutgoingTypingStop;
3254
+ private clearOutgoingTypingStop;
3285
3255
  /**
3286
3256
  * Send typing indicator
3287
3257
  * Non-critical operation, doesn't throw on failure
3288
3258
  */
3289
3259
  sendTypingIndicator(conversationId: string): Promise<void>;
3260
+ stopTypingIndicator(conversationId: string): Promise<void>;
3290
3261
  /**
3291
3262
  * Search conversations
3292
3263
  * Returns empty array on failure
@@ -3301,10 +3272,10 @@ declare class AXConversationService {
3301
3272
  */
3302
3273
  private handleMessageUpdate;
3303
3274
  /**
3304
- * Handle message count update
3305
- * Emits events when a message is a reply or forward so components can refresh counts
3275
+ * Bump reply/forward counts locally when realtime events arrive outside the active message list.
3306
3276
  */
3307
- private handleMessageCountUpdate;
3277
+ private syncMessageCountFromRealtime;
3278
+ private bumpMessageCount;
3308
3279
  /**
3309
3280
  * Handle message deletion
3310
3281
  */
@@ -3322,10 +3293,24 @@ declare class AXConversationService {
3322
3293
  * Updates conversation metadata including unread count, last message, etc.
3323
3294
  */
3324
3295
  private handleConversationUpdate;
3296
+ private handleConversationCreated;
3297
+ private handleConversationDeleted;
3298
+ private handleReadReceipt;
3299
+ private handleMessageStatusChange;
3300
+ /**
3301
+ * Insert or refresh a conversation in the in-memory inbox.
3302
+ * @param promote When true, bumps activity so the chat sorts to the top (create / reopen).
3303
+ */
3304
+ private syncConversationToInbox;
3305
+ private finalizeSentMessage;
3325
3306
  /**
3326
3307
  * Update conversation's last message
3327
3308
  */
3328
3309
  private updateConversationLastMessage;
3310
+ /** Keep sidebar preview in sync when the last cached message is edited or deleted. */
3311
+ private syncLastMessageIfRelevant;
3312
+ /** Recompute conversation preview after a message is removed from the local cache. */
3313
+ private refreshConversationLastMessage;
3329
3314
  /**
3330
3315
  * Update conversation properties
3331
3316
  * @param conversationId - Conversation ID
@@ -3337,7 +3322,7 @@ declare class AXConversationService {
3337
3322
  * @param conversationId - Conversation ID
3338
3323
  * @param settings - Partial settings to update
3339
3324
  */
3340
- updateConversationSettings(conversationId: string, settings: Partial<AXConversation['settings']>): Promise<void>;
3325
+ updateConversationSettings(conversationId: string, settings: Partial<AXConversationRoomPreferences>): Promise<void>;
3341
3326
  /**
3342
3327
  * Update conversation title
3343
3328
  * @param conversationId - Conversation ID
@@ -3361,15 +3346,19 @@ declare class AXConversationService {
3361
3346
  * @param participantIds - Array of participant user IDs
3362
3347
  * @param type - Conversation type (private, group, channel)
3363
3348
  * @param metadata - Optional metadata (title, avatar, etc.)
3364
- * @returns Created conversation
3349
+ * @param options - Optional flags (`forceCreate` recreates private chats even when one exists)
3350
+ * @returns Created or existing conversation
3365
3351
  */
3366
- createConversation(participantIds: string[], type: AXConversationType, metadata?: AXConversationMetadata): Promise<AXConversation>;
3352
+ createConversation(participantIds: string[], type: AXConversationType, metadata?: AXConversationMetadata, options?: {
3353
+ forceCreate?: boolean;
3354
+ }): Promise<AXConversation>;
3367
3355
  /**
3368
3356
  * Get available users for conversation creation
3369
- * @param query - Optional search query
3370
- * @returns List of users
3357
+ * @param filters - Optional search filters (e.g. `query`)
3358
+ * @param pagination - Pagination parameters
3359
+ * @returns Paginated list of users
3371
3360
  */
3372
- getUsers(query?: string): Promise<AXConversationParticipant[]>;
3361
+ getUsers(filters?: AXConversationUserSearchFilters, pagination?: AXConversationPagination): Promise<AXConversationPaginatedResult<AXConversationParticipant>>;
3373
3362
  /**
3374
3363
  * Mark entire conversation as read
3375
3364
  * @param conversationId - Conversation ID
@@ -3393,11 +3382,6 @@ declare class AXConversationService {
3393
3382
  * @returns Number of times forwarded
3394
3383
  */
3395
3384
  getForwardCount(messageId: string): Promise<number>;
3396
- /**
3397
- * Disconnect and cleanup
3398
- * Cleanly closes all connections and resources
3399
- */
3400
- disconnect(): Promise<void>;
3401
3385
  /**
3402
3386
  * Archive conversation
3403
3387
  * @param conversationId - Conversation ID
@@ -3476,6 +3460,10 @@ declare class AXConversationService {
3476
3460
  * @param caption - Optional caption
3477
3461
  */
3478
3462
  forwardMessage(messageId: string, conversationIds: string[], caption?: string): Promise<void>;
3463
+ /**
3464
+ * Runs a forward operation while locking all forward actions until it completes.
3465
+ */
3466
+ runWithForwardingLock<T>(task: () => Promise<T>): Promise<T>;
3479
3467
  /**
3480
3468
  * Search messages in conversation
3481
3469
  * @param conversationId - Conversation ID
@@ -3530,7 +3518,7 @@ declare class AXConversationService {
3530
3518
  * @param status - Presence status
3531
3519
  * @param statusText - Optional status text
3532
3520
  */
3533
- updatePresence(status: 'online' | 'offline' | 'away' | 'busy' | 'invisible', statusText?: string): Promise<void>;
3521
+ updatePresence(status: AXConversationPresenceStatus, statusText?: string): Promise<void>;
3534
3522
  /**
3535
3523
  * Validate message content before sending
3536
3524
  * Uses centralized validation utilities for consistency
@@ -3678,6 +3666,7 @@ declare class AXConversationForwardMessageDialogComponent implements OnInit {
3678
3666
  readonly forwardListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
3679
3667
  readonly forwardList: _angular_core.Signal<AXListComponent>;
3680
3668
  readonly forwardListDataSource: AXDataSource<unknown>;
3669
+ readonly isForwarding: _angular_core.Signal<boolean>;
3681
3670
  readonly canForward: _angular_core.Signal<boolean>;
3682
3671
  private readonly _syncPopupTitleEffect;
3683
3672
  ngOnInit(): void;
@@ -3711,18 +3700,21 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3711
3700
  private readonly infoBarService;
3712
3701
  private readonly translation;
3713
3702
  private readonly document;
3703
+ private readonly platform;
3704
+ private readonly actionSheetService;
3714
3705
  protected readonly config: Required<_acorex_components_conversation.AXConversationConfig>;
3715
3706
  /**
3716
- * Background for the message list scroll area from config, or the built-in soft gradient when unset/empty.
3707
+ * Background for the message list scroll area from config, or the built-in soft wash when unset/empty.
3717
3708
  * Set `messageListBackground` to `transparent` or `none` for a flat look.
3709
+ * Supports `{ light, dark }` for theme-specific backgrounds.
3718
3710
  */
3719
- messageListBackgroundStyle(): string;
3711
+ readonly messageListUsesDefaultWallpaper: _angular_core.Signal<boolean>;
3712
+ readonly messageListWallpaperDark: _angular_core.Signal<boolean>;
3713
+ readonly messageListBackgroundStyle: _angular_core.Signal<string>;
3720
3714
  resolvedEmptyStateComponent(): Type<AXConversationMessageListEmptyComponent>;
3721
3715
  /** Fallback when no conversation is active and no `ax-conversation-message-list-no-active` content is projected. */
3722
3716
  protected readonly noActiveFallbackComponent: typeof AXConversationMessageListNoActiveDefaultComponent;
3723
3717
  private readonly timeouts;
3724
- private readonly replyCounts;
3725
- private readonly forwardCounts;
3726
3718
  readonly reactionPickerTarget: _angular_core.WritableSignal<string>;
3727
3719
  readonly reactionPickerElement: _angular_core.WritableSignal<HTMLElement>;
3728
3720
  readonly reactionPickerPlacement: _angular_core.WritableSignal<AXPlacement>;
@@ -3731,9 +3723,13 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3731
3723
  readonly contextMenuMessageId: _angular_core.WritableSignal<string>;
3732
3724
  /** True while files are dragged over the message list drop zone. */
3733
3725
  readonly messageListDragging: _angular_core.WritableSignal<boolean>;
3726
+ /** True when the message list uses single-column adaptive layout (matches CSS container query). */
3727
+ readonly isAdaptiveWideLayout: _angular_core.WritableSignal<boolean>;
3734
3728
  /** While true, older history is being prepended — do not auto-scroll to the latest message. */
3735
3729
  private restoringScrollAfterPrepend;
3730
+ private adaptiveLayoutResizeObserver?;
3736
3731
  readonly availableReactions: _angular_core.WritableSignal<string[]>;
3732
+ private reactionsLoading;
3737
3733
  private get registry();
3738
3734
  /** Message list element reference */
3739
3735
  private readonly messageListRef;
@@ -3749,6 +3745,11 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3749
3745
  readonly showScrollButton: _angular_core.WritableSignal<boolean>;
3750
3746
  /** Active conversation */
3751
3747
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
3748
+ readonly isGroupConversation: _angular_core.Signal<boolean>;
3749
+ /** Placeholder indices for the initial message list skeleton. */
3750
+ protected readonly loadingSkeletonItems: readonly [0, 1, 2, 3, 4, 5];
3751
+ /** Whether the active conversation allows message reactions. */
3752
+ readonly reactionsEnabled: _angular_core.Signal<boolean>;
3752
3753
  /** Messages */
3753
3754
  readonly messages: _angular_core.Signal<AXConversationMessage[]>;
3754
3755
  /** Message action event */
@@ -3757,7 +3758,7 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3757
3758
  action: string;
3758
3759
  }>;
3759
3760
  /** Current user from service */
3760
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3761
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
3761
3762
  /** Message grouped by date - use service */
3762
3763
  readonly messageGroups: _angular_core.Signal<{
3763
3764
  date: string;
@@ -3766,6 +3767,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3766
3767
  }[]>;
3767
3768
  constructor();
3768
3769
  private intersectionObserver?;
3770
+ private readonly readIntersectionObserver;
3771
+ private readonly observedReadMessageIds;
3769
3772
  /**
3770
3773
  * Setup intersection observer to mark messages as read when visible
3771
3774
  */
@@ -3780,8 +3783,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3780
3783
  getBubbleClasses(message: AXConversationMessage): string;
3781
3784
  /** Check if message is from current user */
3782
3785
  isOwnMessage(message: AXConversationMessage): boolean;
3783
- /** Should show avatar */
3784
- shouldShowAvatar(message: AXConversationMessage): boolean;
3786
+ /** Whether the avatar slot is rendered (visibility is CSS-controlled per layout mode). */
3787
+ shouldRenderAvatar(message: AXConversationMessage): boolean;
3785
3788
  /** Should show sender name */
3786
3789
  shouldShowSenderName(message: AXConversationMessage): boolean;
3787
3790
  /** Get sender name */
@@ -3793,13 +3796,12 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3793
3796
  /** Resolve renderer component for message */
3794
3797
  getRendererComponent(message: AXConversationMessage): Type<_acorex_components_conversation.AXConversationMessageRendererComponent>;
3795
3798
  /** Resolve lazy renderer loader for message */
3799
+ private static readonly fallbackRendererLoader;
3796
3800
  getRendererComponentLoader(message: AXConversationMessage): (() => Promise<Type<_acorex_components_conversation.AXConversationMessageRendererComponent>>) | (() => Promise<typeof _acorex_components_conversation.AXConversationFallbackRendererComponent>);
3797
3801
  /** Provide inputs for the dynamic renderer */
3798
3802
  getRendererInputs(message: AXConversationMessage): {
3799
3803
  message: AXConversationMessage;
3800
3804
  };
3801
- /** Get status icon */
3802
- getStatusIcon(message: AXConversationMessage): string;
3803
3805
  /** Get status icon CSS classes */
3804
3806
  getStatusIconClasses(message: AXConversationMessage): string;
3805
3807
  /** Get status tooltip text */
@@ -3820,6 +3822,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3820
3822
  userIds: string[];
3821
3823
  hasReacted: boolean;
3822
3824
  }): string;
3825
+ /** Whether reactions can be shown or added for a message in the active conversation. */
3826
+ messageSupportsReactions(message: AXConversationMessage): boolean;
3823
3827
  /** Toggle reaction picker */
3824
3828
  toggleReactionPicker(message: AXConversationMessage, event: MouseEvent): void;
3825
3829
  /** Close reaction picker */
@@ -3832,8 +3836,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3832
3836
  onReactionClickById(messageId: string, emoji: string): void;
3833
3837
  /** Get message by ID */
3834
3838
  getMessageById(messageId: string): AXConversationMessage | undefined;
3835
- /** Load available reactions from API */
3836
- private loadAvailableReactions;
3839
+ /** Load available reactions when the picker is opened (session-cached in service). */
3840
+ private ensureAvailableReactions;
3837
3841
  /** Get message actions from registry */
3838
3842
  getMessageActions(message: AXConversationMessage): _acorex_components_conversation.AXConversationMessageAction[];
3839
3843
  /** Handle reaction click */
@@ -3872,15 +3876,8 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3872
3876
  /** Get ARIA label for message */
3873
3877
  getMessageAriaLabel(message: AXConversationMessage): string;
3874
3878
  getDateSeparatorAriaLabel(dateLabel: string): string;
3875
- /** Get reply count for a message (fetches from API across all conversations) */
3876
3879
  getReplyCount(message: AXConversationMessage): number;
3877
- /** Get forward count for a message (fetches from API across all conversations) */
3878
3880
  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
3881
  onMessageListDragEnter(): void;
3885
3882
  onMessageListDragLeave(): void;
3886
3883
  /** Open the matching composer picker popup when files are dropped on the message list. */
@@ -3890,30 +3887,16 @@ declare class AXConversationMessageListComponent implements OnDestroy {
3890
3887
  handleMessageContextMenuOpening(event: AXContextMenuOpeningEvent, message: AXConversationMessage): void;
3891
3888
  /** Handle context menu item click for messages */
3892
3889
  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
3890
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListComponent, never>;
3907
3891
  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
3892
  }
3909
3893
 
3910
3894
  declare class AXConversationMessageListService {
3911
3895
  private readonly conversationService;
3912
- private readonly config;
3913
3896
  private get registry();
3914
3897
  readonly activeConversation: _angular_core.Signal<_acorex_components_conversation.AXConversation>;
3915
3898
  readonly activeMessages: _angular_core.Signal<AXConversationMessage[]>;
3916
- readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationParticipant>;
3899
+ readonly currentUser: _angular_core.Signal<_acorex_components_conversation.AXConversationUser>;
3917
3900
  /** Initial message history load (conversation switch) */
3918
3901
  readonly loading: _angular_core.Signal<boolean>;
3919
3902
  /** Loading older messages (scroll-up pagination) */
@@ -3926,9 +3909,19 @@ declare class AXConversationMessageListService {
3926
3909
  readonly scrollRequests: _angular_core.WritableSignal<number>;
3927
3910
  /** Live renderer instances keyed by message id (for message actions). */
3928
3911
  private readonly _rendererInstances;
3912
+ /**
3913
+ * Reply counts merged from API fields and loaded messages.
3914
+ */
3915
+ readonly replyCounts: _angular_core.Signal<Map<string, number>>;
3916
+ /**
3917
+ * Forward counts merged from API fields and loaded messages.
3918
+ */
3919
+ readonly forwardCounts: _angular_core.Signal<Map<string, number>>;
3929
3920
  registerRendererInstance(messageId: string, instance: AXConversationMessageRendererComponent): void;
3930
3921
  unregisterRendererInstance(messageId: string): void;
3931
3922
  getRendererInstance(messageId: string): AXConversationMessageRendererComponent | undefined;
3923
+ getReplyCount(messageId: string): number;
3924
+ getForwardCount(messageId: string): number;
3932
3925
  /** Message grouped by date */
3933
3926
  readonly messageGroups: _angular_core.Signal<{
3934
3927
  date: string;
@@ -3948,13 +3941,111 @@ declare class AXConversationMessageListService {
3948
3941
  reactToMessage(messageId: string, emoji: string): Promise<void>;
3949
3942
  /** Request message list to scroll to bottom */
3950
3943
  requestScrollToBottom(): void;
3944
+ private buildCountMap;
3951
3945
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationMessageListService, never>;
3952
3946
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationMessageListService>;
3953
3947
  }
3954
3948
 
3949
+ declare class AXConversationAvatarPickerComponent {
3950
+ readonly fileInput: _angular_core.Signal<ElementRef<HTMLInputElement>>;
3951
+ readonly showClearButton: _angular_core.InputSignal<boolean>;
3952
+ readonly avatarUrl: _angular_core.ModelSignal<string>;
3953
+ readonly onFileSelected: _angular_core.OutputEmitterRef<string>;
3954
+ triggerFileInput(): void;
3955
+ onFileInputChange(event: Event): Promise<void>;
3956
+ clearAvatar(): void;
3957
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarPickerComponent, never>;
3958
+ 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>;
3959
+ }
3960
+
3961
+ /**
3962
+ * Pluggable avatar components for the conversation UI.
3963
+ * Register via `provideConversation({ avatarComponents: { user, conversation } })`.
3964
+ * When only `user` is registered, a built-in conversation avatar host is wired automatically.
3965
+ */
3966
+
3967
+ /** Custom user avatar (e.g. platform `axp-user-avatar`). */
3968
+ interface AXConversationUserAvatarComponent {
3969
+ readonly userId: InputSignal<string>;
3970
+ readonly size: InputSignal<number>;
3971
+ /** Optional resolved display name (e.g. bot/assist peer title). */
3972
+ readonly displayName?: InputSignal<string | undefined>;
3973
+ /** Optional resolved avatar URL when `userId` is not a platform user row. */
3974
+ readonly displayAvatar?: InputSignal<string | undefined>;
3975
+ /** Optional icon class when no avatar image is available. */
3976
+ readonly displayIcon?: InputSignal<string | undefined>;
3977
+ }
3978
+ /** Optional custom group/channel conversation avatar. */
3979
+ interface AXConversationConversationAvatarComponent {
3980
+ readonly conversationId: InputSignal<string>;
3981
+ readonly size: InputSignal<number>;
3982
+ /** Optional resolved display name for the conversation. */
3983
+ readonly displayName?: InputSignal<string | undefined>;
3984
+ /** Optional resolved avatar URL when no platform conversation row exists. */
3985
+ readonly displayAvatar?: InputSignal<string | undefined>;
3986
+ /** Optional icon class when no avatar image is available. */
3987
+ readonly displayIcon?: InputSignal<string | undefined>;
3988
+ }
3989
+ type AXConversationAvatarKind = 'user' | 'conversation' | 'auto';
3990
+ declare const AX_CONVERSATION_USER_AVATAR_COMPONENT: InjectionToken<Type<AXConversationUserAvatarComponent>>;
3991
+ declare const AX_CONVERSATION_CONVERSATION_AVATAR_COMPONENT: InjectionToken<Type<AXConversationConversationAvatarComponent>>;
3992
+ interface AXConversationAvatarComponents {
3993
+ user?: Type<AXConversationUserAvatarComponent>;
3994
+ conversation?: Type<AXConversationConversationAvatarComponent>;
3995
+ }
3996
+
3997
+ declare class AXConversationAvatarComponent {
3998
+ private readonly conversationService;
3999
+ private readonly userAvatarComponent;
4000
+ private readonly conversationAvatarComponent;
4001
+ readonly kind: _angular_core.InputSignal<AXConversationAvatarKind>;
4002
+ readonly userId: _angular_core.InputSignal<string>;
4003
+ readonly conversation: _angular_core.InputSignal<AXConversation>;
4004
+ readonly message: _angular_core.InputSignal<AXConversationMessage>;
4005
+ readonly size: _angular_core.InputSignal<number>;
4006
+ readonly showStatus: _angular_core.InputSignal<boolean>;
4007
+ readonly name: _angular_core.InputSignal<string>;
4008
+ readonly avatar: _angular_core.InputSignal<string>;
4009
+ readonly icon: _angular_core.InputSignal<string>;
4010
+ private readonly currentUserId;
4011
+ readonly resolvedKind: _angular_core.Signal<"user" | "conversation">;
4012
+ readonly resolvedUserId: _angular_core.Signal<string>;
4013
+ readonly customComponent: _angular_core.Signal<Type<unknown>>;
4014
+ readonly customInputs: _angular_core.Signal<Record<string, unknown>>;
4015
+ readonly filteredCustomInputs: _angular_core.Signal<Record<string, unknown>>;
4016
+ readonly fallbackDisplay: _angular_core.Signal<{
4017
+ name: string;
4018
+ avatar: string;
4019
+ icon: string;
4020
+ }>;
4021
+ readonly fallbackInitials: _angular_core.Signal<string>;
4022
+ readonly resolvedStatus: _angular_core.Signal<_acorex_components_conversation.AXConversationPresenceStatus>;
4023
+ readonly statusBadgePresence: _angular_core.Signal<"online" | "offline" | "away" | "busy">;
4024
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationAvatarComponent, never>;
4025
+ 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>;
4026
+ }
4027
+
4028
+ interface AXConversationRegistryComponentRef {
4029
+ component?: Type<unknown>;
4030
+ componentLoader?: () => Promise<Type<unknown>>;
4031
+ }
4032
+ declare class AXConversationRegistryComponentOutletComponent {
4033
+ readonly component: _angular_core.InputSignal<Type<unknown>>;
4034
+ readonly componentLoader: _angular_core.InputSignal<() => Promise<Type<unknown>>>;
4035
+ readonly inputs: _angular_core.InputSignal<Record<string, unknown>>;
4036
+ readonly resolvedComponent: _angular_core.WritableSignal<Type<unknown>>;
4037
+ /** Avoid re-loading when the parent re-binds the same lazy loader reference. */
4038
+ private activeLoader;
4039
+ constructor();
4040
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationRegistryComponentOutletComponent, never>;
4041
+ 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>;
4042
+ }
4043
+ /** Resolve a registry component reference, preferring lazy loaders when provided. */
4044
+ declare function hasRegistryComponent(ref?: AXConversationRegistryComponentRef): boolean;
4045
+
3955
4046
  declare class AXConversationSidebarService {
3956
4047
  private readonly conversationService;
3957
- private readonly config;
4048
+ constructor();
3958
4049
  private get registry();
3959
4050
  readonly searchQuery: _angular_core.WritableSignal<string>;
3960
4051
  readonly activeTabId: _angular_core.WritableSignal<string>;
@@ -3963,7 +4054,6 @@ declare class AXConversationSidebarService {
3963
4054
  readonly loading: _angular_core.Signal<boolean>;
3964
4055
  readonly hasMoreConversations: _angular_core.Signal<boolean>;
3965
4056
  readonly enabledTabs: _angular_core.Signal<_acorex_components_conversation.AXConversationTab[]>;
3966
- private filterCache;
3967
4057
  readonly filteredConversations: _angular_core.Signal<AXConversation[]>;
3968
4058
  /**
3969
4059
  * Filter and sort conversations
@@ -3995,6 +4085,8 @@ declare class AXConversationSidebarComponent implements OnDestroy {
3995
4085
  private readonly conversationService;
3996
4086
  private readonly popupService;
3997
4087
  private readonly translation;
4088
+ private readonly ngZone;
4089
+ private readonly cdr;
3998
4090
  /** Conversation selected event */
3999
4091
  readonly conversationSelected: _angular_core.OutputEmitterRef<AXConversation>;
4000
4092
  /** Search debouncing */
@@ -4005,6 +4097,8 @@ declare class AXConversationSidebarComponent implements OnDestroy {
4005
4097
  readonly loading: _angular_core.Signal<boolean>;
4006
4098
  readonly loadingMore: _angular_core.WritableSignal<boolean>;
4007
4099
  readonly hasMoreConversations: _angular_core.Signal<boolean>;
4100
+ readonly isSidebarTabsHorizontal: _angular_core.Signal<boolean>;
4101
+ readonly sidebarTabLocation: _angular_core.Signal<AXTabLocation>;
4008
4102
  constructor();
4009
4103
  /** Handle search input change with debouncing */
4010
4104
  onSearchChange(value: string): void;
@@ -4038,6 +4132,10 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4038
4132
  conversationService: AXConversationService;
4039
4133
  private readonly toastService;
4040
4134
  private readonly translation;
4135
+ private readonly config;
4136
+ private readonly destroyRef;
4137
+ private searchDebounceTimer?;
4138
+ constructor();
4041
4139
  /**
4042
4140
  * Injected by {@link AXPopupComponent} when this dialog is opened via {@link AXPopupService}.
4043
4141
  * Required for `setTitle` / dynamic header — {@link AXBasePageComponent#setTitle} is otherwise unset.
@@ -4061,6 +4159,7 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4061
4159
  private readonly _resetWizardWhenSingleEffect;
4062
4160
  private readonly _syncPopupTitleEffect;
4063
4161
  readonly usersListEmptyTpl: _angular_core.Signal<TemplateRef<unknown>>;
4162
+ readonly usersListLoadingTpl: _angular_core.Signal<TemplateRef<unknown>>;
4064
4163
  readonly usersList: _angular_core.Signal<AXListComponent>;
4065
4164
  readonly usersListDataSource: AXDataSource<unknown>;
4066
4165
  onCancel(): void;
@@ -4070,7 +4169,7 @@ declare class AXConversationNewDialogComponent extends AXBasePageComponent {
4070
4169
  onSearchChange(value: string): void;
4071
4170
  isUserSelected(id: string): boolean;
4072
4171
  userFromItem(item: unknown): AXConversationParticipant | null;
4073
- private filteredUsers;
4172
+ private mergeUsersCache;
4074
4173
  onCreateConversation(): Promise<void>;
4075
4174
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationNewDialogComponent, never>;
4076
4175
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXConversationNewDialogComponent, "ax-conversation-new-dialog", never, { "__popup__": { "alias": "__popup__"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -4104,25 +4203,24 @@ declare class AXConversationInfiniteScrollDirective {
4104
4203
  /**
4105
4204
  * Conversation feature flags for configurable bundle size.
4106
4205
  */
4107
- type AXConversationMediaPickerFeature = 'image' | 'video' | 'audio' | 'file' | 'voice' | 'location';
4108
4206
  type AXConversationComposerTabFeature = 'emoji' | 'sticker';
4109
4207
  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. */
4208
+ /** Enabled built-in composer popup tabs (`emoji`, `sticker`). Defaults to none when omitted. */
4113
4209
  composerTabs?: AXConversationComposerTabFeature[];
4114
4210
  }
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
4211
  declare function resolveConversationComposerTabs(features?: AXConversationFeatures): readonly AXConversationComposerTabFeature[];
4119
- declare function isMediaPickerEnabled(picker: AXConversationMediaPickerFeature, features?: AXConversationFeatures): boolean;
4120
4212
  declare function isComposerTabEnabled(tab: AXConversationComposerTabFeature, features?: AXConversationFeatures): boolean;
4121
4213
 
4122
4214
  /**
4123
4215
  * Conversation Configuration Interface
4124
4216
  * Centralized configuration values to avoid magic numbers
4125
4217
  */
4218
+ /**
4219
+ * Sidebar conversation tabs layout.
4220
+ * - `vertical`: horizontal tab strip above the conversation list.
4221
+ * - `horizontal`: vertical tab strip at inline-start beside the list (`ax-tabs` location `start`).
4222
+ */
4223
+ type AXConversationSidebarTabsOrientation = 'vertical' | 'horizontal';
4126
4224
  /**
4127
4225
  * Main configuration interface for the conversation component
4128
4226
  */
@@ -4137,13 +4235,14 @@ interface AXConversationConfig {
4137
4235
  infiniteScrollThreshold?: number;
4138
4236
  /** Typing indicator timeout in milliseconds */
4139
4237
  typingIndicatorTimeout?: number;
4140
- /** Typing indicator throttle in milliseconds (for rate limiting) */
4238
+ /** Typing indicator emit throttle in milliseconds while composing (default: 3000) */
4141
4239
  typingIndicatorThrottle?: number;
4240
+ /** How long to show received typing indicators in the UI (default: 4000) */
4241
+ typingDisplayDuration?: number;
4142
4242
  /** Message highlight duration in milliseconds */
4143
4243
  messageHighlightDuration?: number;
4144
4244
  /** Search debounce delay in milliseconds */
4145
4245
  debounceSearch?: number;
4146
- /** Date separator inactivity fade delay in milliseconds */
4147
4246
  /** Maximum messages per conversation */
4148
4247
  maxMessagesPerConversation?: number;
4149
4248
  /** Maximum total messages in store */
@@ -4156,8 +4255,11 @@ interface AXConversationConfig {
4156
4255
  maxSidebarWidth?: number;
4157
4256
  /** Default sidebar width in pixels */
4158
4257
  defaultSidebarWidth?: number;
4159
- /** Filter cache size */
4160
- filterCacheSize?: number;
4258
+ /**
4259
+ * Sidebar conversation tabs layout.
4260
+ * `vertical` places a horizontal tab strip above the list; `horizontal` places a vertical tab strip at inline-start beside the list.
4261
+ */
4262
+ sidebarTabsOrientation?: AXConversationSidebarTabsOrientation;
4161
4263
  /** Maximum message length in characters */
4162
4264
  maxMessageLength?: number;
4163
4265
  /** Minimum message length in characters */
@@ -4166,14 +4268,24 @@ interface AXConversationConfig {
4166
4268
  maxFilesPerMessage?: number;
4167
4269
  /** Threshold for marking messages as read (0.0 to 1.0, default: 0.3) */
4168
4270
  messageReadThreshold?: number;
4271
+ /** Debounce window (ms) before flushing batched read-receipt API calls (default: 3000) */
4272
+ messageReadDebounce?: number;
4273
+ /**
4274
+ * When true, marks the whole conversation as read once when it is selected (single API call).
4275
+ * Per-message intersection observer still handles new messages received while the chat is open.
4276
+ */
4277
+ markConversationReadOnSelect?: boolean;
4169
4278
  /**
4170
4279
  * CSS `background` for the message list (`ax-conversation-message-list` area, all states: loading, empty, messages).
4171
4280
  * 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.
4281
+ * Pass a string for the same value in both themes, or `{ light, dark }` for theme-specific backgrounds.
4282
+ * Empty string = Telegram-inspired theme-aware library default (`{ light, dark }`). `transparent` or `none` = flat background.
4173
4283
  */
4174
- messageListBackground?: string;
4284
+ messageListBackground?: AXConversationMessageListBackground;
4175
4285
  /** Optional feature flags to reduce bundle size per app. */
4176
4286
  features?: AXConversationFeatures;
4287
+ /** Log API calls made by AXConversationService to the console (default: false). */
4288
+ debugApiLogging?: boolean;
4177
4289
  }
4178
4290
 
4179
4291
  /**
@@ -4209,29 +4321,6 @@ declare const AX_CONVERSATION_CONFIG: InjectionToken<Required<AXConversationConf
4209
4321
  */
4210
4322
  declare const AX_CONVERSATION_ERROR_HANDLER_CONFIG: InjectionToken<Partial<AXConversationErrorHandlerConfig>>;
4211
4323
 
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
4324
  /**
4236
4325
  * Registry Configuration Tokens
4237
4326
  * Injection tokens for configuring default registry values
@@ -4249,511 +4338,57 @@ declare const AX_CONVERSATION_DEFAULT_MESSAGE_RENDERERS: InjectionToken<AXConver
4249
4338
  */
4250
4339
  declare const AX_CONVERSATION_DEFAULT_MESSAGE_ACTIONS: InjectionToken<AXConversationMessageAction[]>;
4251
4340
  /**
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;
4341
+ * Default composer tabs configuration
4342
+ * Provide this token to override default composer tabs (emoji, stickers, etc.)
4343
+ */
4344
+ declare const AX_CONVERSATION_DEFAULT_COMPOSER_TABS: InjectionToken<AXConversationComposerTab[]>;
4345
+ /**
4346
+ * Default composer actions configuration
4347
+ * Provide this token to override default composer actions (attach, voice, etc.)
4348
+ */
4349
+ declare const AX_CONVERSATION_DEFAULT_COMPOSER_ACTIONS: InjectionToken<AXConversationComposerAction[]>;
4350
+ /**
4351
+ * Default conversation tabs configuration
4352
+ * Provide this token to override default conversation tabs (all, private, groups, etc.)
4353
+ */
4354
+ declare const AX_CONVERSATION_DEFAULT_CONVERSATION_TABS: InjectionToken<AXConversationTab[]>;
4355
+ /**
4356
+ * Default info bar actions configuration
4357
+ * Provide this token to override default info bar actions (mute, archive, block, etc.)
4358
+ */
4359
+ declare const AX_CONVERSATION_DEFAULT_INFO_BAR_ACTIONS: InjectionToken<AXConversationInfoBarAction[]>;
4360
+ /**
4361
+ * Default conversation item actions configuration
4362
+ * Provide this token to override default conversation item actions (mute, delete, archive, etc.)
4363
+ */
4364
+ declare const AX_CONVERSATION_DEFAULT_CONVERSATION_ITEM_ACTIONS: InjectionToken<AXConversationItemAction[]>;
4365
+ /**
4366
+ * Registry configuration interface
4367
+ */
4368
+ interface AXConversationRegistryConfiguration {
4750
4369
  /**
4751
- * Delay helper
4370
+ * Additional message renderers to register (built-in renderers are automatic).
4371
+ * Each {@link AXConversationMessageRenderer} may include optional `composerActions` for co-located send UX.
4752
4372
  */
4753
- private delay;
4754
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationIndexedDbMessageAiApi, never>;
4755
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationIndexedDbMessageAiApi>;
4373
+ messageRenderers?: AXConversationMessageRenderer[];
4374
+ /** Message actions to register by default */
4375
+ messageActions?: AXConversationMessageAction[];
4376
+ /** Composer tabs to register by default */
4377
+ composerTabs?: AXConversationComposerTab[];
4378
+ /** Composer actions to register by default */
4379
+ composerActions?: AXConversationComposerAction[];
4380
+ /** Conversation tabs to register by default */
4381
+ conversationTabs?: AXConversationTab[];
4382
+ /** Info bar actions to register by default */
4383
+ infoBarActions?: AXConversationInfoBarAction[];
4384
+ /** Conversation item actions to register by default */
4385
+ conversationItemActions?: AXConversationItemAction[];
4756
4386
  }
4387
+ /**
4388
+ * Complete registry configuration token
4389
+ * Provide this for comprehensive registry configuration
4390
+ */
4391
+ declare const AX_CONVERSATION_REGISTRY_CONFIG: InjectionToken<AXConversationRegistryConfiguration>;
4757
4392
 
4758
4393
  declare const AX_CONVERSATION_AUDIO_PRESENTATION: {
4759
4394
  readonly icon: "fa-light fa-music text-amber-500";
@@ -4777,7 +4412,10 @@ declare function applyAudioLocalPreview(payload: AXConversationMessagePayload, l
4777
4412
  * Shared upload state and helpers for composer media pickers.
4778
4413
  */
4779
4414
 
4415
+ /** Stable id for `@for` tracking while upload state is patched immutably. */
4416
+ declare function createPickerUploadItemId(): string;
4780
4417
  interface AXConversationComposerPickerUploadItem {
4418
+ id: string;
4781
4419
  file: File;
4782
4420
  preview?: string;
4783
4421
  duration?: number;
@@ -4827,16 +4465,14 @@ declare function notifyPickerValidationErrors(toast: AXToastService, translation
4827
4465
  file: File;
4828
4466
  errors: AXValidationRuleResult[];
4829
4467
  }[]): 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;
4468
+ /** Close popup/action-sheet host or inline composer shell after send/cancel. */
4469
+ declare function dismissComposerPickerHost(composerService: AXConversationComposerService, popupRef?: AXPopupRef | null, actionSheetRef?: AXActionSheetRef | null): void;
4834
4470
 
4835
4471
  interface AXConversationAudioFile extends AXConversationComposerPickerUploadItem {
4836
4472
  duration?: number;
4837
4473
  dataUrl?: string;
4838
4474
  }
4839
- declare class AXConversationAudioPickerComponent implements OnDestroy {
4475
+ declare class AXConversationAudioPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
4840
4476
  private uploadsDismissed;
4841
4477
  private retainUploadedOnDismiss;
4842
4478
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -4851,16 +4487,20 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4851
4487
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4852
4488
  readonly maxFiles: _angular_core.InputSignal<number>;
4853
4489
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4490
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4854
4491
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4492
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
4855
4493
  readonly catalogFileType: "conversation-audio";
4856
4494
  readonly audioFiles: _angular_core.WritableSignal<AXConversationAudioFile[]>;
4857
4495
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4496
+ private readonly pickerShell;
4858
4497
  readonly typeIconClass: "fa-light fa-music text-amber-500";
4859
4498
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-music text-amber-500" | "fa-light fa-cloud-arrow-up">;
4860
4499
  private catalogFileTypeDef?;
4861
4500
  caption: string;
4862
4501
  readonly allowMultiple: _angular_core.Signal<boolean>;
4863
4502
  constructor();
4503
+ activate(): Promise<void>;
4864
4504
  private createUtilityContext;
4865
4505
  private getCatalogFileTypeDef;
4866
4506
  private runUtility;
@@ -4872,6 +4512,8 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4872
4512
  canSend(): boolean;
4873
4513
  getUploadingLabel(progress: number): string;
4874
4514
  getCancelUploadLabel(): string;
4515
+ getHeaderTitle(): string;
4516
+ onAddMoreFiles(): void;
4875
4517
  cancel(): void;
4876
4518
  ngOnDestroy(): void;
4877
4519
  private dismissPicker;
@@ -4882,11 +4524,13 @@ declare class AXConversationAudioPickerComponent implements OnDestroy {
4882
4524
  getSelectedCountText(): string;
4883
4525
  getSendText(): string;
4884
4526
  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>;
4527
+ 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
4528
  }
4887
4529
 
4888
4530
  declare const AX_CONVERSATION_COMPOSER_EMOJI_TAB: AXConversationComposerTab;
4889
4531
  declare const AX_CONVERSATION_COMPOSER_STICKER_TAB: AXConversationComposerTab;
4532
+ /** Built-in composer popup tabs keyed by {@link AXConversationComposerTabFeature}. */
4533
+ declare const AX_CONVERSATION_BUILTIN_COMPOSER_TABS: Record<AXConversationComposerTabFeature, AXConversationComposerTab>;
4890
4534
 
4891
4535
  interface AXConversationEmoji {
4892
4536
  char: string;
@@ -4942,20 +4586,16 @@ declare function fileItemFromUpload(file: File, result: AXConversationUploaderRe
4942
4586
  declare function mergeFileUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
4943
4587
  declare function applyFileLocalPreview(payload: AXConversationMessagePayload, localUrl: string, mimeType?: string): AXConversationMessagePayload;
4944
4588
 
4945
- interface AXConversationAttachedFile {
4946
- file: File;
4947
- preview?: string;
4589
+ interface AXConversationPickerFileBadge {
4590
+ ext: string;
4591
+ color: string;
4592
+ }
4593
+
4594
+ interface AXConversationAttachedFile extends AXConversationComposerPickerUploadItem {
4948
4595
  icon: string;
4949
4596
  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
4597
  }
4958
- declare class AXConversationFilePickerComponent implements OnDestroy {
4598
+ declare class AXConversationFilePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
4959
4599
  private uploadsDismissed;
4960
4600
  private retainUploadedOnDismiss;
4961
4601
  private readonly uploader;
@@ -4970,16 +4610,20 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
4970
4610
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4971
4611
  readonly maxFiles: _angular_core.InputSignal<number>;
4972
4612
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4613
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4973
4614
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4615
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
4974
4616
  readonly catalogFileType: "conversation-file";
4975
4617
  readonly allowMultiple: _angular_core.Signal<boolean>;
4976
4618
  readonly files: _angular_core.WritableSignal<AXConversationAttachedFile[]>;
4977
4619
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4978
4620
  readonly isUploading: _angular_core.WritableSignal<boolean>;
4621
+ private readonly pickerShell;
4979
4622
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-file text-neutral-500" | "fa-light fa-cloud-arrow-up">;
4980
4623
  private catalogFileTypeDef?;
4981
4624
  caption: string;
4982
4625
  constructor();
4626
+ activate(): Promise<void>;
4983
4627
  private createUtilityContext;
4984
4628
  private getCatalogFileTypeDef;
4985
4629
  private pickerKind;
@@ -4992,6 +4636,9 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
4992
4636
  cancel(): void;
4993
4637
  ngOnDestroy(): void;
4994
4638
  private dismissPicker;
4639
+ getHeaderTitle(): string;
4640
+ getFileBadge(fileName: string): AXConversationPickerFileBadge;
4641
+ onAddMoreFiles(): void;
4995
4642
  getCancelUploadLabel(): string;
4996
4643
  formatFileSize(bytes: number): string;
4997
4644
  canSend(): boolean;
@@ -5001,7 +4648,7 @@ declare class AXConversationFilePickerComponent implements OnDestroy {
5001
4648
  getSelectedCountText(): string;
5002
4649
  getUploadingLabel(progress: number): string;
5003
4650
  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>;
4651
+ 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
4652
  }
5006
4653
 
5007
4654
  declare const AX_CONVERSATION_IMAGE_PRESENTATION: {
@@ -5021,7 +4668,7 @@ declare class AXConversationImageFileTypeProvider extends AXFileTypeInfoProvider
5021
4668
  interface AXConversationImageFile extends AXConversationComposerPickerUploadItem {
5022
4669
  preview: string;
5023
4670
  }
5024
- declare class AXConversationImagePickerComponent implements OnDestroy {
4671
+ declare class AXConversationImagePickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5025
4672
  private uploadsDismissed;
5026
4673
  /** Uploaded blobs are referenced by the sent message — do not delete on dismiss. */
5027
4674
  private retainUploadedOnDismiss;
@@ -5038,14 +4685,18 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5038
4685
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5039
4686
  readonly maxFiles: _angular_core.InputSignal<number>;
5040
4687
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4688
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5041
4689
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4690
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5042
4691
  readonly images: _angular_core.WritableSignal<AXConversationImageFile[]>;
4692
+ private readonly pickerShell;
5043
4693
  readonly isDragging: _angular_core.WritableSignal<boolean>;
5044
4694
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-image text-purple-500" | "fa-light fa-cloud-arrow-up">;
5045
4695
  caption: string;
5046
4696
  readonly allowMultiple: _angular_core.Signal<boolean>;
5047
4697
  private imageFileType?;
5048
4698
  constructor();
4699
+ activate(): Promise<void>;
5049
4700
  private createUtilityContext;
5050
4701
  private loadImageFileType;
5051
4702
  handleFiles(files: File[]): Promise<void>;
@@ -5056,6 +4707,8 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5056
4707
  canSend(): boolean;
5057
4708
  getUploadingLabel(progress: number): string;
5058
4709
  getCancelUploadLabel(): string;
4710
+ getHeaderTitle(): string;
4711
+ onAddMoreFiles(): void;
5059
4712
  cancel(): void;
5060
4713
  ngOnDestroy(): void;
5061
4714
  private dismissPicker;
@@ -5064,20 +4717,23 @@ declare class AXConversationImagePickerComponent implements OnDestroy {
5064
4717
  getSelectedCountText(): string;
5065
4718
  getSendText(): string;
5066
4719
  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>;
4720
+ 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
4721
  }
5069
4722
 
5070
4723
  declare class AXConversationLocationPickerComponent {
5071
- private readonly composerService;
5072
- private readonly conversationService;
4724
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
4725
+ private readonly composerServiceFromInjector;
4726
+ private get composerService();
5073
4727
  readonly translation: AXTranslationService;
5074
4728
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4729
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4730
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5075
4731
  readonly currentLocation: _angular_core.WritableSignal<AXConversationLocationPayload>;
5076
4732
  onMarkerAdded(event: AXMapMarker): void;
5077
4733
  sendLocation(): Promise<void>;
5078
4734
  cancel(): void;
5079
4735
  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>;
4736
+ 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
4737
  }
5082
4738
 
5083
4739
  declare class AXConversationPickerFooterComponent {
@@ -5091,9 +4747,12 @@ declare class AXConversationPickerFooterComponent {
5091
4747
 
5092
4748
  declare class AXConversationPickerHeaderComponent {
5093
4749
  readonly title: _angular_core.InputSignal<string>;
4750
+ readonly showMenu: _angular_core.InputSignal<boolean>;
4751
+ readonly addMoreLabel: _angular_core.InputSignal<string>;
5094
4752
  readonly onClose: _angular_core.OutputEmitterRef<void>;
4753
+ readonly onAddMore: _angular_core.OutputEmitterRef<void>;
5095
4754
  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>;
4755
+ 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
4756
  }
5098
4757
 
5099
4758
  declare function formatFileSize(bytes: number): string;
@@ -5108,12 +4767,20 @@ declare function resolvePersistableMediaUrl(url: string | undefined): string | u
5108
4767
  /** First non-empty URL for img/video/audio at runtime (includes resolved blob: URLs). */
5109
4768
  declare function pickDisplayMediaUrl(...candidates: (string | null | undefined)[]): string;
5110
4769
 
5111
- /** Optional caption field shared by composer media pickers. */
4770
+ /** Caption field with emoji picker for composer media pickers. */
5112
4771
  declare class AXConversationPickerCaptionComponent {
5113
4772
  readonly translation: AXTranslationService;
5114
4773
  readonly caption: _angular_core.ModelSignal<string>;
4774
+ readonly sendDisabled: _angular_core.InputSignal<boolean>;
4775
+ readonly onSend: _angular_core.OutputEmitterRef<void>;
4776
+ readonly emojiPopoverTarget: _angular_core.WritableSignal<HTMLElement>;
4777
+ private readonly emojiPopoverRef;
4778
+ onEmojiClick(event: MouseEvent): void;
4779
+ onEmojiPopoverClosed(): void;
4780
+ onEmojiItemSelected: (item: string | AXConversationStickerPayload) => void;
4781
+ onCaptionKeyDown(event: AXHtmlEvent<KeyboardEvent>): void;
5115
4782
  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>;
4783
+ 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
4784
  }
5118
4785
 
5119
4786
  /** Shared drag-and-drop handlers for composer pickers. */
@@ -5135,29 +4802,21 @@ declare class AXConversationPickerEmptyComponent {
5135
4802
  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
4803
  }
5137
4804
 
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
4805
  /**
5150
4806
  * Wraps composer pickers with {@link AXUploaderZoneDirective} for browse, drop, and validation.
5151
4807
  */
5152
4808
  declare class AXConversationPickerShellComponent {
5153
4809
  private readonly toast;
5154
4810
  private readonly translation;
4811
+ private readonly zone;
5155
4812
  readonly fileType: _angular_core.InputSignal<string>;
5156
4813
  readonly multiple: _angular_core.InputSignal<boolean>;
5157
4814
  readonly filesSelected: _angular_core.OutputEmitterRef<File[]>;
5158
4815
  readonly dragEnter: _angular_core.OutputEmitterRef<DragEvent>;
5159
4816
  readonly dragLeave: _angular_core.OutputEmitterRef<DragEvent>;
5160
4817
  readonly dragOver: _angular_core.OutputEmitterRef<DragEvent>;
4818
+ /** Open the OS file picker for this shell's catalog. */
4819
+ browse(): Promise<void>;
5161
4820
  protected onZoneFileChange(event: AXUploaderFileChangeEvent): void;
5162
4821
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationPickerShellComponent, never>;
5163
4822
  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 +4886,7 @@ interface AXConversationVideoFile extends AXConversationComposerPickerUploadItem
5227
4886
  preview?: string;
5228
4887
  duration?: number;
5229
4888
  }
5230
- declare class AXConversationVideoPickerComponent implements OnDestroy {
4889
+ declare class AXConversationVideoPickerComponent implements OnDestroy, AXConversationComposerActionComponent {
5231
4890
  private uploadsDismissed;
5232
4891
  private retainUploadedOnDismiss;
5233
4892
  readonly service: _angular_core.InputSignal<AXConversationComposerService>;
@@ -5242,16 +4901,20 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5242
4901
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5243
4902
  readonly maxFiles: _angular_core.InputSignal<number>;
5244
4903
  readonly initialFiles: _angular_core.InputSignal<File[]>;
4904
+ readonly autoRun: _angular_core.InputSignal<boolean>;
5245
4905
  readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4906
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5246
4907
  readonly catalogFileType: "conversation-video";
5247
4908
  readonly videos: _angular_core.WritableSignal<AXConversationVideoFile[]>;
5248
4909
  readonly isDragging: _angular_core.WritableSignal<boolean>;
4910
+ private readonly pickerShell;
5249
4911
  caption: string;
5250
4912
  readonly allowMultiple: _angular_core.Signal<boolean>;
5251
4913
  readonly typeIconClass: "fa-light fa-video ax-text-blue-500";
5252
4914
  readonly emptyIconClass: _angular_core.Signal<"fa-light fa-video ax-text-blue-500" | "fa-light fa-cloud-arrow-up">;
5253
4915
  private catalogFileTypeDef?;
5254
4916
  constructor();
4917
+ activate(): Promise<void>;
5255
4918
  private createUtilityContext;
5256
4919
  private getCatalogFileTypeDef;
5257
4920
  private runUtility;
@@ -5263,6 +4926,8 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5263
4926
  canSend(): boolean;
5264
4927
  getUploadingLabel(progress: number): string;
5265
4928
  getCancelUploadLabel(): string;
4929
+ getHeaderTitle(): string;
4930
+ onAddMoreFiles(): void;
5266
4931
  cancel(): void;
5267
4932
  ngOnDestroy(): void;
5268
4933
  private dismissPicker;
@@ -5273,7 +4938,7 @@ declare class AXConversationVideoPickerComponent implements OnDestroy {
5273
4938
  getSelectedCountText(): string;
5274
4939
  getSendText(): string;
5275
4940
  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>;
4941
+ 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
4942
  }
5278
4943
 
5279
4944
  declare const AX_CONVERSATION_VOICE_PRESENTATION: {
@@ -5293,14 +4958,21 @@ declare class AXConversationVoiceFileTypeProvider extends AXFileTypeInfoProvider
5293
4958
  declare function mergeVoiceUploadResult(payload: AXConversationMessagePayload, result: AXUploadResult): AXConversationMessagePayload;
5294
4959
  declare function applyVoiceLocalPreview(payload: AXConversationMessagePayload, localUrl: string): AXConversationMessagePayload;
5295
4960
 
5296
- declare class AXConversationVoiceRecorderComponent {
4961
+ declare class AXConversationVoiceRecorderComponent implements AXConversationComposerActionComponent {
5297
4962
  private readonly platformId;
5298
4963
  private readonly destroyRef;
5299
- private readonly composerService;
4964
+ readonly service: _angular_core.InputSignal<AXConversationComposerService>;
4965
+ private readonly composerServiceFromInjector;
4966
+ private get composerService();
5300
4967
  private readonly uploader;
4968
+ private readonly fileTypeRegistry;
5301
4969
  private readonly toast;
5302
4970
  readonly translation: AXTranslationService;
5303
4971
  readonly conversation: _angular_core.InputSignal<AXConversation>;
4972
+ readonly initialFiles: _angular_core.InputSignal<File[]>;
4973
+ readonly autoRun: _angular_core.InputSignal<boolean>;
4974
+ readonly __popup__: _angular_core.InputSignal<AXPopupRef<any>>;
4975
+ readonly __actionSheet__: _angular_core.InputSignal<AXActionSheetRef<unknown>>;
5304
4976
  readonly recordingComplete: _angular_core.OutputEmitterRef<Blob>;
5305
4977
  readonly recordingCancelled: _angular_core.OutputEmitterRef<void>;
5306
4978
  readonly isRecording: _angular_core.WritableSignal<boolean>;
@@ -5316,7 +4988,9 @@ declare class AXConversationVoiceRecorderComponent {
5316
4988
  private uploadAbortController?;
5317
4989
  readonly formattedTime: _angular_core.Signal<string>;
5318
4990
  constructor();
4991
+ activate(): Promise<void>;
5319
4992
  startRecording(): Promise<void>;
4993
+ private dismissHost;
5320
4994
  /** Stop recording and send */
5321
4995
  stopRecording(): void;
5322
4996
  cancelRecording(): void;
@@ -5330,7 +5004,7 @@ declare class AXConversationVoiceRecorderComponent {
5330
5004
  private sendVoiceMessage;
5331
5005
  private stopAndCleanup;
5332
5006
  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>;
5007
+ 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
5008
  }
5335
5009
 
5336
5010
  declare const AX_CONVERSATION_COMPOSER_EMOJI_ACTION: AXConversationComposerAction;
@@ -5349,13 +5023,17 @@ declare const AX_CONVERSATION_COMPOSER_LOCATION_ACTION: AXConversationComposerAc
5349
5023
 
5350
5024
  /** Ensures built-in conversation catalogs exist on the root file-type registry. */
5351
5025
  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[];
5026
+ /** Registers validation rules and lazy conversation file-type catalogs for composer actions. */
5027
+ declare function provideConversationComposerFileTypes(): Provider[];
5354
5028
 
5355
- /** Lazy-loads conversation file catalogs only for enabled media pickers. */
5029
+ /** Ensure a built-in conversation catalog is registered before pre-overlay file selection. */
5030
+ declare function ensureConversationFileCatalogRegistered(registry: AXFileTypeRegistryService, catalogName: string): Promise<void>;
5031
+ /**
5032
+ * Lazy-loads conversation file catalogs for the root file-type registry.
5033
+ * Must not inject {@link AXConversationComposerActionRegistry} — that registry
5034
+ * depends on {@link AXFileTypeRegistryService}, which would create a circular DI cycle.
5035
+ */
5356
5036
  declare class AXConversationComposerFileTypesProvider extends AXFileTypeInfoProvider {
5357
- private readonly config;
5358
- private cache;
5359
5037
  items(): Promise<AXFileType[]>;
5360
5038
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationComposerFileTypesProvider, never>;
5361
5039
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<AXConversationComposerFileTypesProvider>;
@@ -5370,149 +5048,12 @@ declare function createLocalPreviewUrl(fileService: AXFileService, platformId: o
5370
5048
 
5371
5049
  declare function resolveComposerMaxFiles(action: Pick<AXConversationComposerAction, 'maxFiles'> | undefined, config: Pick<Required<AXConversationConfig>, 'maxFilesPerMessage'>): number;
5372
5050
 
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
5051
  declare class AXConversationInfoBarSearchComponent {
5512
5052
  private readonly platformId;
5513
5053
  private readonly destroyRef;
5514
5054
  private readonly infoBarService;
5515
5055
  private readonly conversationService;
5056
+ private readonly config;
5516
5057
  /** Conversation input */
5517
5058
  readonly conversation: _angular_core.InputSignal<AXConversation>;
5518
5059
  /** Service input */
@@ -5523,13 +5064,14 @@ declare class AXConversationInfoBarSearchComponent {
5523
5064
  readonly resultsCount: _angular_core.Signal<number>;
5524
5065
  /** Current index from service */
5525
5066
  readonly currentIndex: _angular_core.Signal<number>;
5526
- /** Messages from conversation */
5527
- readonly messages: _angular_core.Signal<_acorex_components_conversation.AXConversationMessage[]>;
5067
+ private readonly searchResults;
5068
+ private searchDebounceTimer?;
5528
5069
  private scrollTimer?;
5070
+ private searchRequestId;
5529
5071
  constructor();
5530
5072
  /** Handle search input change */
5531
5073
  onSearchChange(value: string): void;
5532
- /** Perform search in messages */
5074
+ /** Perform server-side search in messages */
5533
5075
  private performSearch;
5534
5076
  /** Navigate to next result */
5535
5077
  onNext(): void;
@@ -5548,7 +5090,7 @@ declare class AXConversationInfoBarSearchComponent {
5548
5090
  */
5549
5091
 
5550
5092
  /**
5551
- * Search in conversation action (inline)
5093
+ * Search in conversation action (inline on desktop, menu on mobile)
5552
5094
  */
5553
5095
  declare const AX_CONVERSATION_INFO_BAR_SEARCH_ACTION: AXConversationInfoBarAction;
5554
5096
  /**
@@ -5734,11 +5276,6 @@ declare function syncPlaybackInfoBarBanner(infoBar: AXConversationInfoBarService
5734
5276
  forceOpen?: boolean;
5735
5277
  }): void;
5736
5278
 
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
5279
  declare class AXConversationVideoAttachmentComponent {
5743
5280
  readonly item: _angular_core.InputSignal<AXConversationVideoMediaItem>;
5744
5281
  readonly playingChange: _angular_core.OutputEmitterRef<boolean>;
@@ -6028,14 +5565,6 @@ declare const AX_CONVERSATION_MESSAGE_DELETE_ACTION: AXConversationMessageAction
6028
5565
  */
6029
5566
  declare const AX_CONVERSATION_MESSAGE_FORWARD_ACTION: AXConversationMessageAction;
6030
5567
 
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
5568
  declare const AX_CONVERSATION_TEXT_RENDERER: AXConversationMessageRenderer;
6040
5569
 
6041
5570
  declare const AX_CONVERSATION_IMAGE_RENDERER: AXConversationMessageRenderer;
@@ -6101,6 +5630,29 @@ declare const AX_CONVERSATION_TAB_BOT: AXConversationTab;
6101
5630
  declare const AX_CONVERSATION_TAB_UNREAD: AXConversationTab;
6102
5631
  declare const AX_CONVERSATION_TAB_ARCHIVED: AXConversationTab;
6103
5632
 
5633
+ declare class AXConversationDefaultConversationAvatarComponent {
5634
+ private readonly conversationService;
5635
+ private readonly userAvatarComponent;
5636
+ readonly conversationId: _angular_core.InputSignal<string>;
5637
+ readonly size: _angular_core.InputSignal<number>;
5638
+ private readonly currentUserId;
5639
+ private readonly conversation;
5640
+ readonly peerUserId: _angular_core.Signal<string>;
5641
+ readonly useUserAvatar: _angular_core.Signal<_angular_core.Type<_acorex_components_conversation.AXConversationUserAvatarComponent>>;
5642
+ readonly userAvatarInputs: _angular_core.Signal<{
5643
+ userId: string;
5644
+ size: number;
5645
+ displayName: string;
5646
+ displayAvatar: string;
5647
+ displayIcon: string;
5648
+ }>;
5649
+ readonly filteredUserAvatarInputs: _angular_core.Signal<Record<string, unknown>>;
5650
+ readonly fallbackDisplay: _angular_core.Signal<_acorex_components_conversation.AXConversationAvatarDisplay>;
5651
+ readonly fallbackInitials: _angular_core.Signal<string>;
5652
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXConversationDefaultConversationAvatarComponent, never>;
5653
+ 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>;
5654
+ }
5655
+
6104
5656
  /**
6105
5657
  * Configuration options for conversation module
6106
5658
  */
@@ -6132,7 +5684,7 @@ declare class AXConversationModule {
6132
5684
  */
6133
5685
  static forChild(options?: Omit<AXConversationOptions, 'userApi' | 'conversationApi' | 'messageApi' | 'realtimeApi'>): ModuleWithProviders<AXConversationModule>;
6134
5686
  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]>;
5687
+ 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
5688
  static ɵinj: _angular_core.ɵɵInjectorDeclaration<AXConversationModule>;
6137
5689
  }
6138
5690
  /**
@@ -6169,27 +5721,71 @@ interface AXConversationAvatarDisplay {
6169
5721
  avatar?: string;
6170
5722
  icon?: string;
6171
5723
  }
5724
+ /** Conversation types that resolve a single peer participant for viewer-scoped avatar/title. */
5725
+ declare const AX_CONVERSATION_PEER_AVATAR_TYPES: ReadonlySet<AXConversationType>;
5726
+ /**
5727
+ * Other participant in a peer-scoped conversation (excludes the current viewer).
5728
+ * Applies to private 1:1 and bot assist chats with exactly one non-viewer participant.
5729
+ */
5730
+ declare function resolveConversationPeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6172
5731
  /** Other participant in a private chat (excludes the current user). */
6173
5732
  declare function resolvePrivatePeerUserId(conversation: AXConversation, currentUserId?: string): string | undefined;
6174
- /** Whether `auto` kind should render a user avatar for this conversation. */
5733
+ /** Peer participant for private and bot conversations. */
5734
+ declare function resolveConversationPeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
5735
+ /** Whether `auto` kind should render a registered user avatar for this conversation. */
6175
5736
  declare function shouldUseUserAvatarForConversation(conversation: AXConversation, currentUserId?: string): boolean;
6176
5737
  declare function resolveUserAvatarDisplay(userId: string, conversation: AXConversation | undefined, message?: AXConversationMessage): AXConversationAvatarDisplay;
6177
5738
  declare function resolveConversationAvatarDisplay(conversation: AXConversation, currentUserId?: string): AXConversationAvatarDisplay;
6178
5739
 
5740
+ interface AXConversationMessageListBackgroundPreset {
5741
+ id: string;
5742
+ value: AXConversationMessageListThemeBackground;
5743
+ }
5744
+ /** Library default when no per-conversation or global background is set (pattern-5 tile + gradient wash). */
5745
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_THEME_BACKGROUND: AXConversationMessageListThemeBackground;
5746
+ /** Predefined chat-area backgrounds for the info panel (light + dark variants). */
5747
+ declare const AX_CONVERSATION_MESSAGE_LIST_BACKGROUND_PRESETS: AXConversationMessageListBackgroundPreset[];
5748
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND_PRESET_ID = "solid-default";
5749
+
5750
+ /** Subtle Telegram-style chat-area wash when `messageListBackground` is not set (theme-aware). */
5751
+ declare const AX_CONVERSATION_DEFAULT_MESSAGE_LIST_BACKGROUND: string;
5752
+ declare function isMessageListThemeBackground(value: unknown): value is AXConversationMessageListThemeBackground;
5753
+ /** Pick the raw CSS string for the active theme; `undefined` when unset. */
5754
+ declare function resolveMessageListBackgroundRaw(value: AXConversationMessageListBackground | undefined, isDark: boolean): string | undefined;
5755
+ /** Turn bare `https://...` or `/path` into valid CSS `background` for images. */
5756
+ declare function normalizeMessageListBackgroundValue(raw: string): string;
5757
+ /** Whether the built-in pattern-5 wallpaper (gradient + tiled SVG) should be used. */
5758
+ declare function usesDefaultMessageListWallpaper(value: AXConversationMessageListBackground | undefined): boolean;
5759
+ /** Resolve config/metadata background for the active theme, with library default fallback. */
5760
+ declare function resolveMessageListBackgroundStyle(value: AXConversationMessageListBackground | undefined, isDark: boolean): string;
5761
+ /** Whether two stored backgrounds represent the same preset (supports legacy string values). */
5762
+ declare function isSameMessageListBackground(a: AXConversationMessageListBackground | undefined, b: AXConversationMessageListThemeBackground, isDark: boolean): boolean;
5763
+
5764
+ /** Default Font Awesome icon for group conversations without a custom avatar image. */
5765
+ declare const AX_CONVERSATION_DEFAULT_GROUP_ICON = "fa-light fa-users";
5766
+ /** Default Font Awesome icon for private/bot conversations without a custom avatar image. */
5767
+ declare const AX_CONVERSATION_DEFAULT_USER_ICON = "fa-light fa-user";
6179
5768
  /** True when the stored title is a placeholder, not a user-defined name. */
6180
5769
  declare function isGenericPrivateConversationTitle(title: string | undefined): boolean;
5770
+ /**
5771
+ * Find an existing private 1:1 conversation between the current user and a peer.
5772
+ * Matches conversations with exactly those two participants.
5773
+ */
5774
+ declare function findExistingPrivateConversation(conversations: AXConversation[], currentUserId: string, peerUserId: string): AXConversation | undefined;
6181
5775
  /** Other participant in a private 1v1 chat (excludes the current viewer). */
6182
5776
  declare function resolvePrivatePeerParticipant(conversation: AXConversation, currentUserId?: string): AXConversationParticipant | undefined;
6183
5777
  /**
6184
5778
  * Resolves the display title for the current viewer.
6185
- * Private 1v1 chats show the other participant's name when no custom title is set.
5779
+ * Private and bot peer-scoped chats show the other participant's name when no custom title is set.
6186
5780
  */
6187
5781
  declare function resolveConversationTitleForViewer(conversation: AXConversation, currentUserId?: string): string;
6188
5782
  /**
6189
- * Returns a viewer-scoped copy of a conversation with dynamic private title/avatar/icon.
5783
+ * Returns a viewer-scoped copy of a conversation with dynamic peer title/avatar/icon.
6190
5784
  * Does not mutate the source object.
6191
5785
  */
6192
5786
  declare function resolveConversationForViewer(conversation: AXConversation, currentUserId?: string): AXConversation;
5787
+ /** Whether message reactions are enabled for a conversation. Defaults to `true` when omitted. */
5788
+ declare function isConversationReactionsEnabled(conversation?: AXConversation | null): boolean;
6193
5789
 
6194
5790
  /** Resolves typed `profile`, falling back to legacy `metadata.profile`. */
6195
5791
  declare function resolveParticipantProfile(participant?: AXConversationParticipant): AXConversationUserProfile;
@@ -6217,85 +5813,36 @@ declare class AXConversationDateUtilsService {
6217
5813
  static formatTime(date: Date): string;
6218
5814
  }
6219
5815
 
5816
+ /**
5817
+ * Message Utilities Service
5818
+ * Helper functions for message formatting and display
5819
+ */
5820
+
6220
5821
  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
5822
  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
5823
  static getMessageText(message: AXConversationMessage): string;
6259
- /**
6260
- * Format message preview text
6261
- */
6262
5824
  static getPreviewText(message: AXConversationMessage, maxLength?: number): {
6263
5825
  value: string;
6264
5826
  type: string;
6265
5827
  icon: string;
6266
5828
  };
6267
- /**
6268
- * Check if message is from current user
6269
- */
6270
5829
  static isOwnMessage(message: AXConversationMessage, currentUserId: string): boolean;
6271
- /**
6272
- * Get message status icon class (Font Awesome)
6273
- */
6274
- 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
- */
5830
+ static getSenderName(message: AXConversationMessage, conversation: AXConversation): string;
5831
+ static getSenderAvatar(message: AXConversationMessage, conversation: AXConversation): string | undefined;
5832
+ static getSenderAvatarIcon(message: AXConversationMessage, conversation: AXConversation): string | undefined;
5833
+ static getConversationAvatar(conversation: AXConversation): string | undefined;
5834
+ static getConversationAvatarIcon(conversation: AXConversation): string | undefined;
5835
+ static getConversationStatus(conversation: AXConversation, presence?: AXConversationUserPresence): AXConversationPresenceStatus | undefined;
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 };