@sendbird/uikit-react-native 3.0.4 → 3.1.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 (145) hide show
  1. package/lib/commonjs/components/ChannelInput/SendInput.js +151 -19
  2. package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
  3. package/lib/commonjs/components/ChannelInput/index.js +5 -13
  4. package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
  5. package/lib/commonjs/components/ChannelMessageList/index.js +34 -20
  6. package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
  7. package/lib/commonjs/components/ChatFlatList/index.js +1 -1
  8. package/lib/commonjs/components/ChatFlatList/index.js.map +1 -1
  9. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
  10. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
  11. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +191 -0
  12. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
  13. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +12 -1
  14. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
  15. package/lib/commonjs/components/MessageSearchResultItem.js +2 -8
  16. package/lib/commonjs/components/MessageSearchResultItem.js.map +1 -1
  17. package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
  18. package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
  19. package/lib/commonjs/containers/GroupChannelPreviewContainer.js +3 -9
  20. package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -1
  21. package/lib/commonjs/containers/SendbirdUIKitContainer.js +43 -9
  22. package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
  23. package/lib/commonjs/contexts/SendbirdChatCtx.js +5 -0
  24. package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
  25. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js +5 -1
  26. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
  27. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +47 -10
  28. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  29. package/lib/commonjs/domain/groupChannel/module/moduleContext.js +38 -3
  30. package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
  31. package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
  32. package/lib/commonjs/domain/openChannel/types.js.map +1 -1
  33. package/lib/commonjs/fragments/createGroupChannelFragment.js +19 -0
  34. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  35. package/lib/commonjs/hooks/useConnection.js +2 -1
  36. package/lib/commonjs/hooks/useConnection.js.map +1 -1
  37. package/lib/commonjs/hooks/useMentionSuggestion.js +1 -1
  38. package/lib/commonjs/hooks/useMentionSuggestion.js.map +1 -1
  39. package/lib/commonjs/hooks/useMentionTextInput.js +4 -3
  40. package/lib/commonjs/hooks/useMentionTextInput.js.map +1 -1
  41. package/lib/commonjs/libs/MentionManager.js.map +1 -1
  42. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  43. package/lib/commonjs/localization/createBaseStringSet.js +29 -0
  44. package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
  45. package/lib/commonjs/platform/createMediaService.native.js +1 -1
  46. package/lib/commonjs/platform/createMediaService.native.js.map +1 -1
  47. package/lib/commonjs/platform/types.js.map +1 -1
  48. package/lib/commonjs/utils/pubsub.js +3 -1
  49. package/lib/commonjs/utils/pubsub.js.map +1 -1
  50. package/lib/commonjs/version.js +1 -1
  51. package/lib/commonjs/version.js.map +1 -1
  52. package/lib/module/components/ChannelInput/SendInput.js +153 -21
  53. package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
  54. package/lib/module/components/ChannelInput/index.js +6 -14
  55. package/lib/module/components/ChannelInput/index.js.map +1 -1
  56. package/lib/module/components/ChannelMessageList/index.js +34 -20
  57. package/lib/module/components/ChannelMessageList/index.js.map +1 -1
  58. package/lib/module/components/ChatFlatList/index.js +1 -1
  59. package/lib/module/components/ChatFlatList/index.js.map +1 -1
  60. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
  61. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
  62. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +182 -0
  63. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
  64. package/lib/module/components/GroupChannelMessageRenderer/index.js +13 -2
  65. package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
  66. package/lib/module/components/MessageSearchResultItem.js +3 -9
  67. package/lib/module/components/MessageSearchResultItem.js.map +1 -1
  68. package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
  69. package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
  70. package/lib/module/containers/GroupChannelPreviewContainer.js +4 -10
  71. package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -1
  72. package/lib/module/containers/SendbirdUIKitContainer.js +43 -9
  73. package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
  74. package/lib/module/contexts/SendbirdChatCtx.js +6 -1
  75. package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
  76. package/lib/module/domain/groupChannel/component/GroupChannelInput.js +5 -1
  77. package/lib/module/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
  78. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +50 -13
  79. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  80. package/lib/module/domain/groupChannel/module/moduleContext.js +39 -4
  81. package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
  82. package/lib/module/domain/groupChannel/types.js.map +1 -1
  83. package/lib/module/domain/openChannel/types.js.map +1 -1
  84. package/lib/module/fragments/createGroupChannelFragment.js +19 -0
  85. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  86. package/lib/module/hooks/useConnection.js +2 -1
  87. package/lib/module/hooks/useConnection.js.map +1 -1
  88. package/lib/module/hooks/useMentionSuggestion.js +1 -1
  89. package/lib/module/hooks/useMentionSuggestion.js.map +1 -1
  90. package/lib/module/hooks/useMentionTextInput.js +4 -3
  91. package/lib/module/hooks/useMentionTextInput.js.map +1 -1
  92. package/lib/module/libs/MentionManager.js.map +1 -1
  93. package/lib/module/localization/StringSet.type.js.map +1 -1
  94. package/lib/module/localization/createBaseStringSet.js +30 -1
  95. package/lib/module/localization/createBaseStringSet.js.map +1 -1
  96. package/lib/module/platform/createMediaService.native.js +1 -1
  97. package/lib/module/platform/createMediaService.native.js.map +1 -1
  98. package/lib/module/platform/types.js.map +1 -1
  99. package/lib/module/utils/pubsub.js +3 -1
  100. package/lib/module/utils/pubsub.js.map +1 -1
  101. package/lib/module/version.js +1 -1
  102. package/lib/module/version.js.map +1 -1
  103. package/lib/typescript/src/components/ChannelInput/index.d.ts +2 -0
  104. package/lib/typescript/src/components/ChannelMessageList/index.d.ts +4 -1
  105. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +9 -0
  106. package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +1 -0
  107. package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +1 -0
  108. package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +4 -2
  109. package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +4 -0
  110. package/lib/typescript/src/domain/groupChannel/types.d.ts +6 -2
  111. package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +1 -1
  112. package/lib/typescript/src/domain/openChannel/types.d.ts +1 -2
  113. package/lib/typescript/src/libs/MentionManager.d.ts +1 -4
  114. package/lib/typescript/src/localization/StringSet.type.d.ts +7 -1
  115. package/lib/typescript/src/platform/types.d.ts +10 -11
  116. package/lib/typescript/src/version.d.ts +1 -1
  117. package/package.json +6 -6
  118. package/src/components/ChannelInput/SendInput.tsx +184 -51
  119. package/src/components/ChannelInput/index.tsx +11 -15
  120. package/src/components/ChannelMessageList/index.tsx +45 -27
  121. package/src/components/ChatFlatList/index.tsx +1 -1
  122. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.tsx +5 -1
  123. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +177 -0
  124. package/src/components/GroupChannelMessageRenderer/index.tsx +16 -1
  125. package/src/components/MessageSearchResultItem.tsx +3 -5
  126. package/src/components/ReactionAddons/BottomSheetReactionAddon.tsx +6 -7
  127. package/src/containers/GroupChannelPreviewContainer.tsx +6 -7
  128. package/src/containers/SendbirdUIKitContainer.tsx +40 -10
  129. package/src/contexts/SendbirdChatCtx.tsx +7 -1
  130. package/src/domain/groupChannel/component/GroupChannelInput.tsx +5 -1
  131. package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +46 -13
  132. package/src/domain/groupChannel/module/moduleContext.tsx +38 -3
  133. package/src/domain/groupChannel/types.ts +8 -2
  134. package/src/domain/openChannel/types.ts +1 -2
  135. package/src/fragments/createGroupChannelFragment.tsx +15 -0
  136. package/src/hooks/useConnection.ts +1 -1
  137. package/src/hooks/useMentionSuggestion.ts +2 -1
  138. package/src/hooks/useMentionTextInput.ts +2 -2
  139. package/src/libs/MentionManager.tsx +1 -8
  140. package/src/localization/StringSet.type.ts +11 -0
  141. package/src/localization/createBaseStringSet.ts +30 -0
  142. package/src/platform/createMediaService.native.tsx +1 -1
  143. package/src/platform/types.ts +9 -9
  144. package/src/utils/pubsub.ts +3 -1
  145. package/src/version.ts +1 -1
