@ermis-network/ermis-chat-react 1.0.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/index.cjs +15288 -4203
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +701 -195
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.mts +862 -94
  6. package/dist/index.d.ts +862 -94
  7. package/dist/index.mjs +15238 -4179
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +9 -4
  10. package/src/channelTypeUtils.ts +1 -1
  11. package/src/components/Avatar.tsx +2 -1
  12. package/src/components/Channel.tsx +6 -2
  13. package/src/components/ChannelActions.tsx +61 -2
  14. package/src/components/ChannelHeader.tsx +19 -5
  15. package/src/components/ChannelInfo/AddMemberModal.tsx +5 -1
  16. package/src/components/ChannelInfo/ChannelInfo.tsx +330 -187
  17. package/src/components/ChannelInfo/ChannelInfoTabs.tsx +59 -297
  18. package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +30 -174
  19. package/src/components/ChannelInfo/EditChannelModal.tsx +4 -1
  20. package/src/components/ChannelInfo/MediaGridItem.tsx +12 -2
  21. package/src/components/ChannelInfo/MemberListItem.tsx +2 -3
  22. package/src/components/ChannelInfo/MessageSearchPanel.tsx +27 -126
  23. package/src/components/ChannelInfo/States.tsx +1 -1
  24. package/src/components/ChannelInfo/index.ts +3 -0
  25. package/src/components/ChannelInfo/useChannelInfoTabs.tsx +386 -0
  26. package/src/components/ChannelInfo/useChannelSettings.ts +212 -0
  27. package/src/components/ChannelInfo/useMessageSearch.tsx +141 -0
  28. package/src/components/ChannelList.tsx +177 -290
  29. package/src/components/CreateChannelModal.tsx +166 -88
  30. package/src/components/Dropdown.tsx +1 -16
  31. package/src/components/EditPreview.tsx +1 -0
  32. package/src/components/ErmisCallProvider.tsx +72 -17
  33. package/src/components/ErmisCallUI.tsx +43 -20
  34. package/src/components/FlatTopicGroupItem.tsx +232 -0
  35. package/src/components/ForwardMessageModal.tsx +31 -77
  36. package/src/components/MediaLightbox.tsx +62 -40
  37. package/src/components/MentionSuggestions.tsx +47 -35
  38. package/src/components/MessageActionsBox.tsx +4 -1
  39. package/src/components/MessageInput.tsx +126 -7
  40. package/src/components/MessageInputDefaults.tsx +127 -1
  41. package/src/components/MessageItem.tsx +93 -26
  42. package/src/components/MessageQuickReactions.tsx +153 -26
  43. package/src/components/MessageReactions.tsx +2 -1
  44. package/src/components/MessageRenderers.tsx +111 -39
  45. package/src/components/Panel.tsx +1 -14
  46. package/src/components/PinnedMessages.tsx +17 -5
  47. package/src/components/PreviewOverlay.tsx +24 -0
  48. package/src/components/ReadReceipts.tsx +2 -1
  49. package/src/components/TopicList.tsx +221 -0
  50. package/src/components/TopicModal.tsx +4 -1
  51. package/src/components/TypingIndicator.tsx +14 -5
  52. package/src/components/UserPicker.tsx +87 -10
  53. package/src/components/VirtualMessageList.tsx +106 -20
  54. package/src/context/ChatComponentsContext.tsx +14 -0
  55. package/src/context/ChatProvider.tsx +18 -14
  56. package/src/context/ErmisCallContext.tsx +4 -0
  57. package/src/hooks/useChannelCapabilities.ts +7 -4
  58. package/src/hooks/useChannelData.ts +10 -3
  59. package/src/hooks/useChannelListUpdates.ts +72 -20
  60. package/src/hooks/useChannelMessages.ts +72 -10
  61. package/src/hooks/useChannelRowUpdates.ts +24 -5
  62. package/src/hooks/useChatUser.ts +31 -0
  63. package/src/hooks/useContactChannels.ts +45 -0
  64. package/src/hooks/useContactCount.ts +50 -0
  65. package/src/hooks/useDownloadHandler.ts +36 -0
  66. package/src/hooks/useDragAndDrop.ts +79 -0
  67. package/src/hooks/useForwardMessage.ts +112 -0
  68. package/src/hooks/useInviteChannels.ts +88 -0
  69. package/src/hooks/useInviteCount.ts +104 -0
  70. package/src/hooks/useMentions.ts +0 -1
  71. package/src/hooks/useMessageActions.ts +13 -10
  72. package/src/hooks/usePendingState.ts +21 -4
  73. package/src/hooks/usePreviewState.ts +69 -0
  74. package/src/hooks/useStickerPicker.ts +62 -0
  75. package/src/hooks/useTopicGroupUpdates.ts +197 -0
  76. package/src/index.ts +56 -6
  77. package/src/messageTypeUtils.ts +13 -1
  78. package/src/styles/_base.css +0 -1
  79. package/src/styles/_call-ui.css +59 -2
  80. package/src/styles/_channel-info.css +41 -4
  81. package/src/styles/_channel-list.css +97 -57
  82. package/src/styles/_create-channel-modal.css +10 -0
  83. package/src/styles/_forward-modal.css +16 -1
  84. package/src/styles/_media-lightbox.css +32 -0
  85. package/src/styles/_mentions.css +1 -1
  86. package/src/styles/_message-actions.css +3 -4
  87. package/src/styles/_message-bubble.css +286 -107
  88. package/src/styles/_message-input.css +131 -0
  89. package/src/styles/_message-list.css +33 -17
  90. package/src/styles/_message-quick-reactions.css +40 -9
  91. package/src/styles/_message-reactions.css +4 -0
  92. package/src/styles/_modal.css +2 -1
  93. package/src/styles/_preview-overlay.css +38 -0
  94. package/src/styles/_tokens.css +17 -15
  95. package/src/styles/_typing-indicator.css +7 -1
  96. package/src/styles/index.css +1 -0
  97. package/src/types.ts +362 -14
  98. package/src/utils/avatarColors.ts +48 -0
  99. package/src/utils.ts +193 -10
package/src/types.ts CHANGED
@@ -7,6 +7,8 @@ import type {
7
7
  ChannelSort,
8
8
  ChannelQueryOptions,
9
9
  UserCallInfo,
10
+ SystemMessageTranslations,
11
+ SignalMessageTranslations,
10
12
  } from '@ermis-network/ermis-chat-sdk';
11
13
  import type { ErmisChat } from '@ermis-network/ermis-chat-sdk';
12
14
 
@@ -56,9 +58,13 @@ export type ChatContextValue = {
56
58
  enableCall?: boolean;
57
59
  };
58
60
 
61
+ import type { ChatComponentsContextValue } from './context/ChatComponentsContext';
62
+
59
63
  export type ChatProviderProps = {
60
64
  client: ErmisChat;
61
65
  children: React.ReactNode;
66
+ /** Global UI primitive components registry */
67
+ components?: ChatComponentsContextValue;
62
68
  /** Initial theme, defaults to 'dark' */
63
69
  initialTheme?: Theme;
64
70
  /** Enable direct call feature (Audio/Video). If enabled, configures internal CallProvider */
@@ -193,6 +199,9 @@ export type ErmisCallRingingProps = {
193
199
  endCallLabel: string;
194
200
  audioCallBadgeLabel: string;
195
201
  videoCallBadgeLabel: string;
202
+ isAccepting?: boolean;
203
+ isRejecting?: boolean;
204
+ isEnding?: boolean;
196
205
  };
197
206
 
198
207
  /** Props for the Connected Audio state view */
@@ -240,6 +249,7 @@ export type ErmisCallControlsBarProps = {
240
249
  selectedVideoDeviceId: string;
241
250
  switchAudioDevice: (id: string) => Promise<void>;
242
251
  switchVideoDevice: (id: string) => Promise<void>;
252
+ isEnding?: boolean;
243
253
  };
244
254
 
245
255
  /* ----------------------------------------------------------
@@ -337,8 +347,10 @@ export type ChannelActionLabels = {
337
347
  closeTopic?: string;
338
348
  reopenTopic?: string;
339
349
  createTopic?: string;
350
+ deleteTopic?: string;
340
351
  deleteChannel?: string;
341
352
  leaveChannel?: string;
353
+ truncateChannel?: string;
342
354
  };
343
355
 
344
356
  export type ChannelActionIcons = {
@@ -350,8 +362,10 @@ export type ChannelActionIcons = {
350
362
  CloseTopicIcon?: React.ReactNode;
351
363
  ReopenTopicIcon?: React.ReactNode;
352
364
  CreateTopicIcon?: React.ReactNode;
365
+ DeleteTopicIcon?: React.ReactNode;
353
366
  DeleteChannelIcon?: React.ReactNode;
354
367
  LeaveChannelIcon?: React.ReactNode;
368
+ TruncateChannelIcon?: React.ReactNode;
355
369
  };
356
370
 
357
371
  export type ChannelActionsProps = {
@@ -365,7 +379,7 @@ export type ChannelItemProps = {
365
379
  isActive: boolean;
366
380
  hasUnread: boolean;
367
381
  unreadCount: number;
368
- lastMessageText: string;
382
+ lastMessageText: React.ReactNode;
369
383
  lastMessageUser: string;
370
384
  lastMessageTimestamp?: Date | string | null;
371
385
  onSelect: (channel: Channel) => void;
@@ -388,6 +402,10 @@ export type ChannelItemProps = {
388
402
  onEditTopic?: (channel: Channel) => void;
389
403
  /** Handler when Close/Reopen Topic action is triggered */
390
404
  onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;
405
+ /** Handler when Delete Topic action is triggered */
406
+ onDeleteTopic?: (channel: Channel) => void;
407
+ /** Handler when Truncate Channel action is triggered */
408
+ onTruncateChannel?: (channel: Channel) => void;
391
409
  /** Array of action IDs to hide from the actions dropdown */
392
410
  hiddenActions?: string[];
393
411
  /** Custom labels for default channel actions */
@@ -398,6 +416,68 @@ export type ChannelItemProps = {
398
416
  isOnline?: boolean;
399
417
  };
400
418
 
419
+ /* ----------------------------------------------------------
420
+ TopicPill types (for FlatTopicGroupItem)
421
+ ---------------------------------------------------------- */
422
+ export type TopicPillProps = {
423
+ /** The topic channel to display as a pill */
424
+ topic: Channel;
425
+ /** Size of the topic avatar in pixels (default: 16) */
426
+ avatarSize?: number;
427
+ };
428
+
429
+ /* ----------------------------------------------------------
430
+ TopicList types
431
+ ---------------------------------------------------------- */
432
+ export type TopicListProps = {
433
+ /** Parent channel that has topics enabled */
434
+ channel: Channel;
435
+ /** Custom channel item component for each topic row */
436
+ ChannelItemComponent?: React.ComponentType<ChannelItemProps>;
437
+ /** Custom avatar for the general (parent) topic */
438
+ GeneralAvatarComponent?: React.ComponentType<AvatarProps>;
439
+ /** Custom avatar for sub-topic items */
440
+ TopicAvatarComponent?: React.ComponentType<AvatarProps>;
441
+ /** Custom avatar component (fallback) */
442
+ AvatarComponent?: React.ComponentType<AvatarProps>;
443
+ /** Label for the general topic (default: 'general') */
444
+ generalTopicLabel?: string;
445
+ /** Pinned icon component */
446
+ PinnedIconComponent?: React.ComponentType;
447
+ /** Custom channel actions component */
448
+ ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;
449
+ /** Called when a topic is selected */
450
+ onSelectTopic?: (topic: Channel) => void;
451
+ /** Handler for Edit Topic action */
452
+ onEditTopic?: (channel: Channel) => void;
453
+ /** Handler for Close/Reopen Topic action */
454
+ onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;
455
+ /** Handler for Delete Topic action */
456
+ onDeleteTopic?: (channel: Channel) => void;
457
+ /** Actions to hide */
458
+ hiddenActions?: string[];
459
+ /** Custom action labels */
460
+ actionLabels?: ChannelActionLabels;
461
+ /** Custom action icons */
462
+ actionIcons?: ChannelActionIcons;
463
+ /** Icon for closed topics */
464
+ closedTopicIcon?: React.ReactNode;
465
+ /** Badge label for pending members */
466
+ pendingBadgeLabel?: string;
467
+ /** Badge label for blocked members */
468
+ blockedBadgeLabel?: string;
469
+ /** Auto-scroll the topic list to the top when the current user sends a message (default: true) */
470
+ scrollToTopOnOwnMessage?: boolean;
471
+ deletedMessageLabel?: React.ReactNode;
472
+ stickerMessageLabel?: React.ReactNode;
473
+ photoMessageLabel?: React.ReactNode;
474
+ videoMessageLabel?: React.ReactNode;
475
+ voiceRecordingMessageLabel?: React.ReactNode;
476
+ fileMessageLabel?: React.ReactNode;
477
+ systemMessageTranslations?: SystemMessageTranslations;
478
+ signalMessageTranslations?: SignalMessageTranslations;
479
+ };
480
+
401
481
  export type ChannelListProps = {
402
482
  filters?: ChannelFilters;
403
483
  sort?: ChannelSort;
@@ -405,6 +485,8 @@ export type ChannelListProps = {
405
485
  renderChannel?: (channel: Channel, isActive: boolean) => React.ReactNode;
406
486
  onChannelSelect?: (channel: Channel) => void;
407
487
  className?: string;
488
+ /** Whether to show pending invites visually in the main list (default: true) */
489
+ showPendingInvites?: boolean;
408
490
  /** Array of action IDs to hide from the actions dropdown */
409
491
  hiddenActions?: string[];
410
492
  LoadingIndicator?: React.ComponentType<{ text?: string }>;
@@ -420,18 +502,30 @@ export type ChannelListProps = {
420
502
  pendingBadgeLabel?: string;
421
503
  /** Label for the loading indicator */
422
504
  loadingLabel?: string;
423
- /** Label for the empty state indicator */
505
+ /** Component to display when there is an error loading channels */
506
+ ErrorIndicator?: React.ComponentType<{ text?: string; onRetry?: () => void }>;
507
+ /** Label to display in the error indicator */
508
+ errorLabel?: string;
509
+ /** Label to display in the empty state indicator */
424
510
  emptyStateLabel?: string;
425
511
  /** Label for the blocked channel badge hover */
426
512
  blockedBadgeLabel?: string;
427
- /** Custom component for rendering topic group */
428
- ChannelTopicGroupComponent?: React.ComponentType<any>;
429
- /** Custom avatar component for general topic */
430
- GeneralTopicAvatarComponent?: React.ComponentType<any>;
431
- /** Custom avatar component for other topics */
432
- TopicAvatarComponent?: React.ComponentType<any>;
433
- /** Name for the general topic (default: "general") */
434
- generalTopicLabel?: string;
513
+ /** Label for deleted messages in the preview strip (default: 'This message was deleted') */
514
+ deletedMessageLabel?: React.ReactNode;
515
+ /** Label for sticker messages in the preview strip (default: 'Sticker') */
516
+ stickerMessageLabel?: React.ReactNode;
517
+ /** Label for photo messages in the preview strip (default: '📷 Photo') */
518
+ photoMessageLabel?: React.ReactNode;
519
+ /** Label for video messages in the preview strip (default: '🎬 Video') */
520
+ videoMessageLabel?: React.ReactNode;
521
+ /** Label for voice message in the preview strip (default: '🎤 Voice message') */
522
+ voiceRecordingMessageLabel?: React.ReactNode;
523
+ /** Label for file messages in the preview strip (default: '📎 File') */
524
+ fileMessageLabel?: React.ReactNode;
525
+ /** Custom translation templates for system messages in the preview strip */
526
+ systemMessageTranslations?: SystemMessageTranslations;
527
+ /** Custom translation templates for signal (call) messages in the preview strip */
528
+ signalMessageTranslations?: SignalMessageTranslations;
435
529
  /** Handler when Add Topic button is clicked on a team channel */
436
530
  onAddTopic?: (channel: Channel) => void;
437
531
  /** Optional custom emoji picker for TopicModal */
@@ -444,12 +538,30 @@ export type ChannelListProps = {
444
538
  onEditTopic?: (channel: Channel) => void;
445
539
  /** Handler when Close/Reopen Topic action is triggered */
446
540
  onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;
541
+ /** Handler when Delete Topic action is triggered */
542
+ onDeleteTopic?: (channel: Channel) => void;
543
+ /** Handler when Truncate action is triggered */
544
+ onTruncateChannel?: (channel: Channel) => void;
447
545
  /** Custom labels for default channel actions */
448
546
  actionLabels?: ChannelActionLabels;
449
547
  /** Custom icons for default channel actions */
450
548
  actionIcons?: ChannelActionIcons;
451
549
  /** Show online/offline indicator dots on channel item avatars for friend channels (default: true) */
452
550
  showOnlineStatus?: boolean;
551
+ /** Handler when a topic-enabled channel is clicked — enables drill-down mode */
552
+ onTopicDrillDown?: (channel: Channel) => void;
553
+ /** Max number of topic pills shown in the preview strip (default: 3) */
554
+ maxVisibleTopics?: number;
555
+ /** Label for the overflow indicator when topics exceed maxVisibleTopics (default: '...') */
556
+ moreTopicsLabel?: string;
557
+ /** Label for the general topic pill (default: 'general') */
558
+ generalTopicLabel?: string;
559
+ /** Custom component for rendering each topic pill in the preview strip */
560
+ TopicPillComponent?: React.ComponentType<TopicPillProps>;
561
+ /** Custom component to replace the entire flat topic group item */
562
+ FlatTopicGroupItemComponent?: React.ComponentType<any>;
563
+ /** Auto-scroll the channel list to the top when the current user sends a message (default: true) */
564
+ scrollToTopOnOwnMessage?: boolean;
453
565
  };
454
566
 
455
567
  /* ----------------------------------------------------------
@@ -464,6 +576,9 @@ export type AttachmentProps = {
464
576
  export type MessageRendererProps = {
465
577
  message: FormatMessageResponse;
466
578
  isOwnMessage: boolean;
579
+ systemMessageTranslations?: SystemMessageTranslations;
580
+ signalMessageTranslations?: SignalMessageTranslations;
581
+ onMentionClick?: (userId: string) => void;
467
582
  };
468
583
 
469
584
  export type MessageBubbleProps = {
@@ -503,6 +618,12 @@ export type MediaLightboxProps = {
503
618
  export type MessageListProps = {
504
619
  /** Fully custom render for each message */
505
620
  renderMessage?: (message: FormatMessageResponse, isOwnMessage: boolean) => React.ReactNode;
621
+ /** Handler when a mention is clicked */
622
+ onMentionClick?: (userId: string) => void;
623
+ /** Handler when a sender's username is clicked in the message list */
624
+ onUserNameClick?: (userId: string) => void;
625
+ /** Handler when clicking to add a custom reaction */
626
+ onAddReactionClick?: (e: React.MouseEvent, messageId: string) => void;
506
627
  /** Additional CSS class name */
507
628
  className?: string;
508
629
  /** Custom empty state component */
@@ -517,6 +638,8 @@ export type MessageListProps = {
517
638
  loadMoreLimit?: number;
518
639
  /** Custom date separator component */
519
640
  DateSeparatorComponent?: React.ComponentType<DateSeparatorProps>;
641
+ /** Locale string for date separator labels (e.g. 'vi', 'en-US'). Falls back to browser default. */
642
+ dateLocale?: string;
520
643
  /** Custom message item component (replaces the entire row) */
521
644
  MessageItemComponent?: React.ComponentType<MessageItemProps>;
522
645
  /** Custom system message item component */
@@ -572,9 +695,30 @@ export type MessageListProps = {
572
695
  closedTopicReopenLabel?: string;
573
696
 
574
697
  /** Custom component for pending invitee notification in direct channels */
575
- PendingInviteeNotificationComponent?: React.ComponentType<{ inviteeName?: string, label?: string }>;
698
+ PendingInviteeNotificationComponent?: React.ComponentType<{ inviteeName?: string; label?: string }>;
576
699
  /** I18n Label for pending invitee notification */
577
700
  pendingInviteeLabel?: string | ((inviteeName?: string) => string);
701
+
702
+ /** I18n Label for pinned messages header */
703
+ pinnedMessagesLabel?: string | ((count: number) => string);
704
+ /** I18n Label for seeing all pinned messages */
705
+ seeAllLabel?: string;
706
+ /** I18n Label for collapsing pinned messages */
707
+ collapseLabel?: string;
708
+ /** I18n Label for unpinning a message */
709
+ unpinLabel?: string;
710
+ /** I18n Label for sticker message preview */
711
+ stickerLabel?: string;
712
+ /** I18n Label for typing indicator */
713
+ typingIndicatorLabel?: (users: Array<{ id: string; name?: string }>) => string;
714
+ /** I18n Label for deleted display messages (display_type === 'deleted') */
715
+ deletedMessageLabel?: string;
716
+ /** Custom translation templates for system messages */
717
+ systemMessageTranslations?: SystemMessageTranslations;
718
+ /** Custom translation templates for signal (call) messages */
719
+ signalMessageTranslations?: SignalMessageTranslations;
720
+ /** Whether to include hidden (deleted) messages in the initial channel query. Defaults to true. */
721
+ includeHiddenMessages?: boolean;
578
722
  };
579
723
 
580
724
  /* ----------------------------------------------------------
@@ -604,6 +748,8 @@ export type MessageReactionsProps = {
604
748
  onClickReaction?: (type: string) => void;
605
749
  /** Whether interactions are disabled */
606
750
  disabled?: boolean;
751
+ /** Whether the message is from the current user */
752
+ isOwnMessage?: boolean;
607
753
  };
608
754
 
609
755
  /* ----------------------------------------------------------
@@ -667,16 +813,30 @@ export type MessageItemProps = {
667
813
  forwardedLabel?: string;
668
814
  /** I18n Label for edited state */
669
815
  editedLabel?: string;
816
+ /** I18n Label for deleted display messages (display_type === 'deleted') */
817
+ deletedMessageLabel?: React.ReactNode;
818
+ /** Custom translation templates for system messages */
819
+ systemMessageTranslations?: SystemMessageTranslations;
820
+ /** Custom translation templates for signal (call) messages */
821
+ signalMessageTranslations?: SignalMessageTranslations;
822
+ /** Handler when a mention is clicked */
823
+ onMentionClick?: (userId: string) => void;
824
+ /** Handler when a sender's username is clicked in the message list */
825
+ onUserNameClick?: (userId: string) => void;
826
+ /** Handler when clicking to add a custom reaction */
827
+ onAddReactionClick?: (e: React.MouseEvent, messageId: string) => void;
670
828
  };
671
829
 
672
830
  export type SystemMessageItemProps = {
673
831
  message: FormatMessageResponse;
674
832
  isOwnMessage: boolean;
675
833
  SystemRenderer: React.ComponentType<MessageRendererProps>;
834
+ systemMessageTranslations?: SystemMessageTranslations;
676
835
  };
677
836
 
678
837
  export type SendButtonProps = { disabled: boolean; onClick: () => void };
679
838
  export type AttachButtonProps = { disabled: boolean; onClick: () => void };
839
+ export type VoiceRecordButtonProps = { disabled: boolean; onRecordComplete: (file: File) => void };
680
840
 
681
841
  /** Props passed to a consumer-provided emoji picker component */
682
842
  export type EmojiPickerProps = {
@@ -686,6 +846,18 @@ export type EmojiPickerProps = {
686
846
  onClose: () => void;
687
847
  };
688
848
 
849
+ /** Props for the preview overlay when a user has not joined a public channel */
850
+ export type PreviewOverlayProps = {
851
+ /** Title shown in the preview overlay */
852
+ title?: string;
853
+ /** Label for the join button */
854
+ buttonLabel?: string;
855
+ /** Action when the join button is clicked */
856
+ onJoin?: () => void;
857
+ /** Custom class name */
858
+ className?: string;
859
+ };
860
+
689
861
  /** Props passed to the emoji button component */
690
862
  export type EmojiButtonProps = {
691
863
  /** Whether the picker is currently open */
@@ -705,6 +877,8 @@ export type MessageInputProps = {
705
877
  SendButton?: React.ComponentType<SendButtonProps>;
706
878
  /** Custom attach button component */
707
879
  AttachButton?: React.ComponentType<AttachButtonProps>;
880
+ /** Custom voice record button component */
881
+ VoiceRecordButtonComponent?: React.ComponentType<VoiceRecordButtonProps>;
708
882
  /** Custom file preview component */
709
883
  FilesPreviewComponent?: React.ComponentType<FilesPreviewProps>;
710
884
  /** Custom mention suggestions component */
@@ -743,6 +917,32 @@ export type MessageInputProps = {
743
917
  slowModeLabel?: (cooldown: number) => React.ReactNode;
744
918
  /** I18n Label for closed topic */
745
919
  closedTopicLabel?: string;
920
+ /** I18n Label for replying state */
921
+ replyingToLabel?: string;
922
+ /** I18n Label for editing state */
923
+ editingMessageLabel?: string;
924
+ /** I18n Label for Drag and Drop overlay */
925
+ dragAndDropLabel?: string;
926
+ /** Custom component for Drag and Drop overlay */
927
+ DragAndDropOverlayComponent?: React.ComponentType<{ dragAndDropLabel: string }>;
928
+
929
+ /** Custom component for the Preview Overlay (shown instead of input in unjoined public channels) */
930
+ PreviewOverlayComponent?: React.ComponentType<PreviewOverlayProps>;
931
+ /** I18n Title for Preview Overlay */
932
+ previewOverlayTitle?: string;
933
+ /** I18n Label for Join Button in Preview Overlay */
934
+ joinChannelLabel?: string;
935
+
936
+ /** Disable stickers entirely */
937
+ disableStickers?: boolean;
938
+ /** URL for the sticker picker iframe (default: https://sticker.ermis.network) */
939
+ stickerIframeUrl?: string;
940
+ /** Custom sticker picker component */
941
+ StickerPickerComponent?: React.ComponentType<{ stickerIframeUrl: string; onClose: () => void }>;
942
+ /** Custom sticker button component */
943
+ StickerButtonComponent?: React.ComponentType<{ active: boolean; onClick: () => void }>;
944
+ /** I18n Label for maximum characters exceeded error */
945
+ maxCharsLabel?: string;
746
946
  };
747
947
 
748
948
  /* ----------------------------------------------------------
@@ -805,6 +1005,8 @@ export type PinnedMessageItemProps = {
805
1005
  onClickMessage?: (messageId: string) => void;
806
1006
  onUnpin?: (messageId: string) => void;
807
1007
  AvatarComponent: React.ComponentType<AvatarProps>;
1008
+ unpinLabel?: string;
1009
+ stickerLabel?: string;
808
1010
  };
809
1011
 
810
1012
  export type PinnedMessagesProps = {
@@ -818,6 +1020,12 @@ export type PinnedMessagesProps = {
818
1020
  onClickMessage?: (messageId: string) => void;
819
1021
  /** Max messages to show in collapsed state (default: 1) */
820
1022
  maxCollapsed?: number;
1023
+ /** I18n Labels */
1024
+ pinnedMessagesLabel?: string | ((count: number) => string);
1025
+ seeAllLabel?: string;
1026
+ collapseLabel?: string;
1027
+ unpinLabel?: string;
1028
+ stickerLabel?: string;
821
1029
  };
822
1030
 
823
1031
  /* ----------------------------------------------------------
@@ -921,7 +1129,7 @@ export type FilesPreviewProps = {
921
1129
  };
922
1130
 
923
1131
  /* --------------------------------------------------------------------------
924
- * Modal Components
1132
+ * Primitive Components Props
925
1133
  * -------------------------------------------------------------------------- */
926
1134
 
927
1135
  export interface ModalProps {
@@ -935,6 +1143,38 @@ export interface ModalProps {
935
1143
  closeOnOutsideClick?: boolean;
936
1144
  }
937
1145
 
1146
+ export interface DropdownProps {
1147
+ /** Whether the dropdown is open */
1148
+ isOpen: boolean;
1149
+ /** Rect from getBoundingClientRect() of the anchor element */
1150
+ anchorRect: DOMRect | null;
1151
+ /** Callback when dropdown requests to close (e.g., click outside, scroll, Escape) */
1152
+ onClose: () => void;
1153
+ /** Dropdown menu content */
1154
+ children: React.ReactNode;
1155
+ /** Horizontal alignment relative to the anchor. Default: 'left' */
1156
+ align?: 'left' | 'right';
1157
+ /** Optional custom CSS class for the container */
1158
+ className?: string;
1159
+ /** Optional custom CSS style for the container */
1160
+ style?: React.CSSProperties;
1161
+ }
1162
+
1163
+ export type PanelProps = {
1164
+ /** Whether the panel is visible */
1165
+ isOpen: boolean;
1166
+ /** Called when user clicks the back button */
1167
+ onClose: () => void;
1168
+ /** Panel title shown in the header */
1169
+ title?: string;
1170
+ /** Panel body content */
1171
+ children: React.ReactNode;
1172
+ /** Optional header content (replaces default title + back button) */
1173
+ headerContent?: React.ReactNode;
1174
+ /** Additional CSS class name */
1175
+ className?: string;
1176
+ };
1177
+
938
1178
  /* ----------------------------------------------------------
939
1179
  Channel Info types
940
1180
  ---------------------------------------------------------- */
@@ -964,6 +1204,13 @@ export type AttachmentItem = {
964
1204
 
965
1205
  export type MediaTab = 'members' | 'media' | 'links' | 'files';
966
1206
 
1207
+ export type ChannelInfoTabHeaderProps = {
1208
+ activeTab: MediaTab;
1209
+ onTabChange: (tab: MediaTab) => void;
1210
+ availableTabs: MediaTab[];
1211
+ tabCounts: Record<MediaTab, number>;
1212
+ };
1213
+
967
1214
  /* Sub-component prop types for consumer customization */
968
1215
 
969
1216
  export type ChannelInfoMemberItemProps = {
@@ -979,6 +1226,8 @@ export type ChannelInfoMemberItemProps = {
979
1226
  canPromote?: boolean;
980
1227
  onDemote?: (id: string) => void;
981
1228
  canDemote?: boolean;
1229
+ /** Custom labels for member roles (owner, moder, member, pending) */
1230
+ roleLabels?: Record<string, string>;
982
1231
  };
983
1232
 
984
1233
  export type ChannelInfoMediaItemProps = {
@@ -1030,23 +1279,35 @@ export type ChannelInfoActionsProps = {
1030
1279
  onSettingsClick?: () => void;
1031
1280
  onLeaveChannel?: () => void;
1032
1281
  onDeleteChannel?: () => void;
1282
+ onTruncateChannel?: () => void;
1033
1283
  onBlockUser?: () => void;
1034
1284
  onUnblockUser?: () => void;
1285
+ onPin?: () => void;
1286
+ onUnpin?: () => void;
1035
1287
  isTeamChannel?: boolean;
1036
1288
  isTopic?: boolean;
1037
1289
  isClosedTopic?: boolean;
1038
1290
  isBlocked?: boolean;
1291
+ isPinned?: boolean;
1039
1292
  currentUserRole?: string;
1040
1293
  searchLabel?: string;
1041
1294
  settingsLabel?: string;
1042
1295
  deleteLabel?: string;
1296
+ truncateLabel?: string;
1043
1297
  leaveLabel?: string;
1044
1298
  blockLabel?: string;
1045
1299
  unblockLabel?: string;
1300
+ pinLabel?: string;
1301
+ unpinLabel?: string;
1046
1302
  onCloseTopic?: () => void;
1047
1303
  onReopenTopic?: () => void;
1048
1304
  closeTopicLabel?: string;
1049
1305
  reopenTopicLabel?: string;
1306
+ onDeleteTopic?: () => void;
1307
+ deleteTopicLabel?: string;
1308
+ onCreateTopic?: () => void;
1309
+ createTopicLabel?: string;
1310
+ topicsEnabled?: boolean;
1050
1311
  };
1051
1312
 
1052
1313
  export type ChannelInfoMember = {
@@ -1060,6 +1321,7 @@ export type ChannelInfoMember = {
1060
1321
  export type EditChannelData = {
1061
1322
  name?: string;
1062
1323
  image?: string;
1324
+ banner?: string;
1063
1325
  description?: string;
1064
1326
  public?: boolean;
1065
1327
  };
@@ -1167,6 +1429,7 @@ export type ChannelInfoTabsProps = {
1167
1429
  onUnbanMember?: (id: string) => void;
1168
1430
  onPromoteMember?: (id: string) => void;
1169
1431
  onDemoteMember?: (id: string) => void;
1432
+ isPreviewMode?: boolean;
1170
1433
 
1171
1434
  /** Label for the 'Add Member' button in the Members tab (default: 'Add Member') */
1172
1435
  addMemberButtonLabel?: string;
@@ -1179,7 +1442,14 @@ export type ChannelInfoTabsProps = {
1179
1442
  LinkItemComponent?: React.ComponentType<ChannelInfoLinkItemProps>;
1180
1443
  FileItemComponent?: React.ComponentType<ChannelInfoFileItemProps>;
1181
1444
  EmptyStateComponent?: React.ComponentType<ChannelInfoEmptyStateProps>;
1182
- LoadingComponent?: React.ComponentType;
1445
+ LoadingComponent?: React.ComponentType<{ tab?: string }>;
1446
+ /** Custom component for the tab header buttons */
1447
+ TabHeaderComponent?: React.ComponentType<ChannelInfoTabHeaderProps>;
1448
+ /** Whether the tabs panel is currently visible — controls data fetching (default: true) */
1449
+ isVisible?: boolean;
1450
+ roleLabels?: Record<string, string>;
1451
+ /** Ref or Element of the parent scrollable container — used for virtualization sync (default: undefined) */
1452
+ scrollContainerRef?: React.RefObject<HTMLDivElement | null> | HTMLDivElement | null;
1183
1453
  };
1184
1454
 
1185
1455
  export type ChannelInfoProps = {
@@ -1193,6 +1463,8 @@ export type ChannelInfoProps = {
1193
1463
  onClose?: () => void;
1194
1464
  /** Custom Title String for the banner */
1195
1465
  title?: string;
1466
+ /** Whether the panel is visible — controls data fetching timing (default: true) */
1467
+ isVisible?: boolean;
1196
1468
 
1197
1469
  /** Custom components to replace internal sections */
1198
1470
  HeaderComponent?: React.ComponentType<ChannelInfoHeaderProps>;
@@ -1203,6 +1475,8 @@ export type ChannelInfoProps = {
1203
1475
  AddMemberModalComponent?: React.ComponentType<AddMemberModalProps>;
1204
1476
  /** Custom component replacing the entire EditChannelModal */
1205
1477
  EditChannelModalComponent?: React.ComponentType<EditChannelModalProps>;
1478
+ /** Custom component replacing the entire EditTopicModal */
1479
+ EditTopicModalComponent?: React.ComponentType<TopicModalProps>;
1206
1480
 
1207
1481
  /** Custom sub-component overrides (passed through to TabsComponent) */
1208
1482
  MemberItemComponent?: React.ComponentType<ChannelInfoMemberItemProps>;
@@ -1210,7 +1484,9 @@ export type ChannelInfoProps = {
1210
1484
  LinkItemComponent?: React.ComponentType<ChannelInfoLinkItemProps>;
1211
1485
  FileItemComponent?: React.ComponentType<ChannelInfoFileItemProps>;
1212
1486
  EmptyStateComponent?: React.ComponentType<ChannelInfoEmptyStateProps>;
1213
- LoadingComponent?: React.ComponentType;
1487
+ LoadingComponent?: React.ComponentType<{ tab?: string }>;
1488
+ /** Custom component for the tab header buttons (passed through to TabsComponent) */
1489
+ TabHeaderComponent?: React.ComponentType<ChannelInfoTabHeaderProps>;
1214
1490
 
1215
1491
  /** Add Member customization (passed through to AddMemberModal) */
1216
1492
  addMemberModalTitle?: string;
@@ -1243,15 +1519,27 @@ export type ChannelInfoProps = {
1243
1519
  editChannelMaxImageSizeError?: string;
1244
1520
 
1245
1521
  /** Action Labels */
1522
+ /** Custom component for the search panel */
1523
+ MessageSearchPanelComponent?: React.ComponentType<MessageSearchPanelProps>;
1524
+ /** Custom component for the channel settings panel */
1525
+ ChannelSettingsPanelComponent?: React.ComponentType<ChannelSettingsPanelProps>;
1246
1526
  actionsSearchLabel?: string;
1247
1527
  actionsSettingsLabel?: string;
1248
1528
  actionsDeleteLabel?: string;
1529
+ actionsTruncateLabel?: string;
1249
1530
  actionsLeaveLabel?: string;
1531
+ actionsPinLabel?: string;
1532
+ actionsUnpinLabel?: string;
1533
+ actionsPinTopicLabel?: string;
1534
+ actionsUnpinTopicLabel?: string;
1250
1535
 
1251
1536
  /** Action callbacks */
1252
1537
  onSearchClick?: () => void;
1253
1538
  onLeaveChannel?: () => void;
1254
1539
  onDeleteChannel?: () => void;
1540
+ onTruncateChannel?: (channel: Channel) => void;
1541
+ onPinChannel?: () => void;
1542
+ onUnpinChannel?: () => void;
1255
1543
  onAddMemberClick?: () => void;
1256
1544
  onRemoveMember?: (id: string) => void;
1257
1545
  onBanMember?: (id: string) => void;
@@ -1267,11 +1555,17 @@ export type ChannelInfoProps = {
1267
1555
  actionsUnblockLabel?: string;
1268
1556
  actionsCloseTopicLabel?: string;
1269
1557
  actionsReopenTopicLabel?: string;
1558
+ actionsDeleteTopicLabel?: string;
1559
+ actionsCreateTopicLabel?: string;
1560
+ onDeleteTopic?: (channel: Channel) => void;
1561
+ onCreateTopic?: (channel: Channel) => void;
1270
1562
 
1271
1563
  /** Settings Panel Topics Labels */
1272
1564
  settingsWorkspaceTopicsTitle?: string;
1273
1565
  settingsTopicsFeatureName?: string;
1274
1566
  settingsTopicsFeatureDescription?: string;
1567
+ /** Custom labels for member roles (owner, moder, member, pending) */
1568
+ roleLabels?: Record<string, string>;
1275
1569
  };
1276
1570
 
1277
1571
  /* ----------------------------------------------------------
@@ -1385,12 +1679,54 @@ export type UserPickerProps = {
1385
1679
  emptyText?: string;
1386
1680
  loadingMoreText?: string;
1387
1681
  selectedEmptyLabel?: string;
1682
+ friendsOnly?: boolean;
1388
1683
  };
1389
1684
 
1390
1685
  /* ----------------------------------------------------------
1391
1686
  Create Channel Modal Props
1392
1687
  ---------------------------------------------------------- */
1393
1688
 
1689
+ export type CreateChannelTabsProps = {
1690
+ activeTab: 'messaging' | 'team';
1691
+ onTabChange: (tab: 'messaging' | 'team') => void;
1692
+ disabled?: boolean;
1693
+ directTabLabel?: string;
1694
+ groupTabLabel?: string;
1695
+ };
1696
+
1697
+ export type CreateChannelFooterProps = {
1698
+ tab: 'messaging' | 'team';
1699
+ step: 1 | 2;
1700
+ onCancel: () => void;
1701
+ onNext: () => void;
1702
+ onBack: () => void;
1703
+ onCreate: () => void;
1704
+ isCreating: boolean;
1705
+ isValid: boolean;
1706
+ hasExistingDirectChannel?: boolean;
1707
+ cancelButtonLabel?: string;
1708
+ createButtonLabel?: string;
1709
+ creatingButtonLabel?: string;
1710
+ messageButtonLabel?: string;
1711
+ nextButtonLabel?: string;
1712
+ backButtonLabel?: string;
1713
+ };
1714
+
1715
+ export type CreateChannelGroupFieldsProps = {
1716
+ name: string;
1717
+ onNameChange: (name: string) => void;
1718
+ description: string;
1719
+ onDescriptionChange: (desc: string) => void;
1720
+ isPublic: boolean;
1721
+ onPublicChange: (isPublic: boolean) => void;
1722
+ disabled?: boolean;
1723
+ groupNameLabel?: string;
1724
+ groupNamePlaceholder?: string;
1725
+ groupDescriptionLabel?: string;
1726
+ groupDescriptionPlaceholder?: string;
1727
+ groupPublicLabel?: string;
1728
+ };
1729
+
1394
1730
  export type CreateChannelModalProps = {
1395
1731
  isOpen: boolean;
1396
1732
  onClose: () => void;
@@ -1399,6 +1735,15 @@ export type CreateChannelModalProps = {
1399
1735
  /** Override visual components */
1400
1736
  AvatarComponent?: React.ComponentType<AvatarProps>;
1401
1737
  UserItemComponent?: React.ComponentType<UserPickerItemProps>;
1738
+ TabsComponent?: React.ComponentType<CreateChannelTabsProps>;
1739
+ FooterComponent?: React.ComponentType<CreateChannelFooterProps>;
1740
+ GroupFieldsComponent?: React.ComponentType<CreateChannelGroupFieldsProps>;
1741
+ SearchInputComponent?: React.ComponentType<{
1742
+ value: string;
1743
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
1744
+ placeholder: string;
1745
+ }>;
1746
+ SelectedBoxComponent?: React.ComponentType<UserPickerSelectedBoxProps>;
1402
1747
 
1403
1748
  /** i18n labels */
1404
1749
  title?: string;
@@ -1415,6 +1760,9 @@ export type CreateChannelModalProps = {
1415
1760
  createButtonLabel?: string;
1416
1761
  creatingButtonLabel?: string;
1417
1762
  messageButtonLabel?: string;
1763
+ nextButtonLabel?: string;
1764
+ backButtonLabel?: string;
1765
+ emptyStateLabel?: string;
1418
1766
 
1419
1767
  /** File upload configuration for group channel images */
1420
1768
  imageAccept?: string;