@@ -10,7 +10,7 @@ import type { ClipboardServiceInterface, FileServiceInterface, MediaServiceInter
10
10
  import type { ErrorBoundaryProps, LocalCacheStorage } from '../types';
11
11
  type UnimplementedFeatures = 'enableVoiceMessage' | 'threadReplySelectType' | 'replyType';
12
12
  export declare const SendbirdUIKit: Readonly<{
13
- VERSION: "3.0.4";
13
+ VERSION: "3.1.1";
14
14
  PLATFORM: string;
15
15
  DEFAULT: {
16
16
  AUTO_PUSH_TOKEN_REGISTRATION: boolean;
@@ -32,7 +32,9 @@ export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
32
32
  } & Partial<ChatRelatedFeaturesInUIKit>;
33
33
  uikitOptions?: PartialDeep<{
34
34
  common: SBUConfig['common'];
35
- groupChannel: Omit<SBUConfig['groupChannel']['channel'], UnimplementedFeatures>;
35
+ groupChannel: Omit<SBUConfig['groupChannel']['channel'], UnimplementedFeatures> & {
36
+ replyType: Extract<SBUConfig['groupChannel']['channel']['replyType'], 'none' | 'quote_reply'>;
37
+ };
36
38
  groupChannelList: SBUConfig['groupChannel']['channelList'];
37
39
  groupChannelSettings: SBUConfig['groupChannel']['setting'];
38
40
  openChannel: SBUConfig['openChannel']['channel'];
@@ -1,5 +1,9 @@
1
1
  import React from 'react';
2
2
  declare const _default: React.MemoExoticComponent<(props: Pick<import("../../../components/ChannelMessageList").ChannelMessageListProps<import("@sendbird/chat/groupChannel").GroupChannel>, "channel" | "onTopReached" | "onBottomReached" | "onScrolledAwayFromBottom" | "currentUserId" | "enableMessageGrouping" | "searchItem" | "hasNext" | "onDeleteMessage" | "onResendFailedMessage" | "onPressMediaMessage" | "renderNewMessagesButton" | "renderScrollToBottomButton" | "renderMessage" | "messages" | "newMessages" | "scrolledAwayFromBottom" | "flatListProps"> & {
3
3
  onResetMessageList: (callback?: (() => void) | undefined) => void;
4
+ onResetMessageListWithStartingPoint: (startingPoint: number, callback?: (() => void) | undefined) => void;
5
+ onUpdateSearchItem: (searchItem?: {
6
+ startingPoint: number;
7
+ } | undefined) => void;
4
8
  }) => JSX.Element>;
5
9
  export default _default;
@@ -34,6 +34,8 @@ export interface GroupChannelProps {
34
34
  };
35
35
  MessageList: Pick<ChannelMessageListProps<SendbirdGroupChannel>, 'enableMessageGrouping' | 'currentUserId' | 'channel' | 'messages' | 'newMessages' | 'scrolledAwayFromBottom' | 'onScrolledAwayFromBottom' | 'onTopReached' | 'onBottomReached' | 'onResendFailedMessage' | 'onDeleteMessage' | 'onPressMediaMessage' | 'renderMessage' | 'renderNewMessagesButton' | 'renderScrollToBottomButton' | 'flatListProps' | 'hasNext' | 'searchItem'> & {
36
36
  onResetMessageList: (callback?: () => void) => void;
37
+ onResetMessageListWithStartingPoint: (startingPoint: number, callback?: () => void) => void;
38
+ onUpdateSearchItem: (searchItem?: GroupChannelProps['MessageList']['searchItem']) => void;
37
39
  };
38
40
  Input: Pick<ChannelInputProps, 'shouldRenderInput' | 'onPressSendUserMessage' | 'onPressSendFileMessage' | 'onPressUpdateUserMessage' | 'onPressUpdateFileMessage' | 'SuggestedMentionList' | 'AttachmentsButton'>;
39
41
  SuggestedMentionList: SuggestedMentionListProps;
@@ -52,10 +54,12 @@ export interface GroupChannelProps {
52
54
  export interface GroupChannelContextsType {
53
55
  Fragment: React.Context<{
54
56
  headerTitle: string;
57
+ keyboardAvoidOffset?: number;
55
58
  channel: SendbirdGroupChannel;
56
59
  messageToEdit?: SendbirdUserMessage | SendbirdFileMessage;
57
60
  setMessageToEdit: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
58
- keyboardAvoidOffset?: number;
61
+ messageToReply?: SendbirdUserMessage | SendbirdFileMessage;
62
+ setMessageToReply: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
59
63
  }>;
60
64
  TypingIndicator: React.Context<{
61
65
  typingUsers: SendbirdUser[];
@@ -78,7 +82,7 @@ export type GroupChannelPubSubContextPayload = {
78
82
  message: SendbirdUserMessage | SendbirdFileMessage;
79
83
  };
80
84
  } | {
81
- type: 'MESSAGES_RECEIVED';
85
+ type: 'MESSAGES_RECEIVED' | 'MESSAGES_UPDATED';
82
86
  data: {
83
87
  messages: SendbirdMessage[];
84
88
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  declare const _default: React.MemoExoticComponent<({ onPressHeaderLeft, onPressHeaderRight, rightIconName }: {
3
- rightIconName: "search" | "photo" | "message" | "user" | "document" | "done" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "delete" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thumbnail-none" | "unarchive";
3
+ rightIconName: "search" | "photo" | "user" | "document" | "done" | "message" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "delete" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thumbnail-none" | "unarchive";
4
4
  onPressHeaderLeft: () => void;
5
5
  onPressHeaderRight: () => void;
6
6
  }) => JSX.Element>;
@@ -6,7 +6,6 @@ import type { ChannelInputProps } from '../../components/ChannelInput';
6
6
  import type { ChannelMessageListProps } from '../../components/ChannelMessageList';
7
7
  import type { CommonComponent } from '../../types';
8
8
  import type { PubSub } from '../../utils/pubsub';
9
- import type { GroupChannelPubSubContextPayload } from '../groupChannel/types';
10
9
  export type OpenChannelProps = {
11
10
  Fragment: {
12
11
  channel: SendbirdOpenChannel;
@@ -54,7 +53,7 @@ export type OpenChannelContextsType = {
54
53
  setMessageToEdit: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
55
54
  keyboardAvoidOffset?: number;
56
55
  }>;
57
- PubSub: React.Context<PubSub<GroupChannelPubSubContextPayload>>;
56
+ PubSub: React.Context<PubSub<OpenChannelPubSubContextPayload>>;
58
57
  };
59
58
  export interface OpenChannelModule {
60
59
  Provider: CommonComponent<OpenChannelProps['Provider']>;
@@ -52,9 +52,6 @@ declare class MentionManager {
52
52
  mentionedText: string;
53
53
  mentionedUsers: MentionedUser[];
54
54
  };
55
- shouldUseMentionedMessageTemplate: (message?: SendbirdUserMessage | SendbirdFileMessage, mentionEnabled?: boolean) => message is RequiredSpecific<import("@sendbird/chat/message").FileMessage | import("@sendbird/chat/message").UserMessage, "mentionedMessageTemplate" | "mentionedUsers" | "mentionedUserIds" | "mentionType">;
55
+ shouldUseMentionedMessageTemplate: (message?: SendbirdUserMessage | SendbirdFileMessage, mentionEnabled?: boolean) => boolean;
56
56
  }
57
- type RequiredSpecific<T, K extends keyof T> = T & {
58
- [P in K]-?: T[P];
59
- };
60
57
  export default MentionManager;
@@ -1,5 +1,5 @@
1
1
  import type { Locale } from 'date-fns';
2
- import type { SendbirdBaseMessage, SendbirdFileMessage, SendbirdGroupChannel, SendbirdMember, SendbirdMessage, SendbirdOpenChannel, SendbirdParticipant, SendbirdUser } from '@sendbird/uikit-utils';
2
+ import type { SendbirdBaseMessage, SendbirdFileMessage, SendbirdGroupChannel, SendbirdMember, SendbirdMessage, SendbirdOpenChannel, SendbirdParticipant, SendbirdUser, SendbirdUserMessage } from '@sendbird/uikit-utils';
3
3
  /**
4
4
  * StringSet interface
5
5
  * Do not configure over 3 depths (for overrides easy)
@@ -218,6 +218,7 @@ export interface StringSet {
218
218
  USER_NO_NAME: string;
219
219
  CHANNEL_NO_MEMBERS: string;
220
220
  TYPING_INDICATOR_TYPINGS: (users: SendbirdUser[]) => string | undefined;
221
+ REPLY_FROM_SENDER_TO_RECEIVER: (replyMessage: SendbirdUserMessage | SendbirdFileMessage, parentMessage: SendbirdUserMessage | SendbirdFileMessage, currentUserId?: string) => string;
221
222
  USER_BAR_ME_POSTFIX: string;
222
223
  USER_BAR_OPERATOR: string;
223
224
  REGISTER_AS_OPERATOR: string;
@@ -232,6 +233,7 @@ export interface StringSet {
232
233
  CHANNEL_INPUT_PLACEHOLDER_ACTIVE: string;
233
234
  CHANNEL_INPUT_PLACEHOLDER_DISABLED: string;
234
235
  CHANNEL_INPUT_PLACEHOLDER_MUTED: string;
236
+ CHANNEL_INPUT_PLACEHOLDER_REPLY: string;
235
237
  CHANNEL_INPUT_EDIT_OK: string;
236
238
  CHANNEL_INPUT_EDIT_CANCEL: string;
237
239
  /** ChannelInput > Attachments **/
@@ -239,11 +241,14 @@ export interface StringSet {
239
241
  CHANNEL_INPUT_ATTACHMENT_CAMERA_VIDEO: string;
240
242
  CHANNEL_INPUT_ATTACHMENT_PHOTO_LIBRARY: string;
241
243
  CHANNEL_INPUT_ATTACHMENT_FILES: string;
244
+ CHANNEL_INPUT_REPLY_PREVIEW_TITLE: (user: SendbirdUser) => string;
245
+ CHANNEL_INPUT_REPLY_PREVIEW_BODY: (message: SendbirdUserMessage | SendbirdFileMessage) => string;
242
246
  /** Channel > Message **/
243
247
  CHANNEL_MESSAGE_COPY: string;
244
248
  CHANNEL_MESSAGE_EDIT: string;
245
249
  CHANNEL_MESSAGE_SAVE: string;
246
250
  CHANNEL_MESSAGE_DELETE: string;
251
+ CHANNEL_MESSAGE_REPLY: string;
247
252
  /** Channel > Message > Delete confirm **/
248
253
  CHANNEL_MESSAGE_DELETE_CONFIRM_TITLE: string;
249
254
  CHANNEL_MESSAGE_DELETE_CONFIRM_OK: string;
@@ -295,6 +300,7 @@ export interface StringSet {
295
300
  LEAVE_CHANNEL_ERROR: string;
296
301
  UNKNOWN_ERROR: string;
297
302
  GET_CHANNEL_ERROR: string;
303
+ FIND_PARENT_MSG_ERROR: string;
298
304
  };
299
305
  PROFILE_CARD: {
300
306
  BUTTON_MESSAGE: string;
@@ -50,19 +50,22 @@ export interface FilePickerServiceInterface {
50
50
  export interface FileSystemServiceInterface {
51
51
  save(options?: SaveOptions): Promise<DownloadedPath | null>;
52
52
  }
53
- interface VideoProps {
53
+ export type VideoProps = {
54
54
  source: {
55
55
  uri: string;
56
56
  } | number;
57
57
  resizeMode?: 'cover' | 'contain' | 'stretch';
58
58
  onLoad?: () => void;
59
- }
60
- interface GetVideoThumbnailOptions {
59
+ };
60
+ export type GetVideoThumbnailOptions = {
61
61
  url: string;
62
62
  timeMills?: number;
63
63
  quality?: number;
64
- }
65
- interface CompressImageOptions {
64
+ };
65
+ export type GetVideoThumbnailResult = Promise<{
66
+ path: string;
67
+ } | null>;
68
+ export type CompressImageOptions = {
66
69
  /**
67
70
  * A uri of image file to compress
68
71
  * */
@@ -80,11 +83,8 @@ interface CompressImageOptions {
80
83
  * 1 means highest quality and 0 the lowest quality.
81
84
  * */
82
85
  compressionRate?: number;
83
- }
84
- type GetVideoThumbnailResult = Promise<{
85
- path: string;
86
- } | null>;
87
- type CompressImageResult = Promise<{
86
+ };
87
+ export type CompressImageResult = Promise<{
88
88
  uri: string;
89
89
  size: number;
90
90
  } | null>;
@@ -93,4 +93,3 @@ export interface MediaServiceInterface {
93
93
  getVideoThumbnail(options: GetVideoThumbnailOptions): GetVideoThumbnailResult;
94
94
  compressImage(options: CompressImageOptions): CompressImageResult;
95
95
  }
96
- export {};
@@ -1,2 +1,2 @@
1
- declare const VERSION = "3.0.4";
1
+ declare const VERSION = "3.1.1";
2
2
  export default VERSION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendbird/uikit-react-native",
3
- "version": "3.0.4",
3
+ "version": "3.1.1",
4
4
  "description": "Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.",
5
5
  "keywords": [
6
6
  "sendbird",
@@ -58,10 +58,10 @@
58
58
  "access": "public"
59
59
  },
60
60
  "dependencies": {
61
- "@sendbird/uikit-chat-hooks": "3.0.4",
62
- "@sendbird/uikit-react-native-foundation": "3.0.4",
61
+ "@sendbird/uikit-chat-hooks": "3.1.1",
62
+ "@sendbird/uikit-react-native-foundation": "3.1.1",
63
63
  "@sendbird/uikit-tools": "^0.0.1-alpha.38",
64
- "@sendbird/uikit-utils": "3.0.4"
64
+ "@sendbird/uikit-utils": "3.1.1"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@bam.tech/react-native-image-resizer": "^3.0.4",
@@ -105,7 +105,7 @@
105
105
  "@react-native-clipboard/clipboard": ">=1.8.5",
106
106
  "@react-native-community/netinfo": ">=9.3.0",
107
107
  "@react-native-firebase/messaging": ">=14.4.0",
108
- "@sendbird/chat": "^4.9.2",
108
+ "@sendbird/chat": "^4.9.8",
109
109
  "@sendbird/react-native-scrollview-enhancer": "*",
110
110
  "date-fns": ">=2.28.0",
111
111
  "expo-av": ">=12.0.4",
@@ -204,5 +204,5 @@
204
204
  "readmeFile": "./README.md",
205
205
  "displayName": "@sendbird/uikit-react-native"
206
206
  },
207
- "gitHead": "bf8ff3723f82f75ccf994938d6e5468e6fb669be"
207
+ "gitHead": "cc1e2d626a4a3278e80d523b4c63fd3719c82441"
208
208
  }
@@ -9,17 +9,31 @@ import {
9
9
  } from 'react-native';
10
10
 
11
11
  import { MentionType } from '@sendbird/chat/message';
12
+ import type { BottomSheetItem } from '@sendbird/uikit-react-native-foundation';
12
13
  import {
13
14
  Icon,
15
+ ImageWithPlaceholder,
16
+ Text,
14
17
  TextInput,
18
+ VideoThumbnail,
15
19
  createStyleSheet,
16
20
  useAlert,
17
21
  useBottomSheet,
18
22
  useToast,
19
23
  useUIKitTheme,
20
24
  } from '@sendbird/uikit-react-native-foundation';
21
- import type { BottomSheetItem } from '@sendbird/uikit-react-native-foundation';
22
- import { SendbirdChannel, isImage, shouldCompressImage, useIIFE } from '@sendbird/uikit-utils';
25
+ import {
26
+ FileIcon,
27
+ Logger,
28
+ SendbirdBaseMessage,
29
+ SendbirdChannel,
30
+ getFileIconFromMessageType,
31
+ getMessageType,
32
+ getThumbnailUriFromFileMessage,
33
+ isImage,
34
+ shouldCompressImage,
35
+ useIIFE,
36
+ } from '@sendbird/uikit-utils';
23
37
 
24
38
  import { useLocalization, usePlatformService, useSendbirdChat } from '../../hooks/useContext';
25
39
  import SBUError from '../../libs/SBUError';
@@ -48,81 +62,192 @@ const SendInput = forwardRef<RNTextInput, SendInputProps>(function SendInput(
48
62
  inputFrozen,
49
63
  inputMuted,
50
64
  channel,
65
+ messageToReply,
66
+ setMessageToReply,
51
67
  },
52
68
  ref,
53
69
  ) {
54
70
  const { mentionManager, sbOptions } = useSendbirdChat();
71
+ const { select, colors, palette } = useUIKitTheme();
55
72
  const { STRINGS } = useLocalization();
56
- const { colors } = useUIKitTheme();
57
73
  const { openSheet } = useBottomSheet();
58
74
  const toast = useToast();
75
+ const { mediaService } = usePlatformService();
76
+
77
+ const messageReplyParams = useIIFE(() => {
78
+ const { groupChannel } = sbOptions.uikit;
79
+ if (!channel.isGroupChannel() || groupChannel.channel.replyType === 'none' || !messageToReply) return {};
80
+ return {
81
+ parentMessageId: messageToReply.messageId,
82
+ isReplyToChannel: true,
83
+ };
84
+ });
59
85
 
60
- const onFailureToSend = () => toast.show(STRINGS.TOAST.SEND_MSG_ERROR, 'error');
86
+ const messageMentionParams = useIIFE(() => {
87
+ const { groupChannel } = sbOptions.uikit;
88
+ if (!channel.isGroupChannel() || !groupChannel.channel.enableMention) return {};
89
+ return {
90
+ mentionType: MentionType.USERS,
91
+ mentionedUserIds: mentionedUsers.map((it) => it.user.userId),
92
+ mentionedMessageTemplate: mentionManager.textToMentionedMessageTemplate(
93
+ text,
94
+ mentionedUsers,
95
+ groupChannel.channel.enableMention,
96
+ ),
97
+ };
98
+ });
61
99
 
62
- const sendUserMessage = () => {
63
- const mentionType = MentionType.USERS;
64
- const mentionedUserIds = mentionedUsers.map((it) => it.user.userId);
65
- const mentionedMessageTemplate = mentionManager.textToMentionedMessageTemplate(
66
- text,
67
- mentionedUsers,
68
- sbOptions.uikit.groupChannel.channel.enableMention,
69
- );
100
+ const onFailureToSend = (error: Error) => {
101
+ toast.show(STRINGS.TOAST.SEND_MSG_ERROR, 'error');
102
+ Logger.error(STRINGS.TOAST.SEND_MSG_ERROR, error);
103
+ };
70
104
 
105
+ const sendUserMessage = () => {
71
106
  onPressSendUserMessage({
72
107
  message: text,
73
- mentionType,
74
- mentionedUserIds,
75
- mentionedMessageTemplate,
108
+ ...messageMentionParams,
109
+ ...messageReplyParams,
76
110
  }).catch(onFailureToSend);
77
111
 
78
112
  onChangeText('');
113
+ setMessageToReply?.();
79
114
  };
80
115
 
81
- const sheetItems = useChannelInputItems(channel, (file) => {
82
- onPressSendFileMessage({ file }).catch(onFailureToSend);
83
- });
116
+ const sendFileMessage = (file: FileType) => {
117
+ onPressSendFileMessage({
118
+ file,
119
+ ...messageReplyParams,
120
+ }).catch(onFailureToSend);
121
+
122
+ setMessageToReply?.();
123
+ };
124
+
125
+ const sheetItems = useChannelInputItems(channel, sendFileMessage);
84
126
  const onPressAttachment = () => openSheet({ sheetItems });
85
127
 
86
128
  const getPlaceholder = () => {
87
- if (!inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
88
- if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
89
129
  if (inputMuted) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_MUTED;
130
+ if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
131
+ if (inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
132
+ if (messageToReply) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_REPLY;
90
133
 
91
- return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
134
+ return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
92
135
  };
93
136
 
94
- return (
95
- <View style={styles.sendInputContainer}>
96
- {AttachmentsButton && <AttachmentsButton onPress={onPressAttachment} disabled={inputDisabled} />}
97
- <TextInput
98
- ref={ref}
99
- multiline
100
- disableFullscreenUI
101
- onSelectionChange={onSelectionChange}
102
- editable={!inputDisabled}
103
- onChangeText={onChangeText}
104
- style={styles.input}
105
- placeholder={getPlaceholder()}
106
- >
107
- {mentionManager.textToMentionedComponents(
108
- text,
109
- mentionedUsers,
110
- sbOptions.uikit.groupChannel.channel.enableMention,
111
- )}
112
- </TextInput>
137
+ const getFileIconAsImage = (url: string) => {
138
+ return <ImageWithPlaceholder source={{ uri: url }} style={styles.previewImage} />;
139
+ };
113
140
 
114
- {Boolean(text.trim()) && (
115
- <TouchableOpacity onPress={sendUserMessage} disabled={inputDisabled}>
116
- <Icon
117
- color={
118
- inputDisabled ? colors.ui.input.default.disabled.highlight : colors.ui.input.default.active.highlight
119
- }
120
- icon={'send'}
121
- size={24}
122
- containerStyle={styles.iconSend}
123
- />
124
- </TouchableOpacity>
141
+ const getFileIconAsVideoThumbnail = (url: string) => {
142
+ return (
143
+ <VideoThumbnail
144
+ style={styles.previewImage}
145
+ iconSize={0}
146
+ source={url}
147
+ fetchThumbnailFromVideoSource={(uri) => mediaService.getVideoThumbnail({ url: uri, timeMills: 1000 })}
148
+ />
149
+ );
150
+ };
151
+
152
+ const getFileIconAsSymbol = (icon: FileIcon) => {
153
+ return (
154
+ <Icon
155
+ icon={icon}
156
+ size={20}
157
+ color={colors.onBackground02}
158
+ containerStyle={{
159
+ backgroundColor: select({
160
+ light: palette.background100,
161
+ dark: palette.background500,
162
+ }),
163
+ width: 36,
164
+ height: 36,
165
+ borderRadius: 10,
166
+ marginRight: 10,
167
+ marginTop: 2,
168
+ }}
169
+ />
170
+ );
171
+ };
172
+
173
+ const getFileIcon = (messageToReply: SendbirdBaseMessage) => {
174
+ if (messageToReply?.isFileMessage()) {
175
+ const messageType = getMessageType(messageToReply);
176
+ switch (messageType) {
177
+ case 'file.image':
178
+ return getFileIconAsImage(getThumbnailUriFromFileMessage(messageToReply));
179
+ case 'file.video':
180
+ return getFileIconAsVideoThumbnail(getThumbnailUriFromFileMessage(messageToReply));
181
+ default:
182
+ return getFileIconAsSymbol(getFileIconFromMessageType(messageType));
183
+ }
184
+ }
185
+ return null;
186
+ };
187
+
188
+ return (
189
+ <View>
190
+ {messageToReply && (
191
+ <View
192
+ style={{
193
+ flexDirection: 'row',
194
+ paddingLeft: 18,
195
+ paddingRight: 16,
196
+ paddingTop: 10,
197
+ paddingBottom: 8,
198
+ alignItems: 'center',
199
+ borderTopWidth: 1,
200
+ borderColor: colors.onBackground04,
201
+ }}
202
+ >
203
+ <View style={{ flex: 1, flexDirection: 'row' }}>
204
+ {getFileIcon(messageToReply)}
205
+ <View style={{ flex: 1, flexDirection: 'column' }}>
206
+ <Text numberOfLines={1} style={{ fontSize: 13, fontWeight: '900', marginBottom: 4 }}>
207
+ {STRINGS.LABELS.CHANNEL_INPUT_REPLY_PREVIEW_TITLE(messageToReply.sender)}
208
+ </Text>
209
+ <Text numberOfLines={1} style={{ fontSize: 13, color: colors.onBackground03 }}>
210
+ {STRINGS.LABELS.CHANNEL_INPUT_REPLY_PREVIEW_BODY(messageToReply)}
211
+ </Text>
212
+ </View>
213
+ </View>
214
+ <TouchableOpacity onPress={() => setMessageToReply?.(undefined)}>
215
+ <Icon icon={'close'} size={24} color={colors.onBackground01} containerStyle={styles.iconSend} />
216
+ </TouchableOpacity>
217
+ </View>
125
218
  )}
219
+ <View style={styles.sendInputContainer}>
220
+ {AttachmentsButton && <AttachmentsButton onPress={onPressAttachment} disabled={inputDisabled} />}
221
+ <TextInput
222
+ ref={ref}
223
+ multiline
224
+ disableFullscreenUI
225
+ onSelectionChange={onSelectionChange}
226
+ editable={!inputDisabled}
227
+ onChangeText={onChangeText}
228
+ style={styles.input}
229
+ placeholder={getPlaceholder()}
230
+ >
231
+ {mentionManager.textToMentionedComponents(
232
+ text,
233
+ mentionedUsers,
234
+ sbOptions.uikit.groupChannel.channel.enableMention,
235
+ )}
236
+ </TextInput>
237
+
238
+ {Boolean(text.trim()) && (
239
+ <TouchableOpacity onPress={sendUserMessage} disabled={inputDisabled}>
240
+ <Icon
241
+ color={
242
+ inputDisabled ? colors.ui.input.default.disabled.highlight : colors.ui.input.default.active.highlight
243
+ }
244
+ icon={'send'}
245
+ size={24}
246
+ containerStyle={styles.iconSend}
247
+ />
248
+ </TouchableOpacity>
249
+ )}
250
+ </View>
126
251
  </View>
127
252
  );
128
253
  });
@@ -353,6 +478,14 @@ const styles = createStyleSheet({
353
478
  marginLeft: 4,
354
479
  padding: 4,
355
480
  },
481
+ previewImage: {
482
+ width: 36,
483
+ height: 36,
484
+ borderRadius: 10,
485
+ marginTop: 2,
486
+ marginRight: 10,
487
+ overflow: 'hidden',
488
+ },
356
489
  });
357
490
 
358
491
  export default SendInput;
@@ -1,4 +1,4 @@
1
- import React, { MutableRefObject, useEffect, useRef, useState } from 'react';
1
+ import React, { MutableRefObject, useEffect, useState } from 'react';
2
2
  import { KeyboardAvoidingView, Platform, TextInput, View } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
@@ -56,6 +56,10 @@ export type ChannelInputProps = {
56
56
  messageToEdit: undefined | SendbirdUserMessage | SendbirdFileMessage;
57
57
  setMessageToEdit: (message?: undefined | SendbirdUserMessage | SendbirdFileMessage) => void;
58
58
 
59
+ // reply - only available on group channel
60
+ messageToReply?: undefined | SendbirdUserMessage | SendbirdFileMessage;
61
+ setMessageToReply?: (message?: undefined | SendbirdUserMessage | SendbirdFileMessage) => void;
62
+
59
63
  // mention
60
64
  SuggestedMentionList?: (props: SuggestedMentionListProps) => JSX.Element | null;
61
65
 
@@ -83,9 +87,8 @@ const ChannelInput = (props: ChannelInputProps) => {
83
87
  messageToEdit,
84
88
  });
85
89
  const inputMode = useIIFE(() => {
86
- if (!messageToEdit) return 'send';
87
- if (messageToEdit.isFileMessage()) return 'send';
88
- return 'edit';
90
+ if (messageToEdit && !messageToEdit.isFileMessage()) return 'edit';
91
+ else return 'send';
89
92
  });
90
93
 
91
94
  const mentionAvailable =
@@ -95,7 +98,7 @@ const ChannelInput = (props: ChannelInputProps) => {
95
98
  const [inputHeight, setInputHeight] = useState(styles.inputDefault.height);
96
99
 
97
100
  useTypingTrigger(text, channel);
98
- useTextPersistenceOnDisabled(text, onChangeText, props.inputDisabled);
101
+ useTextClearOnDisabled(onChangeText, props.inputDisabled);
99
102
  useAutoFocusOnEditMode(textInputRef, messageToEdit);
100
103
 
101
104
  const onPressToMention = (user: SendbirdMember, searchStringRange: Range) => {
@@ -138,8 +141,8 @@ const ChannelInput = (props: ChannelInputProps) => {
138
141
  onChangeText={onChangeText}
139
142
  autoFocus={AUTO_FOCUS}
140
143
  onSelectionChange={onSelectionChange}
141
- messageToEdit={messageToEdit}
142
144
  mentionedUsers={mentionedUsers}
145
+ messageToEdit={messageToEdit}
143
146
  setMessageToEdit={setMessageToEdit}
144
147
  />
145
148
  )}
@@ -171,16 +174,9 @@ const useTypingTrigger = (text: string, channel: SendbirdBaseChannel) => {
171
174
  }
172
175
  };
173
176
 
174
- const useTextPersistenceOnDisabled = (text: string, setText: (val: string) => void, chatDisabled: boolean) => {
175
- const textTmpRef = useRef('');
176
-
177
+ const useTextClearOnDisabled = (setText: (val: string) => void, chatDisabled: boolean) => {
177
178
  useEffect(() => {
178
- if (chatDisabled) {
179
- textTmpRef.current = text;
180
- setText('');
181
- } else {
182
- setText(textTmpRef.current);
183
- }
179
+ if (chatDisabled) setText('');
184
180
  }, [chatDisabled]);
185
181
  };
186
182