@kesha-antonov/react-native-chat 5.0.0 → 6.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.
- package/README.md +533 -179
- package/lib/Actions.d.ts.map +1 -1
- package/lib/Actions.js +121 -42
- package/lib/Actions.js.map +1 -1
- package/lib/Avatar.d.ts.map +1 -1
- package/lib/Avatar.js +171 -86
- package/lib/Avatar.js.map +1 -1
- package/lib/Bubble/BubbleBody.d.ts +15 -0
- package/lib/Bubble/BubbleBody.d.ts.map +1 -0
- package/lib/Bubble/BubbleBody.js +218 -0
- package/lib/Bubble/BubbleBody.js.map +1 -0
- package/lib/Bubble/BubbleContent.d.ts +23 -0
- package/lib/Bubble/BubbleContent.d.ts.map +1 -0
- package/lib/Bubble/BubbleContent.js +446 -0
- package/lib/Bubble/BubbleContent.js.map +1 -0
- package/lib/Bubble/BubbleMenu.d.ts +45 -0
- package/lib/Bubble/BubbleMenu.d.ts.map +1 -0
- package/lib/Bubble/BubbleMenu.js +289 -0
- package/lib/Bubble/BubbleMenu.js.map +1 -0
- package/lib/Bubble/BubbleMeta.d.ts +17 -0
- package/lib/Bubble/BubbleMeta.d.ts.map +1 -0
- package/lib/Bubble/BubbleMeta.js +453 -0
- package/lib/Bubble/BubbleMeta.js.map +1 -0
- package/lib/Bubble/LiftedBubble.d.ts +18 -0
- package/lib/Bubble/LiftedBubble.d.ts.map +1 -0
- package/lib/Bubble/LiftedBubble.js +109 -0
- package/lib/Bubble/LiftedBubble.js.map +1 -0
- package/lib/Bubble/PressableBubbleRow.d.ts +33 -0
- package/lib/Bubble/PressableBubbleRow.d.ts.map +1 -0
- package/lib/Bubble/PressableBubbleRow.js +172 -0
- package/lib/Bubble/PressableBubbleRow.js.map +1 -0
- package/lib/Bubble/index.d.ts +6 -0
- package/lib/Bubble/index.d.ts.map +1 -1
- package/lib/Bubble/index.js +380 -494
- package/lib/Bubble/index.js.map +1 -1
- package/lib/Bubble/layout.d.ts +47 -0
- package/lib/Bubble/layout.d.ts.map +1 -0
- package/lib/Bubble/layout.js +258 -0
- package/lib/Bubble/layout.js.map +1 -0
- package/lib/Bubble/styles.d.ts +108 -16
- package/lib/Bubble/styles.d.ts.map +1 -1
- package/lib/Bubble/styles.js +227 -107
- package/lib/Bubble/styles.js.map +1 -1
- package/lib/Bubble/types.d.ts +19 -3
- package/lib/Bubble/types.d.ts.map +1 -1
- package/lib/Bubble/types.js.map +1 -1
- package/lib/Chat/Chat.d.ts +5 -0
- package/lib/Chat/Chat.d.ts.map +1 -0
- package/lib/Chat/Chat.js +464 -0
- package/lib/Chat/Chat.js.map +1 -0
- package/lib/Chat/ChatBackground.d.ts +16 -0
- package/lib/Chat/ChatBackground.d.ts.map +1 -0
- package/lib/Chat/ChatBackground.js +43 -0
- package/lib/Chat/ChatBackground.js.map +1 -0
- package/lib/Chat/ChatKeyboardAvoidingView.js +19 -4
- package/lib/Chat/ChatKeyboardAvoidingView.js.map +1 -1
- package/lib/Chat/ChatMessageList.d.ts +27 -0
- package/lib/Chat/ChatMessageList.d.ts.map +1 -0
- package/lib/Chat/ChatMessageList.js +220 -0
- package/lib/Chat/ChatMessageList.js.map +1 -0
- package/lib/Chat/ChatProviders.d.ts +18 -0
- package/lib/Chat/ChatProviders.d.ts.map +1 -0
- package/lib/Chat/ChatProviders.js +87 -0
- package/lib/Chat/ChatProviders.js.map +1 -0
- package/lib/Chat/ChatSafeAreaProvider.d.ts +35 -0
- package/lib/Chat/ChatSafeAreaProvider.d.ts.map +1 -0
- package/lib/Chat/ChatSafeAreaProvider.js +123 -0
- package/lib/Chat/ChatSafeAreaProvider.js.map +1 -0
- package/lib/Chat/ChatSelectionBar.d.ts +20 -0
- package/lib/Chat/ChatSelectionBar.d.ts.map +1 -0
- package/lib/Chat/ChatSelectionBar.js +141 -0
- package/lib/Chat/ChatSelectionBar.js.map +1 -0
- package/lib/Chat/ChatWrapper.d.ts +11 -0
- package/lib/Chat/ChatWrapper.d.ts.map +1 -0
- package/lib/Chat/ChatWrapper.js +98 -0
- package/lib/Chat/ChatWrapper.js.map +1 -0
- package/lib/Chat/ComposerHost.d.ts +20 -0
- package/lib/Chat/ComposerHost.d.ts.map +1 -0
- package/lib/Chat/ComposerHost.js +118 -0
- package/lib/Chat/ComposerHost.js.map +1 -0
- package/lib/Chat/index.d.ts +1 -8
- package/lib/Chat/index.d.ts.map +1 -1
- package/lib/Chat/index.js +1 -337
- package/lib/Chat/index.js.map +1 -1
- package/lib/Chat/styles.d.ts +14 -2
- package/lib/Chat/styles.d.ts.map +1 -1
- package/lib/Chat/styles.js +19 -9
- package/lib/Chat/styles.js.map +1 -1
- package/lib/Chat/types.d.ts +145 -11
- package/lib/Chat/types.d.ts.map +1 -1
- package/lib/Chat/types.js.map +1 -1
- package/lib/Chat/useChatContextValue.d.ts +19 -0
- package/lib/Chat/useChatContextValue.d.ts.map +1 -0
- package/lib/Chat/useChatContextValue.js +158 -0
- package/lib/Chat/useChatContextValue.js.map +1 -0
- package/lib/Chat/useChatMedia.d.ts +22 -0
- package/lib/Chat/useChatMedia.d.ts.map +1 -0
- package/lib/Chat/useChatMedia.js +127 -0
- package/lib/Chat/useChatMedia.js.map +1 -0
- package/lib/Chat/useChatSelection.d.ts +15 -0
- package/lib/Chat/useChatSelection.d.ts.map +1 -0
- package/lib/Chat/useChatSelection.js +106 -0
- package/lib/Chat/useChatSelection.js.map +1 -0
- package/lib/Chat/useComposerHandlers.d.ts +34 -0
- package/lib/Chat/useComposerHandlers.d.ts.map +1 -0
- package/lib/Chat/useComposerHandlers.js +330 -0
- package/lib/Chat/useComposerHandlers.js.map +1 -0
- package/lib/Chat/useComposerState.d.ts +27 -0
- package/lib/Chat/useComposerState.d.ts.map +1 -0
- package/lib/Chat/useComposerState.js +272 -0
- package/lib/Chat/useComposerState.js.map +1 -0
- package/lib/Chat/useInitialLayout.d.ts +19 -0
- package/lib/Chat/useInitialLayout.d.ts.map +1 -0
- package/lib/Chat/useInitialLayout.js +70 -0
- package/lib/Chat/useInitialLayout.js.map +1 -0
- package/lib/Chat/useMessageActions.d.ts +37 -0
- package/lib/Chat/useMessageActions.d.ts.map +1 -0
- package/lib/Chat/useMessageActions.js +323 -0
- package/lib/Chat/useMessageActions.js.map +1 -0
- package/lib/Chat/useMessageNavigation.d.ts +21 -0
- package/lib/Chat/useMessageNavigation.d.ts.map +1 -0
- package/lib/Chat/useMessageNavigation.js +149 -0
- package/lib/Chat/useMessageNavigation.js.map +1 -0
- package/lib/Chat/useOptionalPeerHints.d.ts +6 -0
- package/lib/Chat/useOptionalPeerHints.d.ts.map +1 -0
- package/lib/Chat/useOptionalPeerHints.js +63 -0
- package/lib/Chat/useOptionalPeerHints.js.map +1 -0
- package/lib/Chat/useResolvedReactions.d.ts +31 -0
- package/lib/Chat/useResolvedReactions.d.ts.map +1 -0
- package/lib/Chat/useResolvedReactions.js +95 -0
- package/lib/Chat/useResolvedReactions.js.map +1 -0
- package/lib/ChatAvatar.d.ts.map +1 -1
- package/lib/ChatAvatar.js +229 -84
- package/lib/ChatAvatar.js.map +1 -1
- package/lib/ChatContext.js +20 -10
- package/lib/ChatContext.js.map +1 -1
- package/lib/ChatList/ChatListAvatar.d.ts +21 -0
- package/lib/ChatList/ChatListAvatar.d.ts.map +1 -0
- package/lib/ChatList/ChatListAvatar.js +178 -0
- package/lib/ChatList/ChatListAvatar.js.map +1 -0
- package/lib/ChatList/ChatListCell.d.ts +16 -0
- package/lib/ChatList/ChatListCell.d.ts.map +1 -0
- package/lib/ChatList/ChatListCell.js +506 -0
- package/lib/ChatList/ChatListCell.js.map +1 -0
- package/lib/ChatList/ChatListShimmer.d.ts +3 -0
- package/lib/ChatList/ChatListShimmer.d.ts.map +1 -0
- package/lib/ChatList/ChatListShimmer.js +235 -0
- package/lib/ChatList/ChatListShimmer.js.map +1 -0
- package/lib/ChatList/index.d.ts +16 -0
- package/lib/ChatList/index.d.ts.map +1 -0
- package/lib/ChatList/index.js +1301 -0
- package/lib/ChatList/index.js.map +1 -0
- package/lib/ChatList/types.d.ts +128 -0
- package/lib/ChatList/types.d.ts.map +1 -0
- package/lib/ChatList/types.js +2 -0
- package/lib/ChatList/types.js.map +1 -0
- package/lib/ChatList/useChatList.d.ts +30 -0
- package/lib/ChatList/useChatList.d.ts.map +1 -0
- package/lib/ChatList/useChatList.js +211 -0
- package/lib/ChatList/useChatList.js.map +1 -0
- package/lib/ChatList/utils.d.ts +28 -0
- package/lib/ChatList/utils.d.ts.map +1 -0
- package/lib/ChatList/utils.js +60 -0
- package/lib/ChatList/utils.js.map +1 -0
- package/lib/Color.js +19 -19
- package/lib/Color.js.map +1 -1
- package/lib/Composer.d.ts.map +1 -1
- package/lib/Composer.js +148 -70
- package/lib/Composer.js.map +1 -1
- package/lib/Constant.js +4 -4
- package/lib/Constant.js.map +1 -1
- package/lib/Day/index.d.ts.map +1 -1
- package/lib/Day/index.js +115 -28
- package/lib/Day/index.js.map +1 -1
- package/lib/Day/styles.d.ts +3 -3
- package/lib/Day/styles.d.ts.map +1 -1
- package/lib/Day/styles.js +20 -17
- package/lib/Day/styles.js.map +1 -1
- package/lib/Day/types.js.map +1 -1
- package/lib/Icons.d.ts +1 -1
- package/lib/Icons.d.ts.map +1 -1
- package/lib/Icons.js.map +1 -1
- package/lib/InputToolbar/FieldGroup.d.ts +28 -0
- package/lib/InputToolbar/FieldGroup.d.ts.map +1 -0
- package/lib/InputToolbar/FieldGroup.js +143 -0
- package/lib/InputToolbar/FieldGroup.js.map +1 -0
- package/lib/InputToolbar/TakePreviewBar.d.ts +17 -0
- package/lib/InputToolbar/TakePreviewBar.d.ts.map +1 -0
- package/lib/InputToolbar/TakePreviewBar.js +126 -0
- package/lib/InputToolbar/TakePreviewBar.js.map +1 -0
- package/lib/InputToolbar/animations.d.ts +105 -0
- package/lib/InputToolbar/animations.d.ts.map +1 -0
- package/lib/InputToolbar/animations.js +238 -0
- package/lib/InputToolbar/animations.js.map +1 -0
- package/lib/InputToolbar/fragments.d.ts +13 -0
- package/lib/InputToolbar/fragments.d.ts.map +1 -0
- package/lib/InputToolbar/fragments.js +207 -0
- package/lib/InputToolbar/fragments.js.map +1 -0
- package/lib/InputToolbar/index.d.ts +7 -0
- package/lib/InputToolbar/index.d.ts.map +1 -0
- package/lib/InputToolbar/index.js +444 -0
- package/lib/InputToolbar/index.js.map +1 -0
- package/lib/InputToolbar/recordingOptions.d.ts +14 -0
- package/lib/InputToolbar/recordingOptions.d.ts.map +1 -0
- package/lib/InputToolbar/recordingOptions.js +38 -0
- package/lib/InputToolbar/recordingOptions.js.map +1 -0
- package/lib/InputToolbar/styles.d.ts +118 -0
- package/lib/InputToolbar/styles.d.ts.map +1 -0
- package/lib/InputToolbar/styles.js +139 -0
- package/lib/InputToolbar/styles.js.map +1 -0
- package/lib/InputToolbar/types.d.ts +77 -0
- package/lib/InputToolbar/types.d.ts.map +1 -0
- package/lib/InputToolbar/types.js +2 -0
- package/lib/InputToolbar/types.js.map +1 -0
- package/lib/InputToolbar/useActionsFragment.d.ts +6 -0
- package/lib/InputToolbar/useActionsFragment.d.ts.map +1 -0
- package/lib/InputToolbar/useActionsFragment.js +139 -0
- package/lib/InputToolbar/useActionsFragment.js.map +1 -0
- package/lib/InputToolbar/useComposerEditing.d.ts +11 -0
- package/lib/InputToolbar/useComposerEditing.d.ts.map +1 -0
- package/lib/InputToolbar/useComposerEditing.js +116 -0
- package/lib/InputToolbar/useComposerEditing.js.map +1 -0
- package/lib/InputToolbar/useEmojiButton.d.ts +14 -0
- package/lib/InputToolbar/useEmojiButton.d.ts.map +1 -0
- package/lib/InputToolbar/useEmojiButton.js +120 -0
- package/lib/InputToolbar/useEmojiButton.js.map +1 -0
- package/lib/InputToolbar/useKeyboardInset.d.ts +9 -0
- package/lib/InputToolbar/useKeyboardInset.d.ts.map +1 -0
- package/lib/InputToolbar/useKeyboardInset.js +25 -0
- package/lib/InputToolbar/useKeyboardInset.js.map +1 -0
- package/lib/InputToolbar/useRecordMode.d.ts +19 -0
- package/lib/InputToolbar/useRecordMode.d.ts.map +1 -0
- package/lib/InputToolbar/useRecordMode.js +124 -0
- package/lib/InputToolbar/useRecordMode.js.map +1 -0
- package/lib/InputToolbar/useRecordTake.d.ts +46 -0
- package/lib/InputToolbar/useRecordTake.d.ts.map +1 -0
- package/lib/InputToolbar/useRecordTake.js +315 -0
- package/lib/InputToolbar/useRecordTake.js.map +1 -0
- package/lib/InputToolbar/useReturnAnimations.d.ts +18 -0
- package/lib/InputToolbar/useReturnAnimations.d.ts.map +1 -0
- package/lib/InputToolbar/useReturnAnimations.js +30 -0
- package/lib/InputToolbar/useReturnAnimations.js.map +1 -0
- package/lib/InputToolbar/useRightControl.d.ts +40 -0
- package/lib/InputToolbar/useRightControl.d.ts.map +1 -0
- package/lib/InputToolbar/useRightControl.js +129 -0
- package/lib/InputToolbar/useRightControl.js.map +1 -0
- package/lib/LoadEarlierMessages.d.ts +2 -0
- package/lib/LoadEarlierMessages.d.ts.map +1 -1
- package/lib/LoadEarlierMessages.js +153 -40
- package/lib/LoadEarlierMessages.js.map +1 -1
- package/lib/Message/SwipeToReply.d.ts +23 -0
- package/lib/Message/SwipeToReply.d.ts.map +1 -0
- package/lib/Message/SwipeToReply.js +337 -0
- package/lib/Message/SwipeToReply.js.map +1 -0
- package/lib/Message/index.d.ts.map +1 -1
- package/lib/Message/index.js +415 -176
- package/lib/Message/index.js.map +1 -1
- package/lib/Message/styles.d.ts +2 -2
- package/lib/Message/styles.js +14 -14
- package/lib/Message/styles.js.map +1 -1
- package/lib/Message/types.d.ts +5 -0
- package/lib/Message/types.d.ts.map +1 -1
- package/lib/Message/types.js.map +1 -1
- package/lib/MessageAudio.d.ts.map +1 -1
- package/lib/MessageAudio.js +647 -107
- package/lib/MessageAudio.js.map +1 -1
- package/lib/MessageFile.d.ts +11 -0
- package/lib/MessageFile.d.ts.map +1 -0
- package/lib/MessageFile.js +315 -0
- package/lib/MessageFile.js.map +1 -0
- package/lib/MessageImage.d.ts +2 -0
- package/lib/MessageImage.d.ts.map +1 -1
- package/lib/MessageImage.js +430 -156
- package/lib/MessageImage.js.map +1 -1
- package/lib/MessageLocation.d.ts.map +1 -1
- package/lib/MessageLocation.js +180 -68
- package/lib/MessageLocation.js.map +1 -1
- package/lib/MessageText.d.ts +8 -1
- package/lib/MessageText.d.ts.map +1 -1
- package/lib/MessageText.js +261 -69
- package/lib/MessageText.js.map +1 -1
- package/lib/MessageVideo/ExpoVideoPlayer.d.ts +6 -0
- package/lib/MessageVideo/ExpoVideoPlayer.d.ts.map +1 -0
- package/lib/MessageVideo/ExpoVideoPlayer.js +68 -0
- package/lib/MessageVideo/ExpoVideoPlayer.js.map +1 -0
- package/lib/MessageVideo/MirroredVideo.d.ts +17 -0
- package/lib/MessageVideo/MirroredVideo.d.ts.map +1 -0
- package/lib/MessageVideo/MirroredVideo.js +223 -0
- package/lib/MessageVideo/MirroredVideo.js.map +1 -0
- package/lib/MessageVideo/RoundNotePlayer.d.ts +4 -0
- package/lib/MessageVideo/RoundNotePlayer.d.ts.map +1 -0
- package/lib/MessageVideo/RoundNotePlayer.js +560 -0
- package/lib/MessageVideo/RoundNotePlayer.js.map +1 -0
- package/lib/MessageVideo/RoundTranscription.d.ts +27 -0
- package/lib/MessageVideo/RoundTranscription.d.ts.map +1 -0
- package/lib/MessageVideo/RoundTranscription.js +151 -0
- package/lib/MessageVideo/RoundTranscription.js.map +1 -0
- package/lib/MessageVideo/VideoTransferOverlay.d.ts +11 -0
- package/lib/MessageVideo/VideoTransferOverlay.d.ts.map +1 -0
- package/lib/MessageVideo/VideoTransferOverlay.js +88 -0
- package/lib/MessageVideo/VideoTransferOverlay.js.map +1 -0
- package/lib/MessageVideo/constants.d.ts +13 -0
- package/lib/MessageVideo/constants.d.ts.map +1 -0
- package/lib/MessageVideo/constants.js +15 -0
- package/lib/MessageVideo/constants.js.map +1 -0
- package/lib/{MessageVideo.d.ts → MessageVideo/index.d.ts} +2 -2
- package/lib/MessageVideo/index.d.ts.map +1 -0
- package/lib/MessageVideo/index.js +92 -0
- package/lib/MessageVideo/index.js.map +1 -0
- package/lib/MessageVideo/liftedMedia.d.ts +13 -0
- package/lib/MessageVideo/liftedMedia.d.ts.map +1 -0
- package/lib/MessageVideo/liftedMedia.js +106 -0
- package/lib/MessageVideo/liftedMedia.js.map +1 -0
- package/lib/MessageVideo/styles.d.ts +71 -0
- package/lib/MessageVideo/styles.d.ts.map +1 -0
- package/lib/MessageVideo/styles.js +78 -0
- package/lib/MessageVideo/styles.js.map +1 -0
- package/lib/MessageVideo/types.d.ts +27 -0
- package/lib/MessageVideo/types.d.ts.map +1 -0
- package/lib/MessageVideo/types.js +2 -0
- package/lib/MessageVideo/types.js.map +1 -0
- package/lib/MessageVideo/useNoteGrow.d.ts +16 -0
- package/lib/MessageVideo/useNoteGrow.d.ts.map +1 -0
- package/lib/MessageVideo/useNoteGrow.js +122 -0
- package/lib/MessageVideo/useNoteGrow.js.map +1 -0
- package/lib/MessageVideo/useNotePlayer.d.ts +14 -0
- package/lib/MessageVideo/useNotePlayer.d.ts.map +1 -0
- package/lib/MessageVideo/useNotePlayer.js +142 -0
- package/lib/MessageVideo/useNotePlayer.js.map +1 -0
- package/lib/MessageVideo/useRingSeek.d.ts +16 -0
- package/lib/MessageVideo/useRingSeek.d.ts.map +1 -0
- package/lib/MessageVideo/useRingSeek.js +157 -0
- package/lib/MessageVideo/useRingSeek.js.map +1 -0
- package/lib/MessageVideo/useRoundNotePlayback.d.ts +46 -0
- package/lib/MessageVideo/useRoundNotePlayback.d.ts.map +1 -0
- package/lib/MessageVideo/useRoundNotePlayback.js +508 -0
- package/lib/MessageVideo/useRoundNotePlayback.js.map +1 -0
- package/lib/MessageVideo/useSendFlightReveal.d.ts +9 -0
- package/lib/MessageVideo/useSendFlightReveal.d.ts.map +1 -0
- package/lib/MessageVideo/useSendFlightReveal.js +85 -0
- package/lib/MessageVideo/useSendFlightReveal.js.map +1 -0
- package/lib/MessageVideo/videoPlayers.d.ts +8 -0
- package/lib/MessageVideo/videoPlayers.d.ts.map +1 -0
- package/lib/MessageVideo/videoPlayers.js +33 -0
- package/lib/MessageVideo/videoPlayers.js.map +1 -0
- package/lib/MessagesContainer/components/DayAnimated/debug.js +38 -24
- package/lib/MessagesContainer/components/DayAnimated/debug.js.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/index.d.ts +1 -1
- package/lib/MessagesContainer/components/DayAnimated/index.d.ts.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/index.js +244 -112
- package/lib/MessagesContainer/components/DayAnimated/index.js.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/styles.d.ts +3 -3
- package/lib/MessagesContainer/components/DayAnimated/styles.js +8 -8
- package/lib/MessagesContainer/components/DayAnimated/styles.js.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/types.d.ts +4 -2
- package/lib/MessagesContainer/components/DayAnimated/types.d.ts.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/types.js.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/useScrollGatedOpacity.d.ts.map +1 -1
- package/lib/MessagesContainer/components/DayAnimated/useScrollGatedOpacity.js +34 -25
- package/lib/MessagesContainer/components/DayAnimated/useScrollGatedOpacity.js.map +1 -1
- package/lib/MessagesContainer/components/Item/index.d.ts +3 -4
- package/lib/MessagesContainer/components/Item/index.d.ts.map +1 -1
- package/lib/MessagesContainer/components/Item/index.js +290 -99
- package/lib/MessagesContainer/components/Item/index.js.map +1 -1
- package/lib/MessagesContainer/components/Item/types.d.ts +5 -0
- package/lib/MessagesContainer/components/Item/types.d.ts.map +1 -1
- package/lib/MessagesContainer/components/Item/types.js.map +1 -1
- package/lib/MessagesContainer/components/PageDownCounter.d.ts +14 -0
- package/lib/MessagesContainer/components/PageDownCounter.d.ts.map +1 -0
- package/lib/MessagesContainer/components/PageDownCounter.js +209 -0
- package/lib/MessagesContainer/components/PageDownCounter.js.map +1 -0
- package/lib/MessagesContainer/components/ScrollToBottomButton.d.ts +21 -0
- package/lib/MessagesContainer/components/ScrollToBottomButton.d.ts.map +1 -0
- package/lib/MessagesContainer/components/ScrollToBottomButton.js +195 -0
- package/lib/MessagesContainer/components/ScrollToBottomButton.js.map +1 -0
- package/lib/MessagesContainer/components/dayLayout.d.ts +2 -2
- package/lib/MessagesContainer/components/dayLayout.d.ts.map +1 -1
- package/lib/MessagesContainer/components/dayLayout.js +18 -13
- package/lib/MessagesContainer/components/dayLayout.js.map +1 -1
- package/lib/MessagesContainer/index.d.ts.map +1 -1
- package/lib/MessagesContainer/index.js +361 -420
- package/lib/MessagesContainer/index.js.map +1 -1
- package/lib/MessagesContainer/listState.d.ts +18 -0
- package/lib/MessagesContainer/listState.d.ts.map +1 -0
- package/lib/MessagesContainer/listState.js +25 -0
- package/lib/MessagesContainer/listState.js.map +1 -0
- package/lib/MessagesContainer/listTransitions.d.ts +10 -0
- package/lib/MessagesContainer/listTransitions.d.ts.map +1 -0
- package/lib/MessagesContainer/listTransitions.js +12 -0
- package/lib/MessagesContainer/listTransitions.js.map +1 -0
- package/lib/MessagesContainer/pageDownReturn.d.ts +11 -0
- package/lib/MessagesContainer/pageDownReturn.d.ts.map +1 -0
- package/lib/MessagesContainer/pageDownReturn.js +9 -0
- package/lib/MessagesContainer/pageDownReturn.js.map +1 -0
- package/lib/MessagesContainer/rowConfig.d.ts +39 -0
- package/lib/MessagesContainer/rowConfig.d.ts.map +1 -0
- package/lib/MessagesContainer/rowConfig.js +161 -0
- package/lib/MessagesContainer/rowConfig.js.map +1 -0
- package/lib/MessagesContainer/rowStore.d.ts +37 -0
- package/lib/MessagesContainer/rowStore.d.ts.map +1 -0
- package/lib/MessagesContainer/rowStore.js +140 -0
- package/lib/MessagesContainer/rowStore.js.map +1 -0
- package/lib/MessagesContainer/styles.d.ts +37 -31
- package/lib/MessagesContainer/styles.d.ts.map +1 -1
- package/lib/MessagesContainer/styles.js +75 -54
- package/lib/MessagesContainer/styles.js.map +1 -1
- package/lib/MessagesContainer/types.d.ts +33 -30
- package/lib/MessagesContainer/types.d.ts.map +1 -1
- package/lib/MessagesContainer/types.js +1 -9
- package/lib/MessagesContainer/types.js.map +1 -1
- package/lib/MessagesContainer/useCellLayouts.d.ts +17 -0
- package/lib/MessagesContainer/useCellLayouts.d.ts.map +1 -0
- package/lib/MessagesContainer/useCellLayouts.js +133 -0
- package/lib/MessagesContainer/useCellLayouts.js.map +1 -0
- package/lib/MessagesContainer/useDaysPositions.d.ts +18 -0
- package/lib/MessagesContainer/useDaysPositions.d.ts.map +1 -0
- package/lib/MessagesContainer/useDaysPositions.js +109 -0
- package/lib/MessagesContainer/useDaysPositions.js.map +1 -0
- package/lib/MessagesContainer/useListChrome.d.ts +14 -0
- package/lib/MessagesContainer/useListChrome.d.ts.map +1 -0
- package/lib/MessagesContainer/useListChrome.js +176 -0
- package/lib/MessagesContainer/useListChrome.js.map +1 -0
- package/lib/MessagesContainer/useListMetrics.d.ts +32 -0
- package/lib/MessagesContainer/useListMetrics.d.ts.map +1 -0
- package/lib/MessagesContainer/useListMetrics.js +176 -0
- package/lib/MessagesContainer/useListMetrics.js.map +1 -0
- package/lib/MessagesContainer/useMessageRows.d.ts +46 -0
- package/lib/MessagesContainer/useMessageRows.d.ts.map +1 -0
- package/lib/MessagesContainer/useMessageRows.js +228 -0
- package/lib/MessagesContainer/useMessageRows.js.map +1 -0
- package/lib/MessagesContainer/usePageDownUnread.d.ts +27 -0
- package/lib/MessagesContainer/usePageDownUnread.d.ts.map +1 -0
- package/lib/MessagesContainer/usePageDownUnread.js +152 -0
- package/lib/MessagesContainer/usePageDownUnread.js.map +1 -0
- package/lib/MessagesContainer/useScrollActivity.d.ts +13 -0
- package/lib/MessagesContainer/useScrollActivity.d.ts.map +1 -0
- package/lib/MessagesContainer/useScrollActivity.js +84 -0
- package/lib/MessagesContainer/useScrollActivity.js.map +1 -0
- package/lib/MessagesContainer/useScrollToBottom.d.ts +26 -0
- package/lib/MessagesContainer/useScrollToBottom.d.ts.map +1 -0
- package/lib/MessagesContainer/useScrollToBottom.js +164 -0
- package/lib/MessagesContainer/useScrollToBottom.js.map +1 -0
- package/lib/MessagesContainer/useTapToClosePanels.d.ts +7 -0
- package/lib/MessagesContainer/useTapToClosePanels.d.ts.map +1 -0
- package/lib/MessagesContainer/useTapToClosePanels.js +55 -0
- package/lib/MessagesContainer/useTapToClosePanels.js.map +1 -0
- package/lib/MessagesContainer/viewability.d.ts +9 -0
- package/lib/MessagesContainer/viewability.d.ts.map +1 -0
- package/lib/MessagesContainer/viewability.js +110 -0
- package/lib/MessagesContainer/viewability.js.map +1 -0
- package/lib/Models.d.ts +188 -3
- package/lib/Models.d.ts.map +1 -1
- package/lib/Models.js.map +1 -1
- package/lib/QuickReplies.js +234 -101
- package/lib/QuickReplies.js.map +1 -1
- package/lib/Reactions/MessageReactions.d.ts +5 -0
- package/lib/Reactions/MessageReactions.d.ts.map +1 -1
- package/lib/Reactions/MessageReactions.js +359 -80
- package/lib/Reactions/MessageReactions.js.map +1 -1
- package/lib/Reactions/ReactionPicker.d.ts +5 -3
- package/lib/Reactions/ReactionPicker.d.ts.map +1 -1
- package/lib/Reactions/ReactionPicker.js +68 -82
- package/lib/Reactions/ReactionPicker.js.map +1 -1
- package/lib/Reactions/index.js +1 -0
- package/lib/Reactions/index.js.map +1 -1
- package/lib/Reactions/types.d.ts +49 -5
- package/lib/Reactions/types.d.ts.map +1 -1
- package/lib/Reactions/types.js.map +1 -1
- package/lib/Reply/index.js.map +1 -1
- package/lib/Reply/types.d.ts +19 -3
- package/lib/Reply/types.d.ts.map +1 -1
- package/lib/Reply/types.js.map +1 -1
- package/lib/Send.d.ts +2 -2
- package/lib/Send.d.ts.map +1 -1
- package/lib/Send.js +218 -47
- package/lib/Send.js.map +1 -1
- package/lib/SystemMessage.d.ts.map +1 -1
- package/lib/SystemMessage.js +106 -37
- package/lib/SystemMessage.js.map +1 -1
- package/lib/Theme.d.ts +320 -23
- package/lib/Theme.d.ts.map +1 -1
- package/lib/Theme.js +548 -119
- package/lib/Theme.js.map +1 -1
- package/lib/Time.d.ts +7 -0
- package/lib/Time.d.ts.map +1 -1
- package/lib/Time.js +122 -30
- package/lib/Time.js.map +1 -1
- package/lib/TypingIndicator/index.d.ts +9 -1
- package/lib/TypingIndicator/index.d.ts.map +1 -1
- package/lib/TypingIndicator/index.js +318 -94
- package/lib/TypingIndicator/index.js.map +1 -1
- package/lib/TypingIndicator/styles.d.ts +6 -2
- package/lib/TypingIndicator/styles.d.ts.map +1 -1
- package/lib/TypingIndicator/styles.js +22 -18
- package/lib/TypingIndicator/styles.js.map +1 -1
- package/lib/TypingIndicator/types.js.map +1 -1
- package/lib/attachments/AttachmentButton.d.ts +18 -0
- package/lib/attachments/AttachmentButton.d.ts.map +1 -0
- package/lib/attachments/AttachmentButton.js +110 -0
- package/lib/attachments/AttachmentButton.js.map +1 -0
- package/lib/attachments/AttachmentMenu/CaptionBar.d.ts +15 -0
- package/lib/attachments/AttachmentMenu/CaptionBar.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/CaptionBar.js +165 -0
- package/lib/attachments/AttachmentMenu/CaptionBar.js.map +1 -0
- package/lib/attachments/AttachmentMenu/GalleryCell.d.ts +14 -0
- package/lib/attachments/AttachmentMenu/GalleryCell.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/GalleryCell.js +267 -0
- package/lib/attachments/AttachmentMenu/GalleryCell.js.map +1 -0
- package/lib/attachments/AttachmentMenu/GalleryGrid.d.ts +18 -0
- package/lib/attachments/AttachmentMenu/GalleryGrid.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/GalleryGrid.js +184 -0
- package/lib/attachments/AttachmentMenu/GalleryGrid.js.map +1 -0
- package/lib/attachments/AttachmentMenu/TabBar.d.ts +14 -0
- package/lib/attachments/AttachmentMenu/TabBar.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/TabBar.js +127 -0
- package/lib/attachments/AttachmentMenu/TabBar.js.map +1 -0
- package/lib/attachments/AttachmentMenu/TabButton.d.ts +15 -0
- package/lib/attachments/AttachmentMenu/TabButton.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/TabButton.js +219 -0
- package/lib/attachments/AttachmentMenu/TabButton.js.map +1 -0
- package/lib/attachments/AttachmentMenu/TabPanel.d.ts +17 -0
- package/lib/attachments/AttachmentMenu/TabPanel.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/TabPanel.js +170 -0
- package/lib/attachments/AttachmentMenu/TabPanel.js.map +1 -0
- package/lib/attachments/AttachmentMenu/constants.d.ts +54 -0
- package/lib/attachments/AttachmentMenu/constants.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/constants.js +79 -0
- package/lib/attachments/AttachmentMenu/constants.js.map +1 -0
- package/lib/attachments/AttachmentMenu/index.d.ts +16 -0
- package/lib/attachments/AttachmentMenu/index.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/index.js +498 -0
- package/lib/attachments/AttachmentMenu/index.js.map +1 -0
- package/lib/attachments/AttachmentMenu/styles.d.ts +259 -0
- package/lib/attachments/AttachmentMenu/styles.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/styles.js +262 -0
- package/lib/attachments/AttachmentMenu/styles.js.map +1 -0
- package/lib/attachments/AttachmentMenu/useSheetPresence.d.ts +14 -0
- package/lib/attachments/AttachmentMenu/useSheetPresence.d.ts.map +1 -0
- package/lib/attachments/AttachmentMenu/useSheetPresence.js +74 -0
- package/lib/attachments/AttachmentMenu/useSheetPresence.js.map +1 -0
- package/lib/attachments/buildMessages.d.ts +36 -0
- package/lib/attachments/buildMessages.d.ts.map +1 -0
- package/lib/attachments/buildMessages.js +192 -0
- package/lib/attachments/buildMessages.js.map +1 -0
- package/lib/attachments/gallery.d.ts +28 -0
- package/lib/attachments/gallery.d.ts.map +1 -0
- package/lib/attachments/gallery.js +245 -0
- package/lib/attachments/gallery.js.map +1 -0
- package/lib/attachments/types.d.ts +69 -0
- package/lib/attachments/types.d.ts.map +1 -0
- package/lib/attachments/types.js +2 -0
- package/lib/attachments/types.js.map +1 -0
- package/lib/colorUtils.d.ts +24 -0
- package/lib/colorUtils.d.ts.map +1 -0
- package/lib/colorUtils.js +71 -0
- package/lib/colorUtils.js.map +1 -0
- package/lib/components/AttachmentSheet.d.ts +1 -1
- package/lib/components/AttachmentSheet.d.ts.map +1 -1
- package/lib/components/AttachmentSheet.js +515 -155
- package/lib/components/AttachmentSheet.js.map +1 -1
- package/lib/components/BasicMarkdown.d.ts +7 -1
- package/lib/components/BasicMarkdown.d.ts.map +1 -1
- package/lib/components/BasicMarkdown.js +234 -184
- package/lib/components/BasicMarkdown.js.map +1 -1
- package/lib/components/BubbleBackground.d.ts +55 -0
- package/lib/components/BubbleBackground.d.ts.map +1 -0
- package/lib/components/BubbleBackground.js +513 -0
- package/lib/components/BubbleBackground.js.map +1 -0
- package/lib/components/ChatEmpty.d.ts +18 -0
- package/lib/components/ChatEmpty.d.ts.map +1 -0
- package/lib/components/ChatEmpty.js +125 -0
- package/lib/components/ChatEmpty.js.map +1 -0
- package/lib/components/ChatLoadingOverlay.d.ts +10 -0
- package/lib/components/ChatLoadingOverlay.d.ts.map +1 -0
- package/lib/components/ChatLoadingOverlay.js +89 -0
- package/lib/components/ChatLoadingOverlay.js.map +1 -0
- package/lib/components/ChatOverlay.d.ts +9 -0
- package/lib/components/ChatOverlay.d.ts.map +1 -0
- package/lib/components/ChatOverlay.js +60 -0
- package/lib/components/ChatOverlay.js.map +1 -0
- package/lib/components/ChatWallpaper.d.ts +32 -0
- package/lib/components/ChatWallpaper.d.ts.map +1 -0
- package/lib/components/ChatWallpaper.js +277 -0
- package/lib/components/ChatWallpaper.js.map +1 -0
- package/lib/components/ContextMenu/MenuCard.d.ts +21 -0
- package/lib/components/ContextMenu/MenuCard.d.ts.map +1 -0
- package/lib/components/ContextMenu/MenuCard.js +265 -0
- package/lib/components/ContextMenu/MenuCard.js.map +1 -0
- package/lib/components/ContextMenu/ReactionButton.d.ts +15 -0
- package/lib/components/ContextMenu/ReactionButton.d.ts.map +1 -0
- package/lib/components/ContextMenu/ReactionButton.js +116 -0
- package/lib/components/ContextMenu/ReactionButton.js.map +1 -0
- package/lib/components/ContextMenu/ReactionFlight.d.ts +14 -0
- package/lib/components/ContextMenu/ReactionFlight.d.ts.map +1 -0
- package/lib/components/ContextMenu/ReactionFlight.js +111 -0
- package/lib/components/ContextMenu/ReactionFlight.js.map +1 -0
- package/lib/components/ContextMenu/ReactionsBar.d.ts +35 -0
- package/lib/components/ContextMenu/ReactionsBar.d.ts.map +1 -0
- package/lib/components/ContextMenu/ReactionsBar.js +354 -0
- package/lib/components/ContextMenu/ReactionsBar.js.map +1 -0
- package/lib/components/ContextMenu/constants.d.ts +68 -0
- package/lib/components/ContextMenu/constants.d.ts.map +1 -0
- package/lib/components/ContextMenu/constants.js +105 -0
- package/lib/components/ContextMenu/constants.js.map +1 -0
- package/lib/components/ContextMenu/index.d.ts +12 -0
- package/lib/components/ContextMenu/index.d.ts.map +1 -0
- package/lib/components/ContextMenu/index.js +476 -0
- package/lib/components/ContextMenu/index.js.map +1 -0
- package/lib/components/ContextMenu/placement.d.ts +50 -0
- package/lib/components/ContextMenu/placement.d.ts.map +1 -0
- package/lib/components/ContextMenu/placement.js +117 -0
- package/lib/components/ContextMenu/placement.js.map +1 -0
- package/lib/components/ContextMenu/styles.d.ts +199 -0
- package/lib/components/ContextMenu/styles.d.ts.map +1 -0
- package/lib/components/ContextMenu/styles.js +169 -0
- package/lib/components/ContextMenu/styles.js.map +1 -0
- package/lib/components/ContextMenu/types.d.ts +62 -0
- package/lib/components/ContextMenu/types.d.ts.map +1 -0
- package/lib/components/ContextMenu/types.js +2 -0
- package/lib/components/ContextMenu/types.js.map +1 -0
- package/lib/components/ContextMenu/useExpandPanel.d.ts +11 -0
- package/lib/components/ContextMenu/useExpandPanel.d.ts.map +1 -0
- package/lib/components/ContextMenu/useExpandPanel.js +81 -0
- package/lib/components/ContextMenu/useExpandPanel.js.map +1 -0
- package/lib/components/ContextMenu/useMenuPresence.d.ts +17 -0
- package/lib/components/ContextMenu/useMenuPresence.d.ts.map +1 -0
- package/lib/components/ContextMenu/useMenuPresence.js +125 -0
- package/lib/components/ContextMenu/useMenuPresence.js.map +1 -0
- package/lib/components/FloatingRoundNote.d.ts +13 -0
- package/lib/components/FloatingRoundNote.d.ts.map +1 -0
- package/lib/components/FloatingRoundNote.js +541 -0
- package/lib/components/FloatingRoundNote.js.map +1 -0
- package/lib/components/GlassSurface.d.ts +16 -0
- package/lib/components/GlassSurface.d.ts.map +1 -0
- package/lib/components/GlassSurface.js +114 -0
- package/lib/components/GlassSurface.js.map +1 -0
- package/lib/components/Icon.js +57 -8
- package/lib/components/Icon.js.map +1 -1
- package/lib/components/LinkPreviewCard.d.ts +36 -0
- package/lib/components/LinkPreviewCard.d.ts.map +1 -0
- package/lib/components/LinkPreviewCard.js +416 -0
- package/lib/components/LinkPreviewCard.js.map +1 -0
- package/lib/components/LucideIcon.d.ts.map +1 -1
- package/lib/components/LucideIcon.js +103 -106
- package/lib/components/LucideIcon.js.map +1 -1
- package/lib/components/MarkdownMessageText.d.ts +17 -2
- package/lib/components/MarkdownMessageText.d.ts.map +1 -1
- package/lib/components/MarkdownMessageText.js +270 -22
- package/lib/components/MarkdownMessageText.js.map +1 -1
- package/lib/components/MediaCard.d.ts.map +1 -1
- package/lib/components/MediaCard.js +223 -85
- package/lib/components/MediaCard.js.map +1 -1
- package/lib/components/MediaControls.js +1094 -450
- package/lib/components/MediaControls.js.map +1 -1
- package/lib/components/MediaLoader.d.ts +21 -0
- package/lib/components/MediaLoader.d.ts.map +1 -0
- package/lib/components/MediaLoader.js +61 -0
- package/lib/components/MediaLoader.js.map +1 -0
- package/lib/components/MessageReply.d.ts +2 -2
- package/lib/components/MessageReply.d.ts.map +1 -1
- package/lib/components/MessageReply.js +266 -83
- package/lib/components/MessageReply.js.map +1 -1
- package/lib/components/MessageStatus.d.ts +23 -0
- package/lib/components/MessageStatus.d.ts.map +1 -0
- package/lib/components/MessageStatus.js +499 -0
- package/lib/components/MessageStatus.js.map +1 -0
- package/lib/components/NoteIndicators.d.ts +25 -0
- package/lib/components/NoteIndicators.d.ts.map +1 -0
- package/lib/components/NoteIndicators.js +206 -0
- package/lib/components/NoteIndicators.js.map +1 -0
- package/lib/components/NowPlayingBar.d.ts +15 -0
- package/lib/components/NowPlayingBar.d.ts.map +1 -0
- package/lib/components/NowPlayingBar.js +261 -0
- package/lib/components/NowPlayingBar.js.map +1 -0
- package/lib/components/PlayPauseIcon.d.ts +13 -0
- package/lib/components/PlayPauseIcon.d.ts.map +1 -0
- package/lib/components/PlayPauseIcon.js +187 -0
- package/lib/components/PlayPauseIcon.js.map +1 -0
- package/lib/components/PlaybackSpeedPill.d.ts +11 -0
- package/lib/components/PlaybackSpeedPill.d.ts.map +1 -0
- package/lib/components/PlaybackSpeedPill.js +350 -0
- package/lib/components/PlaybackSpeedPill.js.map +1 -0
- package/lib/components/RadialProgress.d.ts +70 -0
- package/lib/components/RadialProgress.d.ts.map +1 -0
- package/lib/components/RadialProgress.js +864 -0
- package/lib/components/RadialProgress.js.map +1 -0
- package/lib/components/RecordButton/LockPill.d.ts +27 -0
- package/lib/components/RecordButton/LockPill.d.ts.map +1 -0
- package/lib/components/RecordButton/LockPill.js +182 -0
- package/lib/components/RecordButton/LockPill.js.map +1 -0
- package/lib/components/RecordButton/ModeButton.d.ts +18 -0
- package/lib/components/RecordButton/ModeButton.d.ts.map +1 -0
- package/lib/components/RecordButton/ModeButton.js +154 -0
- package/lib/components/RecordButton/ModeButton.js.map +1 -0
- package/lib/components/RecordButton/ResumeButton.d.ts +20 -0
- package/lib/components/RecordButton/ResumeButton.d.ts.map +1 -0
- package/lib/components/RecordButton/ResumeButton.js +63 -0
- package/lib/components/RecordButton/ResumeButton.js.map +1 -0
- package/lib/components/RecordButton/Tooltips.d.ts +20 -0
- package/lib/components/RecordButton/Tooltips.d.ts.map +1 -0
- package/lib/components/RecordButton/Tooltips.js +191 -0
- package/lib/components/RecordButton/Tooltips.js.map +1 -0
- package/lib/components/RecordButton/ViewOnceButton.d.ts +16 -0
- package/lib/components/RecordButton/ViewOnceButton.d.ts.map +1 -0
- package/lib/components/RecordButton/ViewOnceButton.js +96 -0
- package/lib/components/RecordButton/ViewOnceButton.js.map +1 -0
- package/lib/components/RecordButton/constants.d.ts +52 -0
- package/lib/components/RecordButton/constants.d.ts.map +1 -0
- package/lib/components/RecordButton/constants.js +58 -0
- package/lib/components/RecordButton/constants.js.map +1 -0
- package/lib/components/RecordButton/index.d.ts +14 -0
- package/lib/components/RecordButton/index.d.ts.map +1 -0
- package/lib/components/RecordButton/index.js +382 -0
- package/lib/components/RecordButton/index.js.map +1 -0
- package/lib/components/RecordButton/styles.d.ts +155 -0
- package/lib/components/RecordButton/styles.d.ts.map +1 -0
- package/lib/components/RecordButton/styles.js +161 -0
- package/lib/components/RecordButton/styles.js.map +1 -0
- package/lib/components/RecordButton/types.d.ts +63 -0
- package/lib/components/RecordButton/types.d.ts.map +1 -0
- package/lib/components/RecordButton/types.js +2 -0
- package/lib/components/RecordButton/types.js.map +1 -0
- package/lib/components/RecordButton/useRecordGesture.d.ts +28 -0
- package/lib/components/RecordButton/useRecordGesture.d.ts.map +1 -0
- package/lib/components/RecordButton/useRecordGesture.js +263 -0
- package/lib/components/RecordButton/useRecordGesture.js.map +1 -0
- package/lib/components/RecordButton/useRecordHints.d.ts +27 -0
- package/lib/components/RecordButton/useRecordHints.d.ts.map +1 -0
- package/lib/components/RecordButton/useRecordHints.js +210 -0
- package/lib/components/RecordButton/useRecordHints.js.map +1 -0
- package/lib/components/RecordButton/useRecordSlideDistance.d.ts +3 -0
- package/lib/components/RecordButton/useRecordSlideDistance.d.ts.map +1 -0
- package/lib/components/RecordButton/useRecordSlideDistance.js +15 -0
- package/lib/components/RecordButton/useRecordSlideDistance.js.map +1 -0
- package/lib/components/RecordButton/useRecordTake.d.ts +41 -0
- package/lib/components/RecordButton/useRecordTake.d.ts.map +1 -0
- package/lib/components/RecordButton/useRecordTake.js +349 -0
- package/lib/components/RecordButton/useRecordTake.js.map +1 -0
- package/lib/components/RecordButton/useSendFlight.d.ts +25 -0
- package/lib/components/RecordButton/useSendFlight.d.ts.map +1 -0
- package/lib/components/RecordButton/useSendFlight.js +162 -0
- package/lib/components/RecordButton/useSendFlight.js.map +1 -0
- package/lib/components/RecordCircle.d.ts +92 -0
- package/lib/components/RecordCircle.d.ts.map +1 -0
- package/lib/components/RecordCircle.js +629 -0
- package/lib/components/RecordCircle.js.map +1 -0
- package/lib/components/RecordingBar.d.ts +24 -0
- package/lib/components/RecordingBar.d.ts.map +1 -0
- package/lib/components/RecordingBar.js +766 -0
- package/lib/components/RecordingBar.js.map +1 -0
- package/lib/components/ReplyPreview.js +318 -135
- package/lib/components/ReplyPreview.js.map +1 -1
- package/lib/components/SelectionBar.d.ts +17 -0
- package/lib/components/SelectionBar.d.ts.map +1 -0
- package/lib/components/SelectionBar.js +214 -0
- package/lib/components/SelectionBar.js.map +1 -0
- package/lib/components/SelectionCheckbox.d.ts +12 -0
- package/lib/components/SelectionCheckbox.d.ts.map +1 -0
- package/lib/components/SelectionCheckbox.js +104 -0
- package/lib/components/SelectionCheckbox.js.map +1 -0
- package/lib/components/SendIcon.js +60 -26
- package/lib/components/SendIcon.js.map +1 -1
- package/lib/components/ServiceSpinner.d.ts +17 -0
- package/lib/components/ServiceSpinner.d.ts.map +1 -0
- package/lib/components/ServiceSpinner.js +77 -0
- package/lib/components/ServiceSpinner.js.map +1 -0
- package/lib/components/Spinner.d.ts +18 -0
- package/lib/components/Spinner.d.ts.map +1 -0
- package/lib/components/Spinner.js +169 -0
- package/lib/components/Spinner.js.map +1 -0
- package/lib/components/StreamingCursor.js +54 -9
- package/lib/components/StreamingCursor.js.map +1 -1
- package/lib/components/Ticks.d.ts +6 -5
- package/lib/components/Ticks.d.ts.map +1 -1
- package/lib/components/Ticks.js +272 -82
- package/lib/components/Ticks.js.map +1 -1
- package/lib/components/TouchableOpacity.d.ts.map +1 -1
- package/lib/components/TouchableOpacity.js +154 -48
- package/lib/components/TouchableOpacity.js.map +1 -1
- package/lib/components/TranscribeButton.d.ts +45 -0
- package/lib/components/TranscribeButton.d.ts.map +1 -0
- package/lib/components/TranscribeButton.js +549 -0
- package/lib/components/TranscribeButton.js.map +1 -0
- package/lib/components/TypingStatus.d.ts +29 -0
- package/lib/components/TypingStatus.d.ts.map +1 -0
- package/lib/components/TypingStatus.js +446 -0
- package/lib/components/TypingStatus.js.map +1 -0
- package/lib/components/UnreadSeparator.d.ts +8 -0
- package/lib/components/UnreadSeparator.d.ts.map +1 -0
- package/lib/components/UnreadSeparator.js +101 -0
- package/lib/components/UnreadSeparator.js.map +1 -0
- package/lib/components/VideoNoteCapture/ProgressRing.d.ts +16 -0
- package/lib/components/VideoNoteCapture/ProgressRing.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/ProgressRing.js +75 -0
- package/lib/components/VideoNoteCapture/ProgressRing.js.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNoteCaptureView.d.ts +31 -0
- package/lib/components/VideoNoteCapture/VideoNoteCaptureView.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNoteCaptureView.js +500 -0
- package/lib/components/VideoNoteCapture/VideoNoteCaptureView.js.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNotePreviewView.d.ts +12 -0
- package/lib/components/VideoNoteCapture/VideoNotePreviewView.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNotePreviewView.js +105 -0
- package/lib/components/VideoNoteCapture/VideoNotePreviewView.js.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNoteStage.d.ts +12 -0
- package/lib/components/VideoNoteCapture/VideoNoteStage.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/VideoNoteStage.js +95 -0
- package/lib/components/VideoNoteCapture/VideoNoteStage.js.map +1 -0
- package/lib/components/VideoNoteCapture/constants.d.ts +50 -0
- package/lib/components/VideoNoteCapture/constants.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/constants.js +53 -0
- package/lib/components/VideoNoteCapture/constants.js.map +1 -0
- package/lib/components/VideoNoteCapture/index.d.ts +3 -0
- package/lib/components/VideoNoteCapture/index.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/index.js +2 -0
- package/lib/components/VideoNoteCapture/index.js.map +1 -0
- package/lib/components/VideoNoteCapture/optional.d.ts +6 -0
- package/lib/components/VideoNoteCapture/optional.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/optional.js +15 -0
- package/lib/components/VideoNoteCapture/optional.js.map +1 -0
- package/lib/components/VideoNoteCapture/sessionState.d.ts +10 -0
- package/lib/components/VideoNoteCapture/sessionState.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/sessionState.js +19 -0
- package/lib/components/VideoNoteCapture/sessionState.js.map +1 -0
- package/lib/components/VideoNoteCapture/styles.d.ts +84 -0
- package/lib/components/VideoNoteCapture/styles.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/styles.js +86 -0
- package/lib/components/VideoNoteCapture/styles.js.map +1 -0
- package/lib/components/VideoNoteCapture/types.d.ts +54 -0
- package/lib/components/VideoNoteCapture/types.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/types.js +2 -0
- package/lib/components/VideoNoteCapture/types.js.map +1 -0
- package/lib/components/VideoNoteCapture/useRoundAnimation.d.ts +47 -0
- package/lib/components/VideoNoteCapture/useRoundAnimation.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/useRoundAnimation.js +216 -0
- package/lib/components/VideoNoteCapture/useRoundAnimation.js.map +1 -0
- package/lib/components/VideoNoteCapture/useRoundLayout.d.ts +14 -0
- package/lib/components/VideoNoteCapture/useRoundLayout.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/useRoundLayout.js +61 -0
- package/lib/components/VideoNoteCapture/useRoundLayout.js.map +1 -0
- package/lib/components/VideoNoteCapture/useVideoNoteSession.d.ts +25 -0
- package/lib/components/VideoNoteCapture/useVideoNoteSession.d.ts.map +1 -0
- package/lib/components/VideoNoteCapture/useVideoNoteSession.js +611 -0
- package/lib/components/VideoNoteCapture/useVideoNoteSession.js.map +1 -0
- package/lib/components/VideoNoteOverlay.d.ts +42 -11
- package/lib/components/VideoNoteOverlay.d.ts.map +1 -1
- package/lib/components/VideoNoteOverlay.js +722 -135
- package/lib/components/VideoNoteOverlay.js.map +1 -1
- package/lib/components/VideoNoteRecorder/LiveVideoNote.d.ts +6 -0
- package/lib/components/VideoNoteRecorder/LiveVideoNote.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/LiveVideoNote.js +205 -0
- package/lib/components/VideoNoteRecorder/LiveVideoNote.js.map +1 -0
- package/lib/components/VideoNoteRecorder/RecorderChrome.d.ts +35 -0
- package/lib/components/VideoNoteRecorder/RecorderChrome.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/RecorderChrome.js +350 -0
- package/lib/components/VideoNoteRecorder/RecorderChrome.js.map +1 -0
- package/lib/components/VideoNoteRecorder/UnavailableVideoNote.d.ts +10 -0
- package/lib/components/VideoNoteRecorder/UnavailableVideoNote.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/UnavailableVideoNote.js +52 -0
- package/lib/components/VideoNoteRecorder/UnavailableVideoNote.js.map +1 -0
- package/lib/components/VideoNoteRecorder/constants.d.ts +16 -0
- package/lib/components/VideoNoteRecorder/constants.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/constants.js +30 -0
- package/lib/components/VideoNoteRecorder/constants.js.map +1 -0
- package/lib/components/{VideoNoteRecorder.d.ts → VideoNoteRecorder/index.d.ts} +5 -10
- package/lib/components/VideoNoteRecorder/index.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/index.js +26 -0
- package/lib/components/VideoNoteRecorder/index.js.map +1 -0
- package/lib/components/VideoNoteRecorder/styles.d.ts +159 -0
- package/lib/components/VideoNoteRecorder/styles.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/styles.js +170 -0
- package/lib/components/VideoNoteRecorder/styles.js.map +1 -0
- package/lib/components/VideoNoteRecorder/types.d.ts +7 -0
- package/lib/components/VideoNoteRecorder/types.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/types.js +2 -0
- package/lib/components/VideoNoteRecorder/types.js.map +1 -0
- package/lib/components/VideoNoteRecorder/useRecordingTimer.d.ts +10 -0
- package/lib/components/VideoNoteRecorder/useRecordingTimer.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/useRecordingTimer.js +134 -0
- package/lib/components/VideoNoteRecorder/useRecordingTimer.js.map +1 -0
- package/lib/components/VideoNoteRecorder/useVideoNoteRecording.d.ts +28 -0
- package/lib/components/VideoNoteRecorder/useVideoNoteRecording.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/useVideoNoteRecording.js +287 -0
- package/lib/components/VideoNoteRecorder/useVideoNoteRecording.js.map +1 -0
- package/lib/components/VideoNoteRecorder/visionCameraHooks.d.ts +6 -0
- package/lib/components/VideoNoteRecorder/visionCameraHooks.d.ts.map +1 -0
- package/lib/components/VideoNoteRecorder/visionCameraHooks.js +11 -0
- package/lib/components/VideoNoteRecorder/visionCameraHooks.js.map +1 -0
- package/lib/components/VideoRecordButton.d.ts +1 -1
- package/lib/components/VideoRecordButton.d.ts.map +1 -1
- package/lib/components/VideoRecordButton.js +221 -92
- package/lib/components/VideoRecordButton.js.map +1 -1
- package/lib/components/ViewOnceBadge.d.ts +23 -0
- package/lib/components/ViewOnceBadge.d.ts.map +1 -0
- package/lib/components/ViewOnceBadge.js +233 -0
- package/lib/components/ViewOnceBadge.js.map +1 -0
- package/lib/components/VoiceMessageInput/RecordedVoicePreview.d.ts +16 -0
- package/lib/components/VoiceMessageInput/RecordedVoicePreview.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/RecordedVoicePreview.js +503 -0
- package/lib/components/VoiceMessageInput/RecordedVoicePreview.js.map +1 -0
- package/lib/components/VoiceMessageInput/constants.d.ts +16 -0
- package/lib/components/VoiceMessageInput/constants.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/constants.js +22 -0
- package/lib/components/VoiceMessageInput/constants.js.map +1 -0
- package/lib/components/VoiceMessageInput/formatElapsed.d.ts +2 -0
- package/lib/components/VoiceMessageInput/formatElapsed.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/formatElapsed.js +7 -0
- package/lib/components/VoiceMessageInput/formatElapsed.js.map +1 -0
- package/lib/components/VoiceMessageInput/index.d.ts +9 -0
- package/lib/components/VoiceMessageInput/index.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/index.js +148 -0
- package/lib/components/VoiceMessageInput/index.js.map +1 -0
- package/lib/components/VoiceMessageInput/previewStyles.d.ts +77 -0
- package/lib/components/VoiceMessageInput/previewStyles.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/previewStyles.js +80 -0
- package/lib/components/VoiceMessageInput/previewStyles.js.map +1 -0
- package/lib/components/VoiceMessageInput/previewWaveform.d.ts +15 -0
- package/lib/components/VoiceMessageInput/previewWaveform.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/previewWaveform.js +27 -0
- package/lib/components/VoiceMessageInput/previewWaveform.js.map +1 -0
- package/lib/components/VoiceMessageInput/recorder.d.ts +18 -0
- package/lib/components/VoiceMessageInput/recorder.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/recorder.js +80 -0
- package/lib/components/VoiceMessageInput/recorder.js.map +1 -0
- package/lib/components/VoiceMessageInput/types.d.ts +56 -0
- package/lib/components/VoiceMessageInput/types.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/types.js +2 -0
- package/lib/components/VoiceMessageInput/types.js.map +1 -0
- package/lib/components/VoiceMessageInput/useLazyRecorder.d.ts +7 -0
- package/lib/components/VoiceMessageInput/useLazyRecorder.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/useLazyRecorder.js +61 -0
- package/lib/components/VoiceMessageInput/useLazyRecorder.js.map +1 -0
- package/lib/components/VoiceMessageInput/useStateReport.d.ts +16 -0
- package/lib/components/VoiceMessageInput/useStateReport.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/useStateReport.js +81 -0
- package/lib/components/VoiceMessageInput/useStateReport.js.map +1 -0
- package/lib/components/VoiceMessageInput/useTakePreviewActions.d.ts +34 -0
- package/lib/components/VoiceMessageInput/useTakePreviewActions.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/useTakePreviewActions.js +207 -0
- package/lib/components/VoiceMessageInput/useTakePreviewActions.js.map +1 -0
- package/lib/components/VoiceMessageInput/useVoiceTake.d.ts +25 -0
- package/lib/components/VoiceMessageInput/useVoiceTake.d.ts.map +1 -0
- package/lib/components/VoiceMessageInput/useVoiceTake.js +424 -0
- package/lib/components/VoiceMessageInput/useVoiceTake.js.map +1 -0
- package/lib/components/WaveformPlayer/Bars.d.ts +30 -0
- package/lib/components/WaveformPlayer/Bars.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/Bars.js +171 -0
- package/lib/components/WaveformPlayer/Bars.js.map +1 -0
- package/lib/components/WaveformPlayer/VoiceButton.d.ts +23 -0
- package/lib/components/WaveformPlayer/VoiceButton.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/VoiceButton.js +111 -0
- package/lib/components/WaveformPlayer/VoiceButton.js.map +1 -0
- package/lib/components/WaveformPlayer/WaveformTrack.d.ts +31 -0
- package/lib/components/WaveformPlayer/WaveformTrack.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/WaveformTrack.js +199 -0
- package/lib/components/WaveformPlayer/WaveformTrack.js.map +1 -0
- package/lib/components/WaveformPlayer/audio.d.ts +23 -0
- package/lib/components/WaveformPlayer/audio.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/audio.js +97 -0
- package/lib/components/WaveformPlayer/audio.js.map +1 -0
- package/lib/components/WaveformPlayer/index.d.ts +13 -0
- package/lib/components/WaveformPlayer/index.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/index.js +475 -0
- package/lib/components/WaveformPlayer/index.js.map +1 -0
- package/lib/components/WaveformPlayer/styles.d.ts +257 -0
- package/lib/components/WaveformPlayer/styles.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/styles.js +120 -0
- package/lib/components/WaveformPlayer/styles.js.map +1 -0
- package/lib/components/WaveformPlayer/types.d.ts +32 -0
- package/lib/components/WaveformPlayer/types.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/types.js +2 -0
- package/lib/components/WaveformPlayer/types.js.map +1 -0
- package/lib/components/WaveformPlayer/useSendFlightReveal.d.ts +21 -0
- package/lib/components/WaveformPlayer/useSendFlightReveal.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/useSendFlightReveal.js +105 -0
- package/lib/components/WaveformPlayer/useSendFlightReveal.js.map +1 -0
- package/lib/components/WaveformPlayer/useVoicePlayback.d.ts +39 -0
- package/lib/components/WaveformPlayer/useVoicePlayback.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/useVoicePlayback.js +401 -0
- package/lib/components/WaveformPlayer/useVoicePlayback.js.map +1 -0
- package/lib/components/WaveformPlayer/useVoiceSource.d.ts +38 -0
- package/lib/components/WaveformPlayer/useVoiceSource.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/useVoiceSource.js +244 -0
- package/lib/components/WaveformPlayer/useVoiceSource.js.map +1 -0
- package/lib/components/WaveformPlayer/useWaveformMotion.d.ts +16 -0
- package/lib/components/WaveformPlayer/useWaveformMotion.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/useWaveformMotion.js +135 -0
- package/lib/components/WaveformPlayer/useWaveformMotion.js.map +1 -0
- package/lib/components/WaveformPlayer/useWaveformScrub.d.ts +16 -0
- package/lib/components/WaveformPlayer/useWaveformScrub.d.ts.map +1 -0
- package/lib/components/WaveformPlayer/useWaveformScrub.js +168 -0
- package/lib/components/WaveformPlayer/useWaveformScrub.js.map +1 -0
- package/lib/components/composerPanels.d.ts +13 -0
- package/lib/components/composerPanels.d.ts.map +1 -0
- package/lib/components/composerPanels.js +22 -0
- package/lib/components/composerPanels.js.map +1 -0
- package/lib/components/defaultMessageActions.d.ts +30 -0
- package/lib/components/defaultMessageActions.d.ts.map +1 -0
- package/lib/components/defaultMessageActions.js +124 -0
- package/lib/components/defaultMessageActions.js.map +1 -0
- package/lib/components/earpiece.d.ts +56 -0
- package/lib/components/earpiece.d.ts.map +1 -0
- package/lib/components/earpiece.js +218 -0
- package/lib/components/earpiece.js.map +1 -0
- package/lib/components/floatingNoteMath.d.ts +66 -0
- package/lib/components/floatingNoteMath.d.ts.map +1 -0
- package/lib/components/floatingNoteMath.js +143 -0
- package/lib/components/floatingNoteMath.js.map +1 -0
- package/lib/components/haptics.d.ts +5 -0
- package/lib/components/haptics.d.ts.map +1 -0
- package/lib/components/haptics.js +26 -0
- package/lib/components/haptics.js.map +1 -0
- package/lib/components/mediaDownload.d.ts +14 -0
- package/lib/components/mediaDownload.d.ts.map +1 -0
- package/lib/components/mediaDownload.js +43 -0
- package/lib/components/mediaDownload.js.map +1 -0
- package/lib/components/mediaPalette.d.ts +7 -2
- package/lib/components/mediaPalette.d.ts.map +1 -1
- package/lib/components/mediaPalette.js +27 -15
- package/lib/components/mediaPalette.js.map +1 -1
- package/lib/components/mediaPlayback.d.ts +204 -5
- package/lib/components/mediaPlayback.d.ts.map +1 -1
- package/lib/components/mediaPlayback.js +746 -17
- package/lib/components/mediaPlayback.js.map +1 -1
- package/lib/components/mediaTransfer.d.ts +29 -0
- package/lib/components/mediaTransfer.d.ts.map +1 -0
- package/lib/components/mediaTransfer.js +52 -0
- package/lib/components/mediaTransfer.js.map +1 -0
- package/lib/components/mediaViewer/MediaViewer.d.ts +17 -0
- package/lib/components/mediaViewer/MediaViewer.d.ts.map +1 -0
- package/lib/components/mediaViewer/MediaViewer.js +347 -0
- package/lib/components/mediaViewer/MediaViewer.js.map +1 -0
- package/lib/components/mediaViewer/MediaViewerChrome.d.ts +14 -0
- package/lib/components/mediaViewer/MediaViewerChrome.d.ts.map +1 -0
- package/lib/components/mediaViewer/MediaViewerChrome.js +164 -0
- package/lib/components/mediaViewer/MediaViewerChrome.js.map +1 -0
- package/lib/components/mediaViewer/MediaViewerHost.d.ts +10 -0
- package/lib/components/mediaViewer/MediaViewerHost.d.ts.map +1 -0
- package/lib/components/mediaViewer/MediaViewerHost.js +76 -0
- package/lib/components/mediaViewer/MediaViewerHost.js.map +1 -0
- package/lib/components/mediaViewer/MediaViewerPage.d.ts +25 -0
- package/lib/components/mediaViewer/MediaViewerPage.d.ts.map +1 -0
- package/lib/components/mediaViewer/MediaViewerPage.js +194 -0
- package/lib/components/mediaViewer/MediaViewerPage.js.map +1 -0
- package/lib/components/mediaViewer/gallery.d.ts +27 -0
- package/lib/components/mediaViewer/gallery.d.ts.map +1 -0
- package/lib/components/mediaViewer/gallery.js +41 -0
- package/lib/components/mediaViewer/gallery.js.map +1 -0
- package/lib/components/messageHighlight.d.ts +41 -0
- package/lib/components/messageHighlight.d.ts.map +1 -0
- package/lib/components/messageHighlight.js +157 -0
- package/lib/components/messageHighlight.js.map +1 -0
- package/lib/components/messagePress.d.ts +14 -0
- package/lib/components/messagePress.d.ts.map +1 -0
- package/lib/components/messagePress.js +18 -0
- package/lib/components/messagePress.js.map +1 -0
- package/lib/components/messageSelection.d.ts +39 -0
- package/lib/components/messageSelection.d.ts.map +1 -0
- package/lib/components/messageSelection.js +135 -0
- package/lib/components/messageSelection.js.map +1 -0
- package/lib/components/recordingFeedback.d.ts +22 -0
- package/lib/components/recordingFeedback.d.ts.map +1 -0
- package/lib/components/recordingFeedback.js +80 -0
- package/lib/components/recordingFeedback.js.map +1 -0
- package/lib/components/recordingMeter.d.ts +19 -0
- package/lib/components/recordingMeter.d.ts.map +1 -0
- package/lib/components/recordingMeter.js +21 -0
- package/lib/components/recordingMeter.js.map +1 -0
- package/lib/components/roundNoteChrome.d.ts +107 -0
- package/lib/components/roundNoteChrome.d.ts.map +1 -0
- package/lib/components/roundNoteChrome.js +249 -0
- package/lib/components/roundNoteChrome.js.map +1 -0
- package/lib/components/roundNotePlayers.d.ts +78 -0
- package/lib/components/roundNotePlayers.d.ts.map +1 -0
- package/lib/components/roundNotePlayers.js +230 -0
- package/lib/components/roundNotePlayers.js.map +1 -0
- package/lib/components/sendFlight.d.ts +88 -0
- package/lib/components/sendFlight.d.ts.map +1 -0
- package/lib/components/sendFlight.js +146 -0
- package/lib/components/sendFlight.js.map +1 -0
- package/lib/components/viewOnce.d.ts +27 -0
- package/lib/components/viewOnce.d.ts.map +1 -0
- package/lib/components/viewOnce.js +168 -0
- package/lib/components/viewOnce.js.map +1 -0
- package/lib/components/visionCamera.d.ts +45 -0
- package/lib/components/visionCamera.d.ts.map +1 -0
- package/lib/components/visionCamera.js +117 -0
- package/lib/components/visionCamera.js.map +1 -0
- package/lib/components/voiceEditing.d.ts +34 -0
- package/lib/components/voiceEditing.d.ts.map +1 -0
- package/lib/components/voiceEditing.js +159 -0
- package/lib/components/voiceEditing.js.map +1 -0
- package/lib/components/voiceWaveform.d.ts +108 -0
- package/lib/components/voiceWaveform.d.ts.map +1 -0
- package/lib/components/voiceWaveform.js +165 -0
- package/lib/components/voiceWaveform.js.map +1 -0
- package/lib/components/wallpaperGradient.d.ts +16 -0
- package/lib/components/wallpaperGradient.d.ts.map +1 -0
- package/lib/components/wallpaperGradient.js +186 -0
- package/lib/components/wallpaperGradient.js.map +1 -0
- package/lib/components/windowInsets.d.ts +11 -0
- package/lib/components/windowInsets.d.ts.map +1 -0
- package/lib/components/windowInsets.js +44 -0
- package/lib/components/windowInsets.js.map +1 -0
- package/lib/dayjsLocales.js +15 -2
- package/lib/dayjsLocales.js.map +1 -1
- package/lib/emoji/EmojiGrid/BackspaceButton.d.ts +11 -0
- package/lib/emoji/EmojiGrid/BackspaceButton.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/BackspaceButton.js +111 -0
- package/lib/emoji/EmojiGrid/BackspaceButton.js.map +1 -0
- package/lib/emoji/EmojiGrid/EmojiRow.d.ts +15 -0
- package/lib/emoji/EmojiGrid/EmojiRow.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/EmojiRow.js +71 -0
- package/lib/emoji/EmojiGrid/EmojiRow.js.map +1 -0
- package/lib/emoji/EmojiGrid/Search.d.ts +29 -0
- package/lib/emoji/EmojiGrid/Search.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/Search.js +234 -0
- package/lib/emoji/EmojiGrid/Search.js.map +1 -0
- package/lib/emoji/EmojiGrid/TabStrip.d.ts +16 -0
- package/lib/emoji/EmojiGrid/TabStrip.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/TabStrip.js +237 -0
- package/lib/emoji/EmojiGrid/TabStrip.js.map +1 -0
- package/lib/emoji/EmojiGrid/TonePopup.d.ts +12 -0
- package/lib/emoji/EmojiGrid/TonePopup.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/TonePopup.js +137 -0
- package/lib/emoji/EmojiGrid/TonePopup.js.map +1 -0
- package/lib/emoji/EmojiGrid/constants.d.ts +29 -0
- package/lib/emoji/EmojiGrid/constants.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/constants.js +65 -0
- package/lib/emoji/EmojiGrid/constants.js.map +1 -0
- package/lib/emoji/EmojiGrid/index.d.ts +10 -0
- package/lib/emoji/EmojiGrid/index.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/index.js +450 -0
- package/lib/emoji/EmojiGrid/index.js.map +1 -0
- package/lib/emoji/EmojiGrid/items.d.ts +25 -0
- package/lib/emoji/EmojiGrid/items.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/items.js +75 -0
- package/lib/emoji/EmojiGrid/items.js.map +1 -0
- package/lib/emoji/EmojiGrid/styles.d.ts +181 -0
- package/lib/emoji/EmojiGrid/styles.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/styles.js +184 -0
- package/lib/emoji/EmojiGrid/styles.js.map +1 -0
- package/lib/emoji/EmojiGrid/types.d.ts +53 -0
- package/lib/emoji/EmojiGrid/types.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/types.js +2 -0
- package/lib/emoji/EmojiGrid/types.js.map +1 -0
- package/lib/emoji/EmojiGrid/useTabScroll.d.ts +19 -0
- package/lib/emoji/EmojiGrid/useTabScroll.d.ts.map +1 -0
- package/lib/emoji/EmojiGrid/useTabScroll.js +124 -0
- package/lib/emoji/EmojiGrid/useTabScroll.js.map +1 -0
- package/lib/emoji/EmojiKeyboard.d.ts +79 -0
- package/lib/emoji/EmojiKeyboard.d.ts.map +1 -0
- package/lib/emoji/EmojiKeyboard.js +445 -0
- package/lib/emoji/EmojiKeyboard.js.map +1 -0
- package/lib/emoji/defaultExpandedPicker.d.ts +5 -0
- package/lib/emoji/defaultExpandedPicker.d.ts.map +1 -0
- package/lib/emoji/defaultExpandedPicker.js +11 -0
- package/lib/emoji/defaultExpandedPicker.js.map +1 -0
- package/lib/emoji/emojiData.d.ts +2 -0
- package/lib/emoji/emojiData.d.ts.map +1 -0
- package/lib/emoji/emojiData.js +5 -0
- package/lib/emoji/emojiData.js.map +1 -0
- package/lib/emoji/emojiStore.d.ts +70 -0
- package/lib/emoji/emojiStore.d.ts.map +1 -0
- package/lib/emoji/emojiStore.js +246 -0
- package/lib/emoji/emojiStore.js.map +1 -0
- package/lib/emoji/textEditing.d.ts +20 -0
- package/lib/emoji/textEditing.d.ts.map +1 -0
- package/lib/emoji/textEditing.js +97 -0
- package/lib/emoji/textEditing.js.map +1 -0
- package/lib/emojiOnly.d.ts +11 -0
- package/lib/emojiOnly.d.ts.map +1 -0
- package/lib/emojiOnly.js +79 -0
- package/lib/emojiOnly.js.map +1 -0
- package/lib/gestures/useRowSwipe.d.ts +43 -0
- package/lib/gestures/useRowSwipe.d.ts.map +1 -0
- package/lib/gestures/useRowSwipe.js +74 -0
- package/lib/gestures/useRowSwipe.js.map +1 -0
- package/lib/hooks/useAnimatedPresence.d.ts +22 -0
- package/lib/hooks/useAnimatedPresence.d.ts.map +1 -0
- package/lib/hooks/useAnimatedPresence.js +97 -0
- package/lib/hooks/useAnimatedPresence.js.map +1 -0
- package/lib/hooks/useChatMessages.d.ts +39 -0
- package/lib/hooks/useChatMessages.d.ts.map +1 -0
- package/lib/hooks/useChatMessages.js +125 -0
- package/lib/hooks/useChatMessages.js.map +1 -0
- package/lib/hooks/useColorScheme.d.ts +7 -1
- package/lib/hooks/useColorScheme.d.ts.map +1 -1
- package/lib/hooks/useColorScheme.js +46 -8
- package/lib/hooks/useColorScheme.js.map +1 -1
- package/lib/hooks/useHasKeyboardProvider.js +18 -7
- package/lib/hooks/useHasKeyboardProvider.js.map +1 -1
- package/lib/hooks/useIcons.js +15 -2
- package/lib/hooks/useIcons.js.map +1 -1
- package/lib/hooks/useIsKeyboardVisible.js +39 -17
- package/lib/hooks/useIsKeyboardVisible.js.map +1 -1
- package/lib/hooks/useIsRTL.js +15 -2
- package/lib/hooks/useIsRTL.js.map +1 -1
- package/lib/hooks/useKeyboardVerticalOffset.d.ts +5 -3
- package/lib/hooks/useKeyboardVerticalOffset.d.ts.map +1 -1
- package/lib/hooks/useKeyboardVerticalOffset.js +52 -18
- package/lib/hooks/useKeyboardVerticalOffset.js.map +1 -1
- package/lib/hooks/useLabels.js +15 -2
- package/lib/hooks/useLabels.js.map +1 -1
- package/lib/hooks/useStreamingMessages.js +200 -86
- package/lib/hooks/useStreamingMessages.js.map +1 -1
- package/lib/hooks/useTheme.js +56 -7
- package/lib/hooks/useTheme.js.map +1 -1
- package/lib/hooks/useUpdateLayoutEffect.d.ts.map +1 -1
- package/lib/hooks/useUpdateLayoutEffect.js +35 -11
- package/lib/hooks/useUpdateLayoutEffect.js.map +1 -1
- package/lib/i18n.d.ts +182 -0
- package/lib/i18n.d.ts.map +1 -1
- package/lib/i18n.js +121 -23
- package/lib/i18n.js.map +1 -1
- package/lib/index.d.ts +31 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +18 -1
- package/lib/index.js.map +1 -1
- package/lib/linkParser.d.ts +2 -1
- package/lib/linkParser.d.ts.map +1 -1
- package/lib/linkParser.js +323 -185
- package/lib/linkParser.js.map +1 -1
- package/lib/locales/ar.d.ts.map +1 -1
- package/lib/locales/ar.js +110 -19
- package/lib/locales/ar.js.map +1 -1
- package/lib/locales/de.d.ts.map +1 -1
- package/lib/locales/de.js +110 -19
- package/lib/locales/de.js.map +1 -1
- package/lib/locales/es.d.ts.map +1 -1
- package/lib/locales/es.js +110 -19
- package/lib/locales/es.js.map +1 -1
- package/lib/locales/fr.d.ts.map +1 -1
- package/lib/locales/fr.js +110 -19
- package/lib/locales/fr.js.map +1 -1
- package/lib/locales/hi.d.ts.map +1 -1
- package/lib/locales/hi.js +110 -19
- package/lib/locales/hi.js.map +1 -1
- package/lib/locales/id.d.ts.map +1 -1
- package/lib/locales/id.js +110 -19
- package/lib/locales/id.js.map +1 -1
- package/lib/locales/index.js +19 -5
- package/lib/locales/index.js.map +1 -1
- package/lib/locales/it.d.ts.map +1 -1
- package/lib/locales/it.js +110 -19
- package/lib/locales/it.js.map +1 -1
- package/lib/locales/ja.d.ts.map +1 -1
- package/lib/locales/ja.js +110 -19
- package/lib/locales/ja.js.map +1 -1
- package/lib/locales/ko.d.ts.map +1 -1
- package/lib/locales/ko.js +110 -19
- package/lib/locales/ko.js.map +1 -1
- package/lib/locales/nl.d.ts.map +1 -1
- package/lib/locales/nl.js +110 -19
- package/lib/locales/nl.js.map +1 -1
- package/lib/locales/pl.d.ts.map +1 -1
- package/lib/locales/pl.js +110 -19
- package/lib/locales/pl.js.map +1 -1
- package/lib/locales/pt.d.ts.map +1 -1
- package/lib/locales/pt.js +110 -19
- package/lib/locales/pt.js.map +1 -1
- package/lib/locales/ru.d.ts.map +1 -1
- package/lib/locales/ru.js +110 -19
- package/lib/locales/ru.js.map +1 -1
- package/lib/locales/tr.d.ts.map +1 -1
- package/lib/locales/tr.js +110 -19
- package/lib/locales/tr.js.map +1 -1
- package/lib/locales/zh.d.ts.map +1 -1
- package/lib/locales/zh.js +110 -19
- package/lib/locales/zh.js.map +1 -1
- package/lib/logging.d.ts +5 -0
- package/lib/logging.d.ts.map +1 -1
- package/lib/logging.js +13 -1
- package/lib/logging.js.map +1 -1
- package/lib/messageUtils.d.ts +19 -0
- package/lib/messageUtils.d.ts.map +1 -0
- package/lib/messageUtils.js +61 -0
- package/lib/messageUtils.js.map +1 -0
- package/lib/motion.d.ts +21 -0
- package/lib/motion.d.ts.map +1 -0
- package/lib/motion.js +30 -0
- package/lib/motion.js.map +1 -0
- package/lib/optional/index.d.ts +99 -0
- package/lib/optional/index.d.ts.map +1 -0
- package/lib/optional/index.js +284 -0
- package/lib/optional/index.js.map +1 -0
- package/lib/rtl.js +7 -5
- package/lib/rtl.js.map +1 -1
- package/lib/store.d.ts +40 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +127 -0
- package/lib/store.js.map +1 -0
- package/lib/styles.d.ts +2 -2
- package/lib/styles.d.ts.map +1 -1
- package/lib/styles.js +15 -15
- package/lib/styles.js.map +1 -1
- package/lib/types.js +1 -0
- package/lib/types.js.map +1 -1
- package/lib/utils.d.ts +15 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +199 -94
- package/lib/utils.js.map +1 -1
- package/llms.txt +133 -31
- package/package.json +89 -46
- package/lib/InputToolbar.d.ts +0 -49
- package/lib/InputToolbar.d.ts.map +0 -1
- package/lib/InputToolbar.js +0 -338
- package/lib/InputToolbar.js.map +0 -1
- package/lib/MessageVideo.d.ts.map +0 -1
- package/lib/MessageVideo.js +0 -162
- package/lib/MessageVideo.js.map +0 -1
- package/lib/MessagesContainer/FlashList.d.ts +0 -9
- package/lib/MessagesContainer/FlashList.d.ts.map +0 -1
- package/lib/MessagesContainer/FlashList.js +0 -23
- package/lib/MessagesContainer/FlashList.js.map +0 -1
- package/lib/components/ContextMenu.d.ts +0 -25
- package/lib/components/ContextMenu.d.ts.map +0 -1
- package/lib/components/ContextMenu.js +0 -122
- package/lib/components/ContextMenu.js.map +0 -1
- package/lib/components/VideoNoteRecorder.d.ts.map +0 -1
- package/lib/components/VideoNoteRecorder.js +0 -634
- package/lib/components/VideoNoteRecorder.js.map +0 -1
- package/lib/components/VoiceMessageInput.d.ts +0 -33
- package/lib/components/VoiceMessageInput.d.ts.map +0 -1
- package/lib/components/VoiceMessageInput.js +0 -403
- package/lib/components/VoiceMessageInput.js.map +0 -1
- package/lib/components/WaveformPlayer.d.ts +0 -19
- package/lib/components/WaveformPlayer.d.ts.map +0 -1
- package/lib/components/WaveformPlayer.js +0 -367
- package/lib/components/WaveformPlayer.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<a href="https://www.npmjs.com/package/@kesha-antonov/react-native-chat"><img alt="npm version" src="https://badge.fury.io/js/@kesha-antonov%2Freact-native-chat.svg"/></a>
|
|
3
3
|
<a href="https://www.npmjs.com/package/@kesha-antonov/react-native-chat"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@kesha-antonov%2Freact-native-chat.svg"/></a>
|
|
4
|
-
<a href="https://npm-stat.com/charts.html?package=%40kesha-antonov%2Freact-native-chat&from=2015-01-01"><img alt="total npm downloads" src="https://img.shields.io/badge/total%20downloads-
|
|
4
|
+
<a href="https://npm-stat.com/charts.html?package=%40kesha-antonov%2Freact-native-chat&from=2015-01-01"><img alt="total npm downloads" src="https://img.shields.io/badge/total%20downloads-47.3k-blue.svg"/></a>
|
|
5
5
|
<a href="https://www.npmjs.com/package/@kesha-antonov/react-native-chat"><img alt="npm downloads (last 18 months)" src="https://img.shields.io/npm/dt/@kesha-antonov%2Freact-native-chat.svg?label=18-months%20downloads"/></a>
|
|
6
6
|
<a href="https://github.com/kesha-antonov/react-native-chat/actions/workflows/main.yml"><img src="https://github.com/kesha-antonov/react-native-chat/actions/workflows/main.yml/badge.svg" alt="build"></a>
|
|
7
7
|
<img src="https://img.shields.io/badge/platforms-iOS%20%7C%20Android%20%7C%20Web-lightgrey.svg" alt="platforms">
|
|
@@ -32,7 +32,66 @@
|
|
|
32
32
|
<a href="docs/MIGRATION.md">Migrate in one command with the codemod →</a>
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
<p align="center">
|
|
36
|
+
<strong><a href="https://kesha-antonov.github.io/react-native-chat/">📖 Documentation</a></strong> ·
|
|
37
|
+
<a href="https://kesha-antonov.github.io/react-native-chat/installation">Installation</a> ·
|
|
38
|
+
<a href="https://kesha-antonov.github.io/react-native-chat/usage">Usage</a> ·
|
|
39
|
+
<a href="https://kesha-antonov.github.io/react-native-chat/props">Props</a> ·
|
|
40
|
+
<a href="https://kesha-antonov.github.io/react-native-chat/guides">Guides</a>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<sub>Using it in production? A ⭐ helps other developers find the library.</sub>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<!-- cryptoc-promo:start -->
|
|
48
|
+
<hr />
|
|
49
|
+
|
|
50
|
+
<h2 align="center">Sponsors</h2>
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<a href="https://getstream.io/chat/sdk/react-native/?utm_source=github&utm_medium=sponsor&utm_campaign=keshaantonov&utm_term=react-native-chat"><img width="100" height="100" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/getstream-sponsor-logo.png" alt="Stream" /></a>
|
|
54
|
+
<br />
|
|
55
|
+
<a href="https://getstream.io/chat/sdk/react-native/?utm_source=github&utm_medium=sponsor&utm_campaign=keshaantonov&utm_term=react-native-chat"><strong>Stream</strong></a> - React Native Chat SDK
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
<hr />
|
|
59
|
+
|
|
60
|
+
<table align="center">
|
|
61
|
+
<tr>
|
|
62
|
+
<td align="center" valign="top" width="190">
|
|
63
|
+
<a href="https://cryptoc-app.web.app/"><img src="https://cryptoc-app.web.app/img/icon.png?v=3" width="76" height="76" alt="cryptoc app icon" /></a>
|
|
64
|
+
<br /><br />
|
|
65
|
+
<img src="https://cryptoc-app.web.app/img/qr-get.png?v=2" width="124" height="124" alt="QR code that installs cryptoc" />
|
|
66
|
+
<br />
|
|
67
|
+
<sub>Scan to install</sub>
|
|
68
|
+
<br /><br />
|
|
69
|
+
<!-- App Store button hidden for now
|
|
70
|
+
<a href="https://apps.apple.com/app/cryptoc/id1333169178"><img height="40" src="https://cryptoc-app.web.app/img/appstore.svg?v=2" alt="Download on the App Store" /></a>
|
|
71
|
+
<br />
|
|
72
|
+
-->
|
|
73
|
+
<a href="https://play.google.com/store/apps/details?id=co.ssoul.CryptoC"><img height="59" src="https://cryptoc-app.web.app/img/googleplay.png?v=2" alt="Get it on Google Play" /></a>
|
|
74
|
+
</td>
|
|
75
|
+
<td valign="top">
|
|
76
|
+
|
|
77
|
+
### Support my work
|
|
78
|
+
|
|
79
|
+
**[cryptoc](https://cryptoc-app.web.app/)** - my crypto portfolio app. Your coins on the home screen, lock screen and watch face. iPhone, iPad, Mac, Apple Watch, Android, Android tablet and Wear OS.
|
|
80
|
+
|
|
81
|
+
- Portfolio with average buy price and 24h / 180-day / all-time P&L
|
|
82
|
+
- Widgets in three sizes, refreshed in the background - most days you never open the app
|
|
83
|
+
- Price alerts on 5,000+ coins, delivered while the app is closed
|
|
84
|
+
- **No account, no email, no exchange API keys, no ads.** Your holdings never reach a server - they sync through your own iCloud or Google Drive
|
|
85
|
+
- Free for 3 holdings, and that is not a trial timer
|
|
86
|
+
|
|
87
|
+
<sub>Downloading it is what pays for the time that goes into these libraries.</sub>
|
|
88
|
+
|
|
89
|
+
</td>
|
|
90
|
+
</tr>
|
|
91
|
+
</table>
|
|
92
|
+
|
|
93
|
+
<hr />
|
|
94
|
+
<!-- cryptoc-promo:end -->
|
|
36
95
|
|
|
37
96
|
## Quick start
|
|
38
97
|
|
|
@@ -68,14 +127,23 @@ That is the whole setup - everything below is optional.
|
|
|
68
127
|
|
|
69
128
|
## ✨ Features
|
|
70
129
|
|
|
130
|
+
- 💬 **[Chat list](#chat-list)** - the list of chats with search, selection actions, archive, swipe to archive and draggable pinned chats; plug in your backend
|
|
71
131
|
- 🌗 **[Dark mode & theming](#theming--dark-mode)** - full light/dark token system, switchable at runtime
|
|
72
132
|
- 🤖 **[Streaming AI messages](#streaming-ai-messages)** - token-by-token replies with a typing caret and stop control
|
|
73
133
|
- 😀 **[Emoji reactions](#emoji-reactions)** - long-press picker and reaction pills
|
|
134
|
+
- ⌨️ **[Emoji keyboard](#emoji-keyboard-and-attachment-menu)** - a full emoji panel in the keyboard's place, with search, recents and skin tones
|
|
135
|
+
- 📎 **[Attachment menu](#emoji-keyboard-and-attachment-menu)** - photo grid with numbered selection and a caption, files and location
|
|
74
136
|
- 🎥 **[Video & audio messages](#-whats-new-vs-react-native-gifted-chat)** - real inline playback, with a tappable fallback
|
|
75
|
-
-
|
|
137
|
+
- 🖼️ **[Photo viewer](#message-bubbles--content)** - tap a photo, then swipe through every photo in the chat; pinch or double-tap to zoom
|
|
138
|
+
- 🎙️ **[Voice & video recording](#-whats-new-vs-react-native-gifted-chat)** - hold-to-record voice and round video notes, on once their peers are installed
|
|
139
|
+
- 👋 **[Empty chat greeting](#messages--message-container)** - a "No messages here yet..." card with a tap-to-send 👋
|
|
140
|
+
- 😍 **[Big emoji](#theming--dark-mode)** - emoji-only messages drop the bubble and draw large
|
|
141
|
+
- 🔵 **[Unread bar](#messages--message-container)** - "Unread Messages" above the first unread message, opened scrolled to it
|
|
142
|
+
- 🔗 **[Link previews](#message-bubbles--content)** - a web page block under the text
|
|
143
|
+
- ☑️ **[Multi-select](#message-bubbles--content)** - "Select" in the long-press menu: check circles, Copy / Forward / Delete bar
|
|
76
144
|
- 📍 **[Location messages](#-whats-new-vs-react-native-gifted-chat)** - map card that opens the system maps app
|
|
77
145
|
- ↩️ **[Swipe to reply](#reply-to-messages)** - reply preview and message threading
|
|
78
|
-
- 📋 **[Long-press actions](#message-actions-long-press-context-menu)** -
|
|
146
|
+
- 📋 **[Long-press actions](#message-actions-long-press-context-menu)** - a context menu beside the finger, with a reactions bar
|
|
79
147
|
- ⚡ **[Quick replies](#quick-replies)** - bot-style reply buttons
|
|
80
148
|
- 🔗 **[Smart link parsing](#smart-link-parsing)** - URLs, emails, phones, hashtags, mentions
|
|
81
149
|
- 👤 **[Avatars](#avatars)** - user initials or custom images
|
|
@@ -93,11 +161,23 @@ That is the whole setup - everything below is optional.
|
|
|
93
161
|
Actively maintained, New Architecture ready, built for the latest Reanimated / Gesture Handler.
|
|
94
162
|
|
|
95
163
|
<p align="center">
|
|
96
|
-
<img width="200" src="https://
|
|
97
|
-
 
|
|
98
|
-
<img width="200" src="https://
|
|
99
|
-
 
|
|
100
|
-
<img width="200" src="https://
|
|
164
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/chat-list-light.png" alt="Chat list with unread badges, pins, mutes and swipe-to-archive" />
|
|
165
|
+
|
|
166
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/group-chat-light.png" alt="Group chat with names, avatars, a photo, a file, a reply and reactions" />
|
|
167
|
+
|
|
168
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/group-chat-dark.png" alt="The same group chat in the dark theme" />
|
|
169
|
+
</p>
|
|
170
|
+
|
|
171
|
+
<p align="center">
|
|
172
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/emoji-keyboard.png" alt="Built-in emoji keyboard in place of the system keyboard" />
|
|
173
|
+
|
|
174
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/attachment-sheet.png" alt="Attachment menu with the photo grid, two photos picked and a caption field" />
|
|
175
|
+
|
|
176
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/link-preview-big-emoji.png" alt="Link preview cards and an emoji-only message shown large" />
|
|
177
|
+
</p>
|
|
178
|
+
|
|
179
|
+
<p align="center">
|
|
180
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/chat-list-dark.png" alt="Chat list in the dark theme" />
|
|
101
181
|
</p>
|
|
102
182
|
|
|
103
183
|
---
|
|
@@ -112,16 +192,19 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
112
192
|
| Added in this fork | react-native-gifted-chat | @kesha-antonov/react-native-chat |
|
|
113
193
|
| --- | :---: | :---: |
|
|
114
194
|
| Active maintenance | 💤 sporadic | ✅ active |
|
|
115
|
-
| Modern default UI (
|
|
195
|
+
| Modern default UI (modern messenger look) | dated 2020 look | ✅ wallpaper, tails, inline time, fully overridable |
|
|
116
196
|
| Light/Dark **theme system** | per-component color props | ✅ `theme` / `darkTheme` tokens, runtime switch |
|
|
117
197
|
| Streaming (AI) messages | ❌ | ✅ token-by-token + typing cursor |
|
|
118
198
|
| Emoji reactions | ❌ | ✅ long-press picker + reaction pills |
|
|
199
|
+
| Emoji keyboard | ❌ | ✅ built in: tabs, search, recents, skin tones |
|
|
200
|
+
| Attachment menu | ❌ (`actions` sheet) | ✅ built in: photo grid + caption, files, location |
|
|
201
|
+
| File messages | ❌ | ✅ `IMessage.file` document bubble |
|
|
119
202
|
| Swipe-to-reply + reply preview | ❌ | ✅ built in |
|
|
120
203
|
| **Video / audio messages** | "not implemented, render your own" | ✅ inline players + tappable fallback |
|
|
121
|
-
| **Voice notes** (hold-to-record + waveform) | ❌ | ✅ optional
|
|
122
|
-
| **Video messages** (round camera notes) | ❌ | ✅ optional
|
|
204
|
+
| **Voice notes** (hold-to-record + waveform) | ❌ | ✅ optional |
|
|
205
|
+
| **Video messages** (round camera notes) | ❌ | ✅ optional |
|
|
123
206
|
| **Location messages** | ❌ ignored | ✅ map card → opens system maps |
|
|
124
|
-
| Bubble tails +
|
|
207
|
+
| Bubble tails, inline time + run grouping | flat bubbles | ✅ |
|
|
125
208
|
|
|
126
209
|
</details>
|
|
127
210
|
|
|
@@ -144,12 +227,14 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
144
227
|
### Voice, video and location
|
|
145
228
|
|
|
146
229
|
<details>
|
|
147
|
-
<summary><strong>
|
|
230
|
+
<summary><strong>Recording and media playback</strong></summary>
|
|
231
|
+
|
|
232
|
+
Voice notes (`expo-audio`) and round video notes (`react-native-vision-camera`) turn on by themselves once their peers are installed: the mic button records on hold, and a tap switches it to the camera. Pass `false` to turn either off.
|
|
148
233
|
|
|
149
234
|
```jsx
|
|
150
235
|
<Chat
|
|
151
|
-
|
|
152
|
-
|
|
236
|
+
videoRecording={{ maxDuration: 30 }} // optional: configure; `false` turns round notes off
|
|
237
|
+
mediaPlayback={{ playbackRate: 1.5 }} // optional: start notes at 1.5x, auto-play the next note
|
|
153
238
|
// location messages render automatically for any IMessage with a `location`
|
|
154
239
|
{...props}
|
|
155
240
|
/>
|
|
@@ -158,8 +243,82 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
158
243
|
```bash
|
|
159
244
|
# Optional inline media playback + recording:
|
|
160
245
|
npx expo install expo-video expo-audio expo-image-picker
|
|
246
|
+
# Optional: round video notes and the voice-note waveform
|
|
247
|
+
# (vision-camera 5+, which runs on Nitro and needs its two Nitro packages too)
|
|
248
|
+
npx expo install react-native-vision-camera react-native-nitro-modules react-native-nitro-image react-native-audio-api react-native-svg expo-haptics
|
|
249
|
+
# Optional: trim paused voice takes, blur behind the round-video camera
|
|
250
|
+
npx expo install expo-file-system expo-blur
|
|
161
251
|
```
|
|
162
252
|
|
|
253
|
+
Recording and playback work like this:
|
|
254
|
+
|
|
255
|
+
- **Hold** the record button to record, release to send. With both voice and video enabled, a **tap** switches it between mic and camera, and the choice is remembered. With only video, the camera sits in the record button's place.
|
|
256
|
+
- **Slide left** to cancel: all the way across cancels at once; releasing past about half the way cancels too. **Slide up** to lock and keep recording hands-free. The two exclude each other: no lock once the cancel slide is under way. "Slide up to lock" is shown for the first few takes.
|
|
257
|
+
- **Locked**, the bar shows a `m:ss,t` timer and a CANCEL button, and the lock turns into a **pause** button.
|
|
258
|
+
- A paused **voice** take turns into a preview: its waveform with play, to send or delete. The mic above send **resumes** recording onto its end, and the handles at either end of the waveform **trim** it. Resuming needs `react-native-audio-api`; trimming also needs `expo-file-system`, and a trimmed take is sent as a WAV.
|
|
259
|
+
- A paused **round video** take holds the recording open: the circle shows the frame it paused on (Android; iOS keeps the live camera, dimmed), the bar offers delete and send, and the camera above send **resumes** into the same video. Round takes can't be trimmed.
|
|
260
|
+
- A round note records on the first hold, with the camera drawn over a blurred chat (when `expo-blur` is installed). Switch camera and flash work while recording (the screen lights up for the front camera, the torch for the back one), and you can pinch to zoom. At its 60s limit the take stops into a looping preview (tap to hear it) instead of sending.
|
|
261
|
+
- Haptic ticks on start, stop, lock and mode switch when `expo-haptics` is installed.
|
|
262
|
+
- Starting a recording pauses any note that is playing.
|
|
263
|
+
- Only one note plays at a time. When a voice or round video note plays to its end, the next newer one in the chat starts.
|
|
264
|
+
- While a note plays or is paused, a "now playing" bar at the top of the chat has play/pause, the sender, the speed (1x / 1.5x / 2x; long-press for more, shared by every note) and close; a tap on the title scrolls to the note.
|
|
265
|
+
- Round notes rest in the list on their first frame with a play button (or loop silently with `isRoundVideoAutoplayEnabled`). A tap plays one from the start with sound and grows it, hiding the sender's avatar; a tap pauses it, and a paused note can be scrubbed by dragging around its ring. Its length, in a pill at its bottom-left, counts down while it plays, and playing bars replace its unread dot once it is heard.
|
|
266
|
+
- Set `isMediaUnread` on a message for the unread dot; `mediaPlayback.onMediaRead` reports when an incoming one is played.
|
|
267
|
+
|
|
268
|
+
</details>
|
|
269
|
+
|
|
270
|
+
### Emoji keyboard and attachment menu
|
|
271
|
+
|
|
272
|
+
<details>
|
|
273
|
+
<summary><strong>Built in, on by default</strong></summary>
|
|
274
|
+
|
|
275
|
+
The composer's emoji button opens the built-in emoji keyboard in the system keyboard's place - at the last keyboard height, so switching between the two keeps the composer still. It has the category tabs, search (scroll the grid up to reveal it), recents by use count, a skin-tone popup on long-press and a repeating backspace. A tap inserts at the caret whether or not you control `text`.
|
|
276
|
+
|
|
277
|
+
The paperclip opens the built-in attachment menu: your newest photos in a 3-column grid (with `expo-media-library`), numbered as you pick them, a caption and a "Send N" button; File and Location tabs; a camera tile. Picks arrive in `onSend` as ordinary messages - `image`, `video`, `file` (`{ uri, name, size?, mimeType? }`) or `location` - so there is nothing to wire.
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Each tab shows only when its package is installed:
|
|
281
|
+
npx expo install expo-media-library expo-image-picker expo-document-picker expo-location
|
|
282
|
+
# Optional: keep emoji recents across launches, share received files, fast ph:// thumbnails
|
|
283
|
+
npx expo install @react-native-async-storage/async-storage expo-sharing expo-image
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
<Chat
|
|
288
|
+
emojiKeyboard={{ columns: 8, recents: { storageKey: 'my-app/emoji' } }}
|
|
289
|
+
attachments={{
|
|
290
|
+
tabs: ['gallery', 'file'],
|
|
291
|
+
// Upload first, then send what your backend returns (or `null` to send nothing).
|
|
292
|
+
onPick: async (picked, { caption }) => upload(picked, caption),
|
|
293
|
+
}}
|
|
294
|
+
{...props}
|
|
295
|
+
/>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Hide either with `emojiKeyboard={false}` / `attachments={false}`. `onPressEmoji` replaces the emoji keyboard and `actions` / `onPressActionButton` / `renderActions` replace the attachment menu, as before.
|
|
299
|
+
|
|
300
|
+
**Permissions.** iOS kills an app that asks for a permission without a usage string. In Expo, list the plugins with your own strings (the defaults are generic):
|
|
301
|
+
|
|
302
|
+
```json
|
|
303
|
+
"plugins": [
|
|
304
|
+
["expo-image-picker", { "photosPermission": "...", "cameraPermission": "..." }],
|
|
305
|
+
["expo-media-library", { "photosPermission": "...", "savePhotosPermission": "...", "granularPermissions": ["photo", "video"] }],
|
|
306
|
+
["expo-location", { "locationWhenInUsePermission": "..." }],
|
|
307
|
+
"expo-document-picker",
|
|
308
|
+
"expo-sharing"
|
|
309
|
+
]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
In a bare app add the keys yourself, then rebuild the native app:
|
|
313
|
+
|
|
314
|
+
| Package | iOS `Info.plist` | Android manifest |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| `expo-media-library` | `NSPhotoLibraryUsageDescription` (`NSPhotoLibraryAddUsageDescription` to save) | `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO` (`READ_EXTERNAL_STORAGE` below Android 13) |
|
|
317
|
+
| `expo-image-picker` | `NSPhotoLibraryUsageDescription`, `NSCameraUsageDescription` (`NSMicrophoneUsageDescription` for video) | `CAMERA` (and `RECORD_AUDIO` for video) |
|
|
318
|
+
| `expo-location` | `NSLocationWhenInUseUsageDescription` | `ACCESS_COARSE_LOCATION`, `ACCESS_FINE_LOCATION` |
|
|
319
|
+
| `expo-document-picker` | none (iCloud documents need the iCloud entitlement) | none |
|
|
320
|
+
| `expo-sharing` | none | none |
|
|
321
|
+
|
|
163
322
|
</details>
|
|
164
323
|
|
|
165
324
|
### Custom icons (e.g. Lucide)
|
|
@@ -215,6 +374,7 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
215
374
|
- [Data Structure](#-data-structure)
|
|
216
375
|
- [Props Reference](#-props-reference)
|
|
217
376
|
- [Guides](#-guides)
|
|
377
|
+
- [Chat List](#chat-list)
|
|
218
378
|
- [Reply to Messages](#reply-to-messages)
|
|
219
379
|
- [Maintaining Scroll Position (AI Chatbots)](#maintaining-scroll-position-ai-chatbots)
|
|
220
380
|
- [Streaming (AI) Messages](#streaming-ai-messages)
|
|
@@ -225,6 +385,7 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
225
385
|
- [Localization (i18n)](#localization-i18n)
|
|
226
386
|
- [Message Status](#message-status)
|
|
227
387
|
- [TypeScript](#typescript)
|
|
388
|
+
- [Building blocks](#building-blocks)
|
|
228
389
|
- [Platform Notes](#-platform-notes)
|
|
229
390
|
- [Performance](#-performance)
|
|
230
391
|
- [Testing](#-testing)
|
|
@@ -238,9 +399,11 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
238
399
|
|
|
239
400
|
## 📋 Requirements
|
|
240
401
|
|
|
241
|
-
| React Native | iOS | Android | Expo | TypeScript |
|
|
242
|
-
|
|
243
|
-
| >= 0.
|
|
402
|
+
| React Native | React | iOS | Android | Expo | TypeScript |
|
|
403
|
+
|---|---|---|---|---|---|
|
|
404
|
+
| >= 0.82.0 | >= 19 | >= 15.1 | API 24+ (7.0) | SDK 55+ | >= 5.0 (optional) |
|
|
405
|
+
|
|
406
|
+
The floor comes from `react-native-gesture-handler` 3, which the library is built on (3.0+ is required; it supports React Native 0.82 and newer). The example app runs Expo SDK 58 with React Native 0.88.
|
|
244
407
|
|
|
245
408
|
---
|
|
246
409
|
|
|
@@ -257,26 +420,51 @@ npx expo install @kesha-antonov/react-native-chat react-native-reanimated react-
|
|
|
257
420
|
<details>
|
|
258
421
|
<summary><strong>Three steps</strong></summary>
|
|
259
422
|
|
|
260
|
-
**1.** Install the packages:
|
|
423
|
+
**1.** Install the packages. Reanimated 4 also needs `react-native-worklets`; leave it out on Reanimated 3:
|
|
261
424
|
|
|
262
425
|
```bash
|
|
263
|
-
yarn add @kesha-antonov/react-native-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
426
|
+
yarn add @kesha-antonov/react-native-chat react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
264
427
|
```
|
|
265
428
|
|
|
266
429
|
```bash
|
|
267
|
-
npm install --save @kesha-antonov/react-native-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
430
|
+
npm install --save @kesha-antonov/react-native-chat react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
268
431
|
```
|
|
269
432
|
|
|
270
|
-
**2.**
|
|
433
|
+
**2.** Add the worklets Babel plugin as the last entry in `babel.config.js` - `react-native-worklets/plugin` on Reanimated 4, `react-native-reanimated/plugin` on Reanimated 3 - following the [react-native-reanimated installation guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/).
|
|
434
|
+
|
|
435
|
+
**3.** Install iOS pods, then **rebuild the native app** (`npx react-native run-ios` / `run-android`) and restart Metro with `--reset-cache`. every peer above ships native code, so reloading the JS bundle alone is not enough:
|
|
271
436
|
|
|
272
437
|
```bash
|
|
273
438
|
npx pod-install
|
|
274
439
|
```
|
|
275
440
|
|
|
276
|
-
**3.** Add Reanimated's Babel plugin, following the [react-native-reanimated installation guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#step-2-add-reanimateds-babel-plugin).
|
|
277
|
-
|
|
278
441
|
</details>
|
|
279
442
|
|
|
443
|
+
### Optional peers
|
|
444
|
+
|
|
445
|
+
Every feature below turns itself on when its package is installed and stays hidden when it is not - there is nothing to configure. `getChatCapabilities()` reports what the current install can do, e.g. to build UI that matches the chat's. In development, a feature that was asked for but cannot work (say `audioRecording={{ isEnabled: true }}` without `expo-audio`) logs one hint.
|
|
446
|
+
|
|
447
|
+
| Package | Feature | `getChatCapabilities()` key |
|
|
448
|
+
|---|---|---|
|
|
449
|
+
| `expo-clipboard` or `@react-native-clipboard/clipboard` | "Copy" in the long-press menu | `clipboard` |
|
|
450
|
+
| `expo-haptics` | Haptic ticks (long-press, swipe-to-reply, recording) | `haptics` |
|
|
451
|
+
| `expo-blur` | Blurred backdrop behind the menu and the round video recorder | `blur` |
|
|
452
|
+
| `react-native-svg` | Lucide icons and vector rings | `svg` |
|
|
453
|
+
| `expo-audio` | Voice playback and hold-to-record voice notes | `audioPlayback`, `voiceRecording` |
|
|
454
|
+
| `react-native-audio-api` | Voice waveforms, resume and trim | `waveform` |
|
|
455
|
+
| `expo-video` | Inline video and round video notes | `videoPlayback` |
|
|
456
|
+
| `react-native-vision-camera` 5 | In-chat round video capture | `roundVideoCapture` |
|
|
457
|
+
| `expo-image-picker` | System camera fallback for video notes | `videoRecording` |
|
|
458
|
+
| `react-native-streamdown` | Rich streaming markdown | `markdown` |
|
|
459
|
+
| `@lodev09/react-native-true-sheet` | Native attachment sheet | `nativeSheet` |
|
|
460
|
+
| `expo-media-library` | The attachment menu's photo grid | `mediaLibrary` |
|
|
461
|
+
| `expo-image-picker` | The attachment menu's system photo picker and camera | `imagePicker` |
|
|
462
|
+
| `expo-document-picker` | The attachment menu's File tab | `documentPicker` |
|
|
463
|
+
| `expo-location` | The attachment menu's Location tab | `location` |
|
|
464
|
+
| `expo-sharing` | Opening a received file in the share sheet (otherwise `Linking`) | `sharing` |
|
|
465
|
+
| `@react-native-async-storage/async-storage` | Emoji recents and skin tones kept across launches | `persistentEmojiRecents` |
|
|
466
|
+
| `expo-image` | Gallery thumbnails straight from the photo library | - |
|
|
467
|
+
|
|
280
468
|
---
|
|
281
469
|
|
|
282
470
|
## 🔄 Migrating from react-native-gifted-chat
|
|
@@ -325,14 +513,37 @@ interface IMessage {
|
|
|
325
513
|
createdAt: Date | number
|
|
326
514
|
user: User
|
|
327
515
|
image?: string
|
|
516
|
+
/** Tiny stand-in drawn blurred under `image` until it loads: a small image uri, or a blurhash with expo-image */
|
|
517
|
+
imagePlaceholder?: string
|
|
328
518
|
video?: string
|
|
519
|
+
/** Render `video` as a round video note */
|
|
520
|
+
videoNote?: boolean
|
|
329
521
|
audio?: string
|
|
522
|
+
/** Length of `audio` / `video` in seconds */
|
|
523
|
+
duration?: number
|
|
524
|
+
/** The voice or round note has not been played by its recipient yet (unread dot) */
|
|
525
|
+
isMediaUnread?: boolean
|
|
526
|
+
/** View-once voice or round note: plays a single time, then `mediaPlayback.onViewOnceEnd` fires */
|
|
527
|
+
isViewOnce?: boolean
|
|
528
|
+
/** Transcribed text of a voice or round note, shown under it via the transcribe button */
|
|
529
|
+
transcription?: string
|
|
330
530
|
system?: boolean
|
|
331
531
|
sent?: boolean
|
|
332
532
|
received?: boolean
|
|
333
533
|
pending?: boolean
|
|
534
|
+
/** Sending failed: a red badge replaces the checks */
|
|
535
|
+
isFailed?: boolean
|
|
536
|
+
/** The message was edited: its time reads "edited 14:05" */
|
|
537
|
+
isEdited?: boolean
|
|
538
|
+
editedAt?: Date | number
|
|
334
539
|
/** True while the text is still streaming in (shows a typing cursor) */
|
|
335
540
|
streaming?: boolean
|
|
541
|
+
/** Media uploading or downloading: a progress ring with a cancel ✕ ({ type: 'upload' | 'download', progress?, totalBytes? }) */
|
|
542
|
+
transfer?: MediaTransfer
|
|
543
|
+
/** Media not fetched by itself: a download arrow, which calls `mediaTransfer.onDownload` */
|
|
544
|
+
isDownloadRequired?: boolean
|
|
545
|
+
/** A voice note's waveform from the server (0..1, or 0..31 integers), drawn before the audio downloads */
|
|
546
|
+
waveform?: number[]
|
|
336
547
|
quickReplies?: QuickReplies
|
|
337
548
|
replyMessage?: ReplyMessage
|
|
338
549
|
reactions?: MessageReaction[]
|
|
@@ -340,6 +551,24 @@ interface IMessage {
|
|
|
340
551
|
latitude: number
|
|
341
552
|
longitude: number
|
|
342
553
|
}
|
|
554
|
+
/** A document: a file bubble (icon, name, size); a tap opens it */
|
|
555
|
+
file?: {
|
|
556
|
+
uri: string
|
|
557
|
+
name: string
|
|
558
|
+
size?: number
|
|
559
|
+
mimeType?: string
|
|
560
|
+
}
|
|
561
|
+
/** A web page preview under the text (or fetched via `fetchLinkPreview`); `null` hides it */
|
|
562
|
+
linkPreview?: {
|
|
563
|
+
url?: string
|
|
564
|
+
siteName?: string
|
|
565
|
+
title?: string
|
|
566
|
+
description?: string
|
|
567
|
+
image?: string
|
|
568
|
+
imageWidth?: number
|
|
569
|
+
imageHeight?: number
|
|
570
|
+
imageSize?: 'large' | 'small'
|
|
571
|
+
} | null
|
|
343
572
|
}
|
|
344
573
|
|
|
345
574
|
interface ReplyMessage {
|
|
@@ -381,14 +610,15 @@ Every group below is collapsed - open the one you need.
|
|
|
381
610
|
- **`messageIdGenerator`** _(Function)_ - Generate an id for new messages. Defaults to a simple random string generator.
|
|
382
611
|
- **`locale`** _(String)_ - Locale to localize the dates. You need first to import the locale you need (ie. `require('dayjs/locale/de')` or `import 'dayjs/locale/fr'`)
|
|
383
612
|
- **`colorScheme`** _('light' | 'dark')_ - Force color scheme (light/dark mode). When set to `'light'` or `'dark'`, it overrides the system color scheme. When `undefined`, it uses the system color scheme. Default is `undefined`.
|
|
384
|
-
- **`theme`** _(Object)_ - Override the default light theme tokens (`colors` / `radii` / `spacing` / `typography` / `avatar` / `sendButton` / `composer` / `voice`). Deep-merged over `defaultLightTheme`; any subset is allowed. See [Theming & Dark Mode](#theming--dark-mode).
|
|
613
|
+
- **`theme`** _(Object)_ - Override the default light theme tokens (`colors` / `radii` / `spacing` / `typography` / `avatar` / `sendButton` / `composer` / `voice` / `bubble` / `wallpaper` / `nameColors`). Deep-merged over `defaultLightTheme`; any subset is allowed. See [Theming & Dark Mode](#theming--dark-mode).
|
|
614
|
+
- **`renderWallpaper`** _(Function | null)_ - The chat background. By default `Chat` draws a swirl gradient from `theme.wallpaper`, turning one step per message you send. Return your own element (an image, `ChatWallpaper` with other props...) to replace it, or pass `null` for the plain `theme.colors.background`.
|
|
385
615
|
- **`darkTheme`** _(Object)_ - Same as `theme`, applied when the resolved color scheme is dark (deep-merged over `defaultDarkTheme`).
|
|
386
616
|
- **`icons`** _(Object)_ - Icon override registry. Supply a render function for any built-in icon to replace it (e.g. with `lucide-react-native`). See [Custom icons](#custom-icons-eg-lucide).
|
|
387
617
|
- **`labels`** _(Object)_ - Override any UI string. See [Localization (i18n)](#localization-i18n).
|
|
388
618
|
|
|
389
619
|
### Refs
|
|
390
620
|
|
|
391
|
-
- **`messagesContainerRef`** _(
|
|
621
|
+
- **`messagesContainerRef`** _(`LegendListRef`)_ - Ref to the message list, a [Legend List](https://legendapp.com/open-source/list/) ref: `scrollToEnd`, `scrollToKey` (keys are message `_id`s as strings), `scrollToIndex`, `getState`. Indexes count from the oldest message
|
|
392
622
|
- **`textInputRef`** _(TextInput ref)_ - Ref to the text input
|
|
393
623
|
|
|
394
624
|
</details>
|
|
@@ -404,7 +634,7 @@ Every group below is collapsed - open the one you need.
|
|
|
404
634
|
- **`enableKeyboardProvider`** _(Bool)_ - Render the built-in `KeyboardProvider`; default is `true`. You do **not** need to turn this off just because your app mounts its own provider - that case is detected and reused. Set it to `false` only to opt out completely, e.g. when the provider's edge-to-edge behavior causes layout shift or a header jump on Android/Expo.
|
|
405
635
|
- **`enableGestureHandlerRootView`** _(Bool)_ - Render the `GestureHandlerRootView` Chat mounts around itself; default is `true`. Unlike `KeyboardProvider`, an existing one can't be auto-detected - `react-native-gesture-handler` doesn't expose that publicly - so set this to `false` yourself if your app (or a library it uses, e.g. a bottom sheet) already mounts one at the root. Nesting a second one changes the native view hierarchy around the composer, which has been observed to make a rare Fabric/Yoga layout assertion on iOS more likely, especially when Chat is mounted and unmounted while the keyboard is open ([#17](https://github.com/kesha-antonov/react-native-chat/issues/17)).
|
|
406
636
|
- **`keyboardAvoidingViewProps`** _(Object)_ - Props to be passed to the [`KeyboardAvoidingView`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view). See **keyboardVerticalOffset** below for proper keyboard handling.
|
|
407
|
-
- **`isAlignedTop`** _(`boolean | 'auto'`)_ - Where the bubbles sit **while the whole conversation fits on screen**; once it is taller than the list this has no effect. `false` (default) keeps the usual bottom-anchored chat, `true` pins the messages to the top, and `'auto'` pins them to the top while the keyboard is closed and re-anchors them to the bottom while it is open - so a short conversation starts under the header and moves above the keyboard when the composer is focused ([#2736](https://github.com/FaridSafi/react-native-gifted-chat/issues/2736)). Works with either `isInverted` setting
|
|
637
|
+
- **`isAlignedTop`** _(`boolean | 'auto'`)_ - Where the bubbles sit **while the whole conversation fits on screen**; once it is taller than the list this has no effect. `false` (default) keeps the usual bottom-anchored chat, `true` pins the messages to the top, and `'auto'` pins them to the top while the keyboard is closed and re-anchors them to the bottom while it is open - so a short conversation starts under the header and moves above the keyboard when the composer is focused ([#2736](https://github.com/FaridSafi/react-native-gifted-chat/issues/2736)). Works with either `isInverted` setting.
|
|
408
638
|
- **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
|
|
409
639
|
|
|
410
640
|
#### Understanding `keyboardVerticalOffset`
|
|
@@ -432,6 +662,7 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
432
662
|
|
|
433
663
|
- **`text`** _(String)_ - Input text; default is `undefined`, but if specified, it will override Chat's internal state. Useful for managing text state outside of Chat (e.g. with Redux). Don't forget to implement `textInputProps.onChangeText` to update the text state.
|
|
434
664
|
- **`initialText`** _(String)_ - Initial text to display in the input field
|
|
665
|
+
- **`onDraftChange`** _(Function)_ - `(draft: string) => void`, the user's unsent text as it changes (`''` once sent). Editing a message sets the draft aside and brings it back afterwards, without reporting the edited text. Save it with the chat and pass it back as `initialText`
|
|
435
666
|
- **`isSendButtonAlwaysVisible`** _(Bool)_ - Always show send button in input text composer; default `false`, show only when text input is not empty
|
|
436
667
|
- **`isTextOptional`** _(Bool)_ - Allow sending messages without text (useful for media-only messages); default `false`. Use with `isSendButtonAlwaysVisible` for media attachments.
|
|
437
668
|
- **`isMultiline`** _(Bool)_ - Whether the composer accepts multiple lines; default `true`. With `true` the return key inserts a newline and you send with the send button. Set `false` for a single-line composer whose **return key sends the message** (the keyboard's return key becomes "send" and stays open afterwards).
|
|
@@ -440,16 +671,19 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
440
671
|
- **`renderSend`** _(Component | Function)_ - Custom send button; you can pass children to the original `Send` component quite easily, for example, to use a custom icon ([example](https://github.com/kesha-antonov/react-native-chat/pull/487))
|
|
441
672
|
- **`renderActions`** _(Component | Function)_ - Custom action button on the left of the message composer
|
|
442
673
|
- **`renderAccessory`** _(Component | Function)_ - Custom second line of actions below the message composer
|
|
443
|
-
- **`
|
|
444
|
-
- **`
|
|
445
|
-
- **`
|
|
674
|
+
- **`emojiKeyboard`** _(Bool | Object)_ - The built-in emoji keyboard behind the composer's emoji button, on by default. It opens in the system keyboard's place at the last keyboard height (200 + the bottom inset before a keyboard was seen) and inserts at the caret, whether or not you control `text`. `false` hides the emoji button. An object configures it: `{ isEnabled?, columns?, categories?, recents?, isSearchEnabled?, renderEmojiKeyboard? }` - `columns` fixes the column count (default: as many 45pt columns as fit); `categories` picks and orders the tabs (`'smileys' | 'animals' | 'food' | 'activities' | 'travel' | 'objects' | 'symbols' | 'flags'`); `recents` is `false` or `{ isEnabled?, storageKey?, isPersisted? }` (persisted through `@react-native-async-storage/async-storage` when installed); `isSearchEnabled` (default `true`); `renderEmojiKeyboard({ onSelect, onBackspace, onClose, height, bottomInset })` draws your own keyboard in the panel. Colors and sizes live in `theme.emojiKeyboard`.
|
|
675
|
+
- **`onPressEmoji`** _(Function)_ - Called when the emoji button is pressed, instead of opening the built-in emoji keyboard. Passing it shows the button even with `emojiKeyboard={false}`.
|
|
676
|
+
- **`audioRecording`** _(Bool | Object)_ - Hold-to-record voice notes, **on by default when `expo-audio` is installed**; `false` (or `{ isEnabled: false }`) turns them off. An object configures them: `{ isEnabled?, minDurationMs?, maxDurationMs?, isViewOnceEnabled?, onPermissionDenied?, onTooShort?, onError? }`. `isViewOnceEnabled` shows a view-once toggle above the pause button while a take is locked or paused; a take sent with it on reaches `onSend` with `isViewOnce: true`. `minDurationMs` (default 700) drops takes that long or shorter and calls `onTooShort`; `maxDurationMs` (default 600000) sends the take when reached. Requires the optional `expo-audio` peer (and `react-native-audio-api` for the playback waveform); the mic button is hidden when it is absent. A paused take can be resumed when `react-native-audio-api` is installed with FFmpeg (the M4A recordings are joined without re-encoding), and trimmed when `expo-file-system` is installed too; a trimmed take reaches `onSend` as a 16-bit mono WAV at 24kHz, an untrimmed one as the recorder's M4A.
|
|
677
|
+
- **`videoRecording`** _(Bool | Object)_ - Round video notes, **on by default when `react-native-vision-camera` is installed**; `false` (or `{ isEnabled: false }`) turns them off. `true` / `{ isEnabled: true }` also offers the system-camera fallback below when vision-camera is missing. An object configures them: `{ isEnabled?, maxDuration?, minDurationMs?, isViewOnceEnabled?, onPermissionDenied?, onTooShort?, onError? }`. `maxDuration` is in seconds (default 60); `minDurationMs` (default 800) drops shorter takes and calls `onTooShort`; `isViewOnceEnabled` works as in `audioRecording`, for round notes recorded with vision-camera. With `react-native-vision-camera` 5 or newer linked (plus its `react-native-nitro-modules` and `react-native-nitro-image` peers; it has no Expo config plugin, so add `NSCameraUsageDescription`/`NSMicrophoneUsageDescription` and the `CAMERA`/`RECORD_AUDIO` permissions yourself), the record button records a note on the first hold - shared with voice notes when both are enabled, on its own otherwise. Reaching `maxDuration` stops into a preview (sends directly without `expo-video`). Without vision-camera it falls back to `expo-image-picker`'s system camera, which sends a plain (non-round) video.
|
|
678
|
+
- **`mediaPlayback`** _(Object)_ - How voice and round video notes play. `{ isAutoPlayNextEnabled?, playbackRate?, onPlaybackRateChange?, isRoundVideoAutoplayEnabled?, isNowPlayingBarEnabled?, isFloatingRoundNoteEnabled?, onMediaRead?, isNearEar?, onTranscribe?, onViewOnceEnd? }`. `isNowPlayingBarEnabled` (default `true`) shows a "now playing" bar at the top of the chat while a note plays or is paused. `isFloatingRoundNoteEnabled` (default `true`) keeps a round note that is playing or paused going in a small draggable circle over the list once its row scrolls out of view; set it to `false` to stop the note with its row instead. `isAutoPlayNextEnabled` (default `true`) starts the next newer voice or round note in the chat when one plays to its end. The playback speed is shared by every note; `playbackRate` sets it, and `onPlaybackRateChange` reports changes so the app can keep the speed across launches. `isRoundVideoAutoplayEnabled` (default `false`) loops round notes silently in the list instead of holding their first frame. `onMediaRead(message)` is called when an incoming note with `isMediaUnread` starts playing, so the app can mark it listened. `isNearEar` is raise to listen: feed it from the app's proximity sensor, and while it is `true` the current voice or round note plays through the earpiece (restarting if it was under a second in); when it goes back to `false` the note pauses and the speaker route returns. `onTranscribe(message)` shows a transcribe button on voice notes and beside round notes; tapping it calls this, shows a loading outline until the app sets `message.transcription`, then opens the text under the waveform, or in a bubble under the round note (tap again to collapse or expand). `onViewOnceEnd(message)` is called once a view-once note (`isViewOnce`) has played to its end or been stopped after starting, so the app can remove it. A view-once round note carries the "1" marker on its play button, never autoplays or floats, and cannot be scrubbed.
|
|
446
679
|
- **`textInputProps`** _(Object)_ - props to be passed to the [`<TextInput>`](https://reactnative.dev/docs/textinput).
|
|
447
680
|
|
|
448
681
|
> **Composer height** - there are no height props. The composer starts one line tall and grows with its content. Constrain it through `textInputProps.style` (e.g. `{ maxHeight: 120 }`), which is applied after the measured height and wins.
|
|
449
682
|
|
|
450
683
|
### Actions & Action Sheet
|
|
451
684
|
|
|
452
|
-
- **`
|
|
685
|
+
- **`attachments`** _(Bool | Object)_ - The built-in attachment menu behind the composer's paperclip, on by default; the paperclip shows when at least one tab's peer is installed. Tabs: `gallery` (an in-sheet grid with `expo-media-library`, the system picker with `expo-image-picker` otherwise), `camera` (`expo-image-picker`; a tab of its own only without the grid, which has a camera tile), `file` (`expo-document-picker`) and `location` (`expo-location`). Picks are sent through `onSend`: one `image` / `video` message per photo or video with the caption on the first, a `file` message per document, a `location` message. `false` hides the paperclip. An object configures it: `{ isEnabled?, tabs?, onPick?, renderAttachmentMenu? }` - `tabs` picks and orders them; `onPick(attachments, { caption })` intercepts the picks (`PickedAttachment[]`) and returns the messages to send, `null` to send nothing, or nothing for the default; `renderAttachmentMenu({ visible, onClose, tabs, onSend })` draws your own menu. Colors live in `theme.attachments`. `actions`, `onPressActionButton` and `renderActions` take precedence. See [Emoji keyboard and attachment menu](#emoji-keyboard-and-attachment-menu) for the permissions each peer needs.
|
|
686
|
+
- **`actions`** _(Array)_ - Action options for the composer "+" button. Array of `{ title, action }`; add `icon` (and optional `color`) to an action to render an attachment **grid** (tiles) instead of a list. Opens the built-in themed `AttachmentSheet` - no extra dependency.
|
|
453
687
|
- **`onPressActionButton`** _(Function)_ - Callback when the "+" button is pressed (if set, the built-in `AttachmentSheet` is not shown)
|
|
454
688
|
- **`actionSheet`** _(Function)_ - Escape hatch for a custom system action sheet. **The bundled `@expo/react-native-action-sheet` dependency was removed**, so `context.actionSheet()` defaults to a no-op; pass your own implementation (with `ActionSheetProvider` in your tree) if you relied on it.
|
|
455
689
|
- **`actionSheetOptionTintColor`** _(String)_ - Tint color for action labels in the attachment sheet
|
|
@@ -463,25 +697,42 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
463
697
|
|
|
464
698
|
- **`messagesContainerStyle`** _(Object)_ - Custom style for the messages container
|
|
465
699
|
- **`renderMessage`** _(Component | Function)_ - Custom message container
|
|
466
|
-
- **`renderLoading`** _(Component | Function)_ - Render a loading view
|
|
467
|
-
- **`
|
|
700
|
+
- **`renderLoading`** _(Component | Function)_ - Render a loading view while the chat measures its layout on mount
|
|
701
|
+
- **`isLoading`** _(Boolean)_ - The history is loading. Over an empty list the chat shows a spinner in a service-colored circle (a 28 arc in a 36 circle, growing in from 0.3 over 150ms) in place of the empty-chat card. Messages already passed stay visible, without the spinner
|
|
702
|
+
- **`mediaTransfer`** _(Object)_ - Handlers for the media transfer buttons. `{ onDownload?, onCancel? }`. A message with `transfer: { type, progress?, totalBytes? }` draws the progress ring with a cancel ✕ over its photo, video, file, voice or round note (with "1.2 MB / 4.5 MB" when `totalBytes` or the file size is known); tapping it calls `onCancel(message)`. A message with `isDownloadRequired` draws the download arrow; tapping it calls `onDownload(message)`. Without `onDownload`, a voice note or photo then fetches itself. Remote voice notes, photos and round notes that need no app handling show the same ring while they load, from the request's own progress
|
|
703
|
+
- **`renderChatEmpty`** _(Function | null)_ - What to show while there are no messages. By default a greeting card: "No messages here yet...", a line of help and a big 👋 that sends itself when tapped, centered over the wallpaper. Return your own element to replace it, or pass `null` for nothing. The card is exported as `ChatEmpty`.
|
|
704
|
+
- **`emptyChatGreeting`** _(String | null)_ - The greeting on the empty-chat card, sent as a message when tapped; default `'👋'`. `null` keeps just the title.
|
|
705
|
+
- **`firstUnreadMessageId`** _(String | Number | null)_ - The first message the user has not read. A full-width "Unread Messages" bar is drawn above it and the chat opens scrolled so the bar is at the top. Keep it fixed while the chat is open (the bar stays until you leave), e.g. computed once from the unread count when the screen mounts.
|
|
706
|
+
- **`renderUnreadSeparator`** _(Function | null)_ - Custom "Unread Messages" bar, or `null` to only scroll to the first unread message. The default is exported as `UnreadSeparator`.
|
|
468
707
|
- **`renderChatFooter`** _(Component | Function)_ - Custom component to render below the MessagesContainer (separate from the ListView)
|
|
469
|
-
- **`listProps`** _(Object)_ - Extra props
|
|
470
|
-
- **`isFlashListEnabled`** _(Bool)_ - Render messages with [`@shopify/flash-list`](https://shopify.github.io/flash-list/) v2 instead of `FlatList`; default is `false`. See [FlashList](#flashlist-opt-in).
|
|
708
|
+
- **`listProps`** _(Object)_ - Extra props for the message list, an [`AnimatedLegendList`](https://legendapp.com/open-source/list/api/props/) (e.g. `drawDistance`, `maintainScrollAtEnd`, `onViewableItemsChanged`). The list renders oldest first, not inverted, so `onEndReached` fires at the newest message.
|
|
471
709
|
|
|
472
710
|
### Message Bubbles & Content
|
|
473
711
|
|
|
474
712
|
- **`renderBubble`** _(Component | Function(`props: BubbleProps`))_ - Custom message bubble. Receives [BubbleProps](src/Bubble/types.ts) as parameter.
|
|
475
713
|
- **`renderMessageText`** _(Component | Function)_ - Custom message text
|
|
476
|
-
- **`renderMessageImage`** _(Component | Function)_ - Custom message image
|
|
714
|
+
- **`renderMessageImage`** _(Component | Function)_ - Custom message image. The built-in one opens the photo viewer on tap: it pages through every photo in the chat, oldest first, with a "3 of 12" counter, the caption, sender and date; pinch or double-tap zooms, and a swipe up or down closes it
|
|
477
715
|
- **`renderMessageVideo`** _(Component | Function)_ - Custom message video
|
|
478
716
|
- **`renderMessageAudio`** _(Component | Function)_ - Custom message audio
|
|
479
717
|
- **`renderMessageLocation`** _(Component | Function)_ - Custom renderer for `IMessage.location`; defaults to a map card that opens the system maps app on tap
|
|
480
|
-
- **`
|
|
718
|
+
- **`renderMessageFile`** _(Component | Function)_ - Custom renderer for `IMessage.file`; defaults to a document bubble (a circle with the extension, the name, the size) that opens the file in the share sheet (`expo-sharing`) or through `Linking` on tap
|
|
719
|
+
- **`messageActions`** _(Array | Function(`message`, `defaults`))_ - Long-press context menu actions. Each item is `{ key?, label, icon?, onPress, destructive? }`. An array **replaces** the built-in actions; a function receives the message and the built-in actions for it and returns what to show, so you can extend, filter or reorder them. See [Message actions](#message-actions-long-press-context-menu).
|
|
720
|
+
- **`defaultMessageActions`** _(Bool | `MessageActionKey[]`)_ - The built-in actions, in this order: `reply`, `copy`, `forward`, `pin`, `edit`, `select`, `delete`. Default `true` (all that can work); an array picks and orders them; `false` turns them off. Each shows only when it can work: Reply when `reply.isEnabled` is not `false`; Copy for messages with text when `expo-clipboard` or `@react-native-clipboard/clipboard` is installed; Edit on your own text messages when `onEditMessage` is set; Forward / Pin / Delete when their callbacks are set; Select when a selection can be acted on (a clipboard, Forward or Delete). They are also off when `onLongPressMessage` is set and `messageActions` is not, so an app that handles long-press itself keeps doing so.
|
|
721
|
+
- **`onEditMessage`** _(Function(`message`, `text`))_ - Turns on the "Edit" action for your own text messages. Edit puts the text in the composer under an "Editing" banner; sending then calls this instead of `onSend`. Closing the banner cancels the edit.
|
|
722
|
+
- **`onDeleteMessage`** _(Function(`message`))_ - Turns on the "Delete" action (not red).
|
|
723
|
+
- **`onForwardMessage`** _(Function(`message`))_ - Turns on the "Forward" action.
|
|
724
|
+
- **`onForwardMessages`** _(Function(`messages`))_ - Forwards the messages checked in selection mode, oldest first (also turns on "Forward"). Without it the selection bar's Forward calls `onForwardMessage` once per message.
|
|
725
|
+
- **`onDeleteMessages`** _(Function(`messages`))_ - Deletes the messages checked in selection mode, oldest first (also turns on "Delete"). Without it the selection bar's Delete calls `onDeleteMessage` once per message.
|
|
726
|
+
- **`onSelectionChange`** _(Function(`messages`))_ - Multi-select: "Select" in the long-press menu checks the message, a tap checks or unchecks others (check circles on the left, a tinted row), and a bar replaces the composer with the count, Copy (texts joined oldest first), Forward and Delete. Called on every change with the checked messages; with `[]` once it ends (the X, Android's back, or the last message unchecked).
|
|
727
|
+
- **`renderSelectionBar`** _(Function(`{ count, actions, onClose, messages }`) | null)_ - Custom bar in the composer's place while selecting, or `null` to keep the composer and drive the selection from your own header through `onSelectionChange`.
|
|
728
|
+
- **`fetchLinkPreview`** _(Function(`url`) => Promise<`LinkPreview` | null>)_ - A web page preview (accent bar, site name, bold title, description, picture full width or as a 48dp thumbnail) is drawn under the text for any message with `linkPreview` data. For messages without it, this fetches one for the first link in the text, e.g. from your server's Open Graph endpoint; each URL is fetched once per app run. `IMessage.linkPreview: null` turns it off for one message.
|
|
729
|
+
- **`renderLinkPreview`** _(Function(`{ preview, currentMessage, position, maxWidth, onPress }`) | null)_ - Custom link preview, or `null` to draw none. The default is exported as `LinkPreviewCard`.
|
|
730
|
+
- **`onPressLinkPreview`** _(Function(`preview`, `message`))_ - Called when a link preview is tapped, instead of opening its URL.
|
|
731
|
+
- **`onPinMessage`** _(Function(`message`))_ - Turns on the "Pin" action; it reads "Unpin" on a message with `isPinned: true`. Toggle `isPinned` in the handler.
|
|
481
732
|
- **`renderCustomView`** _(Component | Function)_ - Custom view inside the bubble
|
|
482
733
|
- **`isCustomViewBottom`** _(Bool)_ - Determine whether renderCustomView is displayed before or after the text, image and video views; default is `false`
|
|
483
734
|
- **`onPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is pressed
|
|
484
|
-
- **`onLongPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is long-pressed; you can use this to show action sheets (e.g., copy, delete, reply)
|
|
735
|
+
- **`onLongPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is long-pressed; you can use this to show action sheets (e.g., copy, delete, reply). Setting it (without `messageActions`) turns the built-in long-press menu off
|
|
485
736
|
- **`isMessageGestureEnabled`** _(Bool | Function(`message`))_ - Whether the bubble itself is part of the row's tap / long-press surface that `reactions` and `messageActions` rely on; default is `true`. Pass `false`, or a predicate, for messages that render natively interactive content - the row beside the bubble stays pressable either way. See [Interactive content inside bubbles](#interactive-content-inside-bubbles-video-players-maps).
|
|
486
737
|
- **`imageProps`** _(Object)_ - Extra props to be passed to the [`<Image>`](https://reactnative.dev/docs/image) component created by the default `renderMessageImage`
|
|
487
738
|
- **`imageStyle`** _(Object)_ - Custom style for message images
|
|
@@ -552,6 +803,10 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
552
803
|
|
|
553
804
|
### Avatars
|
|
554
805
|
|
|
806
|
+
Avatars and sender names show in group chats only: a one-to-one chat has neither.
|
|
807
|
+
|
|
808
|
+
- **`isGroupChat`** _(Bool)_ - Whether this is a group chat; default is auto-detected (more than one other sender in `messages` means a group)
|
|
809
|
+
- **`isAvatarVisible`** _(Bool)_ - Show avatars beside incoming messages; default `true` in group chats, `false` in one-to-one chats, and `true` whenever `renderAvatar` is a function. Pass `true` to keep avatars in one-to-one chats
|
|
555
810
|
- **`renderAvatar`** _(Component | Function)_ - Custom message avatar; set to `null` to not render any avatar for the message
|
|
556
811
|
- **`isUserAvatarVisible`** _(Bool)_ - Whether to render an avatar for the current user; default is `false`, only show avatars for other users
|
|
557
812
|
- **`isAvatarVisibleForEveryMessage`** _(Bool)_ - When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is `false`
|
|
@@ -561,7 +816,7 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
561
816
|
|
|
562
817
|
### Username
|
|
563
818
|
|
|
564
|
-
- **`isUsernameVisible`** _(Bool)_ -
|
|
819
|
+
- **`isUsernameVisible`** _(Bool)_ - Show the sender's name on the first message of each run of incoming messages; default `true` in group chats and `false` in one-to-one chats (see `isGroupChat`)
|
|
565
820
|
- **`renderUsername`** _(Component | Function)_ - Custom Username container
|
|
566
821
|
|
|
567
822
|
### Date & Time
|
|
@@ -600,13 +855,13 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
600
855
|
- **`loadEarlierMessagesProps`** _(Object)_ - Props to pass to the LoadEarlierMessages component. The button is only visible when `isAvailable` is `true`:
|
|
601
856
|
- `isAvailable` - Controls button visibility (default: false)
|
|
602
857
|
- `onPress` - Callback when button is pressed
|
|
603
|
-
- `isLoading` -
|
|
604
|
-
- `isInfiniteScrollEnabled` - Enable infinite scroll up when reaching the top of messages container, automatically calls `onPress` (not yet supported for web)
|
|
858
|
+
- `isLoading` - Shows a loading cell, a spinner in a 36 service circle, in place of the button (default: false)
|
|
859
|
+
- `isInfiniteScrollEnabled` - Enable infinite scroll up when reaching the top of messages container, automatically calls `onPress` (not yet supported for web). The list then ends in the loading cell instead of a button while `isAvailable`
|
|
605
860
|
- `label` - Override the default "Load earlier messages" text
|
|
606
861
|
- `containerStyle` / `wrapperStyle` / `textStyle` - Custom styles for the button
|
|
607
862
|
- `activityIndicatorStyle` - Custom style for the loading indicator
|
|
608
|
-
- `activityIndicatorColor` - Color of the
|
|
609
|
-
- `activityIndicatorSize` -
|
|
863
|
+
- `activityIndicatorColor` - Color of the spinner's arc (default: the date pill's text color)
|
|
864
|
+
- `activityIndicatorSize` - Deprecated and ignored: the spinner is a fixed 28 arc
|
|
610
865
|
- **`renderLoadEarlier`** _(Component | Function)_ - Custom "Load earlier messages" button
|
|
611
866
|
|
|
612
867
|
### Typing Indicator
|
|
@@ -615,6 +870,7 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
615
870
|
- **`renderTypingIndicator`** _(Component | Function)_ - Custom typing indicator component
|
|
616
871
|
- **`typingIndicatorStyle`** _(StyleProp<ViewStyle>)_ - Custom style for the TypingIndicator component.
|
|
617
872
|
- **`renderFooter`** _(Component | Function)_ - Custom footer component on the ListView, e.g. `'User is typing...'`; see [CustomizedRenderingExample.tsx](example/components/chat-examples/CustomizedRenderingExample.tsx) for an example. Overrides default typing indicator that triggers when `isTyping` is true.
|
|
873
|
+
- **`TypingStatus`** _(Component)_ - The messenger way to show it: in your chat header, three dots that swell in turn before "typing" (waves for a recording, arrows for an upload). `<TypingStatus users={typingUsers} action='recordingVoice' isGroup color={accent} />` reads "typing", "Anna is typing", "Anna and Max are typing", "recording a voice message"... `ChatList` rows use it for `typingUsers` / `typingAction`, and `getTypingText` gives the text alone
|
|
618
874
|
|
|
619
875
|
### Quick Replies
|
|
620
876
|
|
|
@@ -629,9 +885,12 @@ See the [quick replies example in messages.ts](example/example-expo/data/message
|
|
|
629
885
|
|
|
630
886
|
### Scroll to Bottom
|
|
631
887
|
|
|
632
|
-
|
|
888
|
+
The button comes up after you scroll back towards the newest message by `scrollToBottomOffset`, or when a message arrives while you are away from the newest one, and goes away at the newest message (or after scrolling away again by the same distance, when scrolling brought it up). Messages that arrive while you are away are counted in a badge, which counts down as each one scrolls into view.
|
|
889
|
+
|
|
890
|
+
- **`isScrollToBottomEnabled`** _(Bool)_ - Show the scroll-to-bottom button; default `true`. Passing `true` explicitly also keeps the older behaviour of a non-inverted list scrolling to its end on layout
|
|
891
|
+
- **`isScrollToBottomBadgeEnabled`** _(Bool)_ - Count new messages in a badge on the button; default `true`
|
|
633
892
|
- **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
|
|
634
|
-
- **`scrollToBottomOffset`** _(Integer)_ -
|
|
893
|
+
- **`scrollToBottomOffset`** _(Integer)_ - How far to scroll before the button shows or hides; default `100`
|
|
635
894
|
- **`scrollToBottomStyle`** _(Object)_ - Custom style for Scroll To Bottom wrapper (position, bottom, right, etc.)
|
|
636
895
|
- **`scrollToBottomContentStyle`** _(Object)_ - Custom style for Scroll To Bottom content (size, background, shadow, etc.)
|
|
637
896
|
|
|
@@ -641,6 +900,76 @@ See the [quick replies example in messages.ts](example/example-expo/data/message
|
|
|
641
900
|
|
|
642
901
|
## 🧩 Guides
|
|
643
902
|
|
|
903
|
+
### Chat List
|
|
904
|
+
|
|
905
|
+
Most apps are a list of chats plus the chats themselves. `ChatList` is the list: map your backend's conversations to `ChatListItem` and wire the callbacks, and you get a messenger's main screen:
|
|
906
|
+
|
|
907
|
+
- a header with search, and a selection bar (pin, mute, archive, delete) after a long-press
|
|
908
|
+
- an "Archived Chats" folder, and swipe to archive
|
|
909
|
+
- pinned chats first, which you drag into a new order (with reorder handles while selecting)
|
|
910
|
+
- unread counters, typing and drafts, a loading placeholder and a new-chat button
|
|
911
|
+
|
|
912
|
+
```tsx
|
|
913
|
+
import { Chat, ChatList, ChatListItem } from '@kesha-antonov/react-native-chat'
|
|
914
|
+
|
|
915
|
+
const chats: ChatListItem[] = conversations.map(c => ({
|
|
916
|
+
id: c.id,
|
|
917
|
+
title: c.name,
|
|
918
|
+
avatar: c.photoUrl,
|
|
919
|
+
kind: c.isGroup ? 'group' : 'private',
|
|
920
|
+
lastMessage: c.lastMessage, // an IMessage: preview, time and your sent/read checks
|
|
921
|
+
unreadCount: c.unread,
|
|
922
|
+
isPinned: c.pinned, // pinned chats show first, in the order you pass them
|
|
923
|
+
isMuted: c.muted,
|
|
924
|
+
isArchived: c.archived,
|
|
925
|
+
isOnline: c.online, // green dot on the avatar
|
|
926
|
+
isVerified: c.verified, // check badge after the name
|
|
927
|
+
typingUsers: c.typing, // User[]
|
|
928
|
+
typingAction: c.action, // 'typing' | 'recordingVoice' | 'sendingPhoto' | ...
|
|
929
|
+
draft: drafts[c.id],
|
|
930
|
+
}))
|
|
931
|
+
|
|
932
|
+
<ChatList
|
|
933
|
+
chats={chats}
|
|
934
|
+
user={me}
|
|
935
|
+
isLoading={!loaded}
|
|
936
|
+
onPressChat={chat => navigation.navigate('Chat', { id: chat.id })}
|
|
937
|
+
onPressNewChat={() => navigation.navigate('NewChat')}
|
|
938
|
+
onPinChats={(selected, isPinned) => api.pin(selected.map(c => c.id), isPinned)}
|
|
939
|
+
onMuteChats={(selected, isMuted) => api.mute(selected.map(c => c.id), isMuted)}
|
|
940
|
+
onArchiveChats={(selected, isArchived) => api.archive(selected.map(c => c.id), isArchived)}
|
|
941
|
+
onDeleteChats={selected => api.delete(selected.map(c => c.id))}
|
|
942
|
+
onReorderPinnedChats={ids => api.setPinnedOrder(ids)}
|
|
943
|
+
/>
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
Each action appears only when its callback is passed. The list is controlled: update `chats` from your backend and it follows. For a prototype, `useChatList` keeps the chats in local state and returns the handlers:
|
|
947
|
+
|
|
948
|
+
```tsx
|
|
949
|
+
const list = useChatList(initialChats)
|
|
950
|
+
<ChatList chats={list.chats} user={me} {...list.handlers} onPressChat={openChat} />
|
|
951
|
+
// later: list.receiveMessage(chatId, message), list.markRead(chatId), list.upsertChat(chat)
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
| Prop | What it does |
|
|
955
|
+
| --- | --- |
|
|
956
|
+
| `chats` | Every chat, archived ones included |
|
|
957
|
+
| `user` | You: "You:" in groups and the checks on your own last messages |
|
|
958
|
+
| `onPressChat` / `onLongPressChat` | A tap; a long-press (default: select) |
|
|
959
|
+
| `onPinChats` / `onMuteChats` / `onArchiveChats` / `onDeleteChats` | Selection actions; archive also by swiping a row |
|
|
960
|
+
| `onReorderPinnedChats` | Turns on dragging pinned chats; receives the new order of ids |
|
|
961
|
+
| `onPressNewChat` | Shows the new-chat button |
|
|
962
|
+
| `isLoading` | The loading placeholder |
|
|
963
|
+
| `isSortEnabled` | Pinned first, then by newest message (default `true`) |
|
|
964
|
+
| `isDeleteConfirmed` / `isSwipeEnabled` | Ask before deleting; swipe to archive (both default `true`) |
|
|
965
|
+
| `isHeaderVisible` / `title` / `renderHeaderRight` / `isTopInsetApplied` | The built-in header (hide it to use your navigator's) |
|
|
966
|
+
| `isSearchEnabled` / `filterChat` / `onSearchChange` | Search; a custom match; a server-side search |
|
|
967
|
+
| `isArchiveOpen` / `onArchiveOpenChange` | Control which list shows |
|
|
968
|
+
| `renderChat` / `renderEmpty` / `listProps` / `style` | A custom row (`ChatListCell` is the built-in one), the empty text, FlatList props (`onEndReached`, `refreshControl`...) |
|
|
969
|
+
| `theme` / `darkTheme` / `colorScheme` / `locale` / `labels` / `icons` | As on `Chat`; the list's colors are `theme.chatList` |
|
|
970
|
+
|
|
971
|
+
`ChatListCell`, `ChatListAvatar`, `ChatListShimmer`, `sortChats`, `getChatPreview` and `formatChatListDate` are exported for building your own row or screen.
|
|
972
|
+
|
|
644
973
|
### Reply to Messages
|
|
645
974
|
|
|
646
975
|
<details>
|
|
@@ -664,13 +993,20 @@ Swipe on a message to reply to it, showing a reply preview in the input toolbar
|
|
|
664
993
|
/>
|
|
665
994
|
```
|
|
666
995
|
|
|
996
|
+
Replying works out of the box: long-press a message and pick **Reply**, or swipe it left. The swipe takes over from the list after 0.4cm (about 25pt) of mostly sideways travel, the row follows the finger up to 80pt, a reply arrow fades in from 20pt and fills by 50pt, where a light haptic ticks; letting go past 50pt starts the reply, and the row slides back over 180ms. Turn the swipe off with `reply={{ swipe: { isEnabled: false } }}`, or all replying with `reply={{ isEnabled: false }}`.
|
|
997
|
+
|
|
998
|
+
Tapping a quote inside a bubble scrolls to the quoted message and highlights its row for a second, then fades it out over 300ms. The scroll-to-bottom button then comes up, and its first tap takes you back to the message you tapped the quote in. Pass `reply.onPress(replyMessage, message)` to do something else.
|
|
999
|
+
|
|
667
1000
|
#### Reply Props (Grouped)
|
|
668
1001
|
|
|
669
1002
|
```typescript
|
|
670
1003
|
interface ReplyProps<TMessage> {
|
|
1004
|
+
isEnabled?: boolean // The menu's Reply and swipe-to-reply; default true
|
|
1005
|
+
onReply?: (message: TMessage) => void // A reply started (menu or swipe); use with a controlled `message`
|
|
1006
|
+
|
|
671
1007
|
// Swipe gesture configuration
|
|
672
1008
|
swipe?: {
|
|
673
|
-
isEnabled?: boolean //
|
|
1009
|
+
isEnabled?: boolean // Swipe-to-reply; default true (false to turn it off)
|
|
674
1010
|
direction?: 'left' | 'right' // Swipe direction; default 'left'
|
|
675
1011
|
onSwipe?: (message: TMessage) => void // Callback when swiped
|
|
676
1012
|
renderAction?: ( // Custom swipe action component
|
|
@@ -702,7 +1038,7 @@ interface ReplyProps<TMessage> {
|
|
|
702
1038
|
// Callbacks and state
|
|
703
1039
|
message?: ReplyMessage // Controlled reply state
|
|
704
1040
|
onClear?: () => void // Called when reply cleared
|
|
705
|
-
onPress?: (message:
|
|
1041
|
+
onPress?: (message: ReplyMessage) => void // Quote tapped; default jumps to the quoted message and flashes it
|
|
706
1042
|
|
|
707
1043
|
// Custom renderers
|
|
708
1044
|
renderPreview?: (props: ReplyPreviewProps) => React.ReactNode
|
|
@@ -762,41 +1098,11 @@ The reply preview animates automatically - it expands from zero height with a fa
|
|
|
762
1098
|
<details>
|
|
763
1099
|
<summary><strong>Keep the reading position while long answers stream in</strong></summary>
|
|
764
1100
|
|
|
765
|
-
|
|
1101
|
+
The list follows new content only while it is at the newest message. Scrolled up, the reading position stays put while a long answer streams in or new messages arrive, and the scroll-to-bottom button counts them. Both are Legend List behaviours (`maintainScrollAtEnd`, `maintainVisibleContentPosition`) that the chat turns on; override them through `listProps`:
|
|
766
1102
|
|
|
767
1103
|
```tsx
|
|
768
|
-
//
|
|
769
|
-
<Chat
|
|
770
|
-
listProps={{
|
|
771
|
-
maintainVisibleContentPosition: {
|
|
772
|
-
minIndexForVisible: 0,
|
|
773
|
-
},
|
|
774
|
-
}}
|
|
775
|
-
/>
|
|
776
|
-
|
|
777
|
-
// With auto-scroll threshold - auto-scroll if within 10 pixels of newest content
|
|
778
|
-
<Chat
|
|
779
|
-
listProps={{
|
|
780
|
-
maintainVisibleContentPosition: {
|
|
781
|
-
minIndexForVisible: 0,
|
|
782
|
-
autoscrollToTopThreshold: 10,
|
|
783
|
-
},
|
|
784
|
-
}}
|
|
785
|
-
/>
|
|
786
|
-
|
|
787
|
-
// Conditionally enable based on scroll state (recommended for chatbots)
|
|
788
|
-
const [isScrolledUp, setIsScrolledUp] = useState(false)
|
|
789
|
-
|
|
790
|
-
<Chat
|
|
791
|
-
listProps={{
|
|
792
|
-
onScroll: (event) => {
|
|
793
|
-
setIsScrolledUp(event.contentOffset.y > 50)
|
|
794
|
-
},
|
|
795
|
-
maintainVisibleContentPosition: isScrolledUp
|
|
796
|
-
? { minIndexForVisible: 0, autoscrollToTopThreshold: 10 }
|
|
797
|
-
: undefined,
|
|
798
|
-
}}
|
|
799
|
-
/>
|
|
1104
|
+
// Never follow new content, even at the newest message
|
|
1105
|
+
<Chat listProps={{ maintainScrollAtEnd: false }} />
|
|
800
1106
|
```
|
|
801
1107
|
|
|
802
1108
|
</details>
|
|
@@ -812,14 +1118,14 @@ Render AI assistant replies token-by-token. Incoming chunks are batched with `re
|
|
|
812
1118
|
<details>
|
|
813
1119
|
<summary><strong>useStreamingMessages, stop control and a full example</strong></summary>
|
|
814
1120
|
|
|
815
|
-
The reply above streams in token-by-token (note the caret `▋`) and renders as **markdown** - bold, italics, lists, inline and fenced code - while the
|
|
1121
|
+
The reply above streams in token-by-token (note the caret `▋`) and renders as **markdown** - bold, italics, lists, inline and fenced code - while the app swaps the send button for a **Stop** control mid-stream (with `renderSend`, below). See [Markdown rendering for AI replies](#markdown-rendering-for-ai-replies) to enable markdown.
|
|
816
1122
|
|
|
817
1123
|
- **`IMessage.streaming`** - flag a message as streaming (shows the caret)
|
|
818
1124
|
- **`useStreamingMessages(...)`** - owns the message list, rAF-batches `push()`, and supports stop via `AbortController`. It returns `{ messages, setMessages, append, startStream, isStreaming, stop }`; `setMessages` is there for anything the hook does not cover, so you can patch a message with a plain `map`.
|
|
819
1125
|
|
|
820
1126
|
```tsx
|
|
821
1127
|
import { useCallback } from 'react'
|
|
822
|
-
import { Chat, IMessage, useStreamingMessages } from '@kesha-antonov/react-native-chat'
|
|
1128
|
+
import { Chat, IMessage, Send, SendProps, useStreamingMessages } from '@kesha-antonov/react-native-chat'
|
|
823
1129
|
|
|
824
1130
|
function Bot () {
|
|
825
1131
|
const { messages, append, startStream, isStreaming, stop } = useStreamingMessages<IMessage>()
|
|
@@ -835,7 +1141,14 @@ function Bot () {
|
|
|
835
1141
|
})
|
|
836
1142
|
}, [append, startStream])
|
|
837
1143
|
|
|
838
|
-
|
|
1144
|
+
// While a reply streams, the send button becomes a Stop button.
|
|
1145
|
+
const renderSend = useCallback(
|
|
1146
|
+
(sendProps: SendProps<IMessage>) =>
|
|
1147
|
+
isStreaming ? <MyStopButton onPress={stop} /> : <Send {...sendProps} />,
|
|
1148
|
+
[isStreaming, stop]
|
|
1149
|
+
)
|
|
1150
|
+
|
|
1151
|
+
return <Chat messages={messages} onSend={onSend} user={{ _id: 1 }} renderSend={renderSend} />
|
|
839
1152
|
}
|
|
840
1153
|
```
|
|
841
1154
|
|
|
@@ -867,30 +1180,36 @@ There are two renderers and you get the best available one automatically:
|
|
|
867
1180
|
npx expo install react-native-streamdown react-native-enriched-markdown remend katex
|
|
868
1181
|
```
|
|
869
1182
|
|
|
870
|
-
It also requires `react-native-worklets >= 0.8.3` (i.e. `react-native-reanimated >= 4.3`), and `react-native-enriched-markdown` is a native module, so a dev build / prebuild is required (it does not work in Expo Go).
|
|
1183
|
+
It also requires `react-native-worklets >= 0.8.3` (i.e. `react-native-reanimated >= 4.3`), and `react-native-enriched-markdown` is a native module, so a dev build / prebuild is required (it does not work in Expo Go). 0.3 processes the markdown on a worklet runtime, which needs react-native-worklets' **Bundle Mode**: pass `bundleMode: true` and `importForwarding: { moduleNames: ['remend'] }` to `react-native-worklets/plugin` in `babel.config.js`, and wrap `metro.config.js` in `getBundleModeMetroConfig` from `react-native-worklets/bundleMode` (the example app does both). Until Bundle Mode is on, the chat keeps the built-in renderer and logs a one-time dev hint, since 0.3 throws on its first render without it. Version 0.3+ (`StreamdownText`) and the older `Streamdown` export are both recognised. The bubble's text color, size and link color are mapped onto its `markdownStyle`, so replies match the chat theme in light and dark. Anything in `markdownProps` is forwarded to `StreamdownText`; a `markdownStyle` there is merged per element over the derived one:
|
|
871
1184
|
|
|
872
1185
|
```tsx
|
|
873
|
-
<Chat
|
|
1186
|
+
<Chat
|
|
1187
|
+
messageTextProps={{
|
|
1188
|
+
markdown: true,
|
|
1189
|
+
markdownProps: { markdownStyle: { codeBlock: { backgroundColor: '#0d1117' } } },
|
|
1190
|
+
}}
|
|
1191
|
+
{...props}
|
|
1192
|
+
/>
|
|
874
1193
|
```
|
|
875
1194
|
|
|
876
1195
|
</details>
|
|
877
1196
|
|
|
878
1197
|
### Emoji Reactions
|
|
879
1198
|
|
|
880
|
-
Long-press a message to open a quick emoji picker; selected reactions render as pills
|
|
1199
|
+
Long-press a message to open a quick emoji picker; selected reactions render as pills in the bubble and toggle on tap. The bar's chevron opens the built-in full emoji grid (search, tabs, recents) in place; both ship in the core with no extra dependencies, and `renderExpandedPicker` / `renderReactionPicker` replace them.
|
|
881
1200
|
|
|
882
1201
|
<p align="center">
|
|
883
|
-
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-picker.png" />
|
|
1202
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-picker.png" alt="Long-press menu with the quick reactions bar" />
|
|
884
1203
|
|
|
885
|
-
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-pills.png" />
|
|
1204
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-pills.png" alt="A reaction pill under the message" />
|
|
886
1205
|
|
|
887
|
-
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-emoji-browser.png" />
|
|
1206
|
+
<img width="200" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/reactions-emoji-browser.png" alt="The expanded reactions grid with search and tabs" />
|
|
888
1207
|
</p>
|
|
889
1208
|
|
|
890
1209
|
<details>
|
|
891
1210
|
<summary><strong>Wiring up the toggle, and the full prop list</strong></summary>
|
|
892
1211
|
|
|
893
|
-
Store reactions on each message as a `reactions` array,
|
|
1212
|
+
Store reactions on each message as a `reactions` array and pass `reactions.onReactionPress` - that alone turns reactions on. `Chat.toggleReaction(messages, messageId, emoji, userId)` is the reducer, so the handler is one line. Reaction state is owned by you, so it works with any backend:
|
|
894
1213
|
|
|
895
1214
|
```tsx
|
|
896
1215
|
interface IChatMessage extends IMessage {
|
|
@@ -900,27 +1219,7 @@ interface IChatMessage extends IMessage {
|
|
|
900
1219
|
const CURRENT_USER_ID = 1
|
|
901
1220
|
|
|
902
1221
|
const handleReactionPress = useCallback((message: IChatMessage, emoji: string) => {
|
|
903
|
-
setMessages(prev =>
|
|
904
|
-
prev.map(m => {
|
|
905
|
-
if (m._id !== message._id)
|
|
906
|
-
return m
|
|
907
|
-
|
|
908
|
-
const existing = (m.reactions ?? []).find(r => r.emoji === emoji)
|
|
909
|
-
if (!existing)
|
|
910
|
-
return { ...m, reactions: [...(m.reactions ?? []), { emoji, userIds: [CURRENT_USER_ID] }] }
|
|
911
|
-
|
|
912
|
-
const userIds = existing.userIds.includes(CURRENT_USER_ID)
|
|
913
|
-
? existing.userIds.filter(id => id !== CURRENT_USER_ID)
|
|
914
|
-
: [...existing.userIds, CURRENT_USER_ID]
|
|
915
|
-
|
|
916
|
-
return {
|
|
917
|
-
...m,
|
|
918
|
-
reactions: userIds.length === 0
|
|
919
|
-
? (m.reactions ?? []).filter(r => r.emoji !== emoji)
|
|
920
|
-
: (m.reactions ?? []).map(r => (r.emoji === emoji ? { ...r, userIds } : r)),
|
|
921
|
-
}
|
|
922
|
-
})
|
|
923
|
-
)
|
|
1222
|
+
setMessages(prev => Chat.toggleReaction(prev, message._id, emoji, CURRENT_USER_ID))
|
|
924
1223
|
}, [])
|
|
925
1224
|
|
|
926
1225
|
<Chat
|
|
@@ -928,7 +1227,6 @@ const handleReactionPress = useCallback((message: IChatMessage, emoji: string) =
|
|
|
928
1227
|
onSend={onSend}
|
|
929
1228
|
user={{ _id: CURRENT_USER_ID }}
|
|
930
1229
|
reactions={{
|
|
931
|
-
isEnabled: true,
|
|
932
1230
|
onReactionPress: handleReactionPress,
|
|
933
1231
|
// Optional: provide a richer picker (e.g. a full emoji browser).
|
|
934
1232
|
// See example/components/chat-examples/ReactionsExample.tsx
|
|
@@ -937,13 +1235,20 @@ const handleReactionPress = useCallback((message: IChatMessage, emoji: string) =
|
|
|
937
1235
|
/>
|
|
938
1236
|
```
|
|
939
1237
|
|
|
1238
|
+
`Chat.toggleReaction` (also exported as `toggleReaction`) returns a new array and leaves other messages untouched. A user can leave up to three different reactions on a message by default, as in Telegram - a fourth replaces their oldest; pass `{ maxPerUser: 1 }` as a fifth argument for one reaction each, or any other limit (`Infinity` for none).
|
|
1239
|
+
|
|
1240
|
+
For a prototype, `useChatMessages({ initialMessages, user })` keeps the messages in local state and returns `chatProps` wired to sending, reactions, editing and deleting: `<Chat {...chatProps} />`.
|
|
1241
|
+
|
|
940
1242
|
#### Reactions Props (Grouped)
|
|
941
1243
|
|
|
942
|
-
- **`isEnabled`** _(Bool)_ - Enable emoji reactions
|
|
1244
|
+
- **`isEnabled`** _(Bool)_ - Enable emoji reactions; default is on whenever `onReactionPress` is passed
|
|
943
1245
|
- **`emojis`** _(String[])_ - Emojis shown in the quick picker (default `['👍', '❤️', '😂', '😮', '😢', '👎']`)
|
|
944
|
-
- **`onReactionPress`** _(Function)_ - `(message, emoji) => void` called when an emoji is selected or a pill is tapped.
|
|
1246
|
+
- **`onReactionPress`** _(Function)_ - `(message, emoji) => void` called when an emoji is selected or a pill is tapped. Apply it with `Chat.toggleReaction`
|
|
1247
|
+
- **`getUser`** _(Function)_ - `(userId) => User | undefined`, who reacted. As in Telegram, a pill shows up to three reactors' avatars instead of a count in a one-to-one chat, and in a group while the message has three reactions or fewer, when every reactor is known. Defaults to the senders of the loaded messages (and you)
|
|
945
1248
|
- **`renderReactions`** _(Function)_ - Override the reactions-display component rendered below the bubble
|
|
946
|
-
- **`renderReactionPicker`** _(Function)_ - Override the picker shown on long-press (use for a full emoji browser)
|
|
1249
|
+
- **`renderReactionPicker`** _(Function)_ - Override the picker shown on long-press (use for a full emoji browser). It receives [`ReactionPickerProps`](src/Reactions/types.ts): `visible`, `message`, `emojis`, `onSelect`, `onDismiss`, `position`, the bubble's on-screen box (`pageX`, `pageY`, `bubbleWidth`, `bubbleHeight`), the two picker styles and:
|
|
1250
|
+
- **`messagePreview`** _(ReactNode, optional)_ - A copy of the pressed bubble to draw lifted above your backdrop at the bubble's box. While it is mounted the original bubble is hidden, so the message seems to rise out of the list; if you never render it, the original simply stays put. The easiest way to get the built-in look is to render the exported `ContextMenu` with `items={[]}` (see [Message actions](#message-actions-long-press-context-menu) for its props)
|
|
1251
|
+
- **`renderExpandedPicker`** _(Function(`{ onSelect }`) | null, optional)_ - The expand button. The reactions bar (in the quick picker and above the context menu) ends in a chevron that grows the bar in place into a panel holding what this returns. Defaults to the built-in emoji grid (8 columns, search, tabs, recents); pass your own, or `null` to drop the button. Call `onSelect(emoji)` with the pick; the overlay closes and `onReactionPress` is called. Also passed to a custom `renderReactionPicker`
|
|
947
1252
|
- **`containerStyle`**, **`reactionStyle`**, **`reactionActiveStyle`**, **`reactionTextStyle`**, **`reactionCountStyle`** - Styles for the reaction pills
|
|
948
1253
|
- **`pickerContainerStyle`**, **`pickerEmojiStyle`** - Styles for the quick picker
|
|
949
1254
|
|
|
@@ -982,9 +1287,34 @@ For full control, pass custom `matchers` (`{ type, pattern, getLinkUrl?, getLink
|
|
|
982
1287
|
### Message actions (long-press context menu)
|
|
983
1288
|
|
|
984
1289
|
<details>
|
|
985
|
-
<summary><strong>
|
|
1290
|
+
<summary><strong>Floating menu</strong></summary>
|
|
1291
|
+
|
|
1292
|
+
Long-press a message to open a context menu beside your finger. It opens by default with these actions: **Reply**, **Copy** (with `expo-clipboard` or `@react-native-clipboard/clipboard` installed), **Forward**, **Pin / Unpin**, **Edit** (your own text messages), **Select** and **Delete** - Forward, Pin, Edit and Delete appear once you pass `onForwardMessage`, `onPinMessage`, `onEditMessage` and `onDeleteMessage`. **Select** starts multi-select: check circles beside the messages and a Copy / Forward / Delete bar in the composer's place (see `onSelectionChange`). When reactions are enabled, a reactions row is shown on top of the menu automatically.
|
|
1293
|
+
|
|
1294
|
+
```tsx
|
|
1295
|
+
<Chat
|
|
1296
|
+
messages={messages}
|
|
1297
|
+
onSend={onSend}
|
|
1298
|
+
user={user}
|
|
1299
|
+
onEditMessage={(message, text) => setMessages(prev => prev.map(m => m._id === message._id ? { ...m, text } : m))}
|
|
1300
|
+
onDeleteMessage={message => setMessages(prev => prev.filter(m => m._id !== message._id))}
|
|
1301
|
+
/>
|
|
1302
|
+
```
|
|
986
1303
|
|
|
987
|
-
|
|
1304
|
+
To change the set, pass `messageActions`. A function receives the built-in actions for the message (each with its `key`), so you can add, drop or reorder; an array replaces them. `defaultMessageActions` picks the built-ins by key, or turns them off with `false`.
|
|
1305
|
+
|
|
1306
|
+
```tsx
|
|
1307
|
+
<Chat
|
|
1308
|
+
messageActions={(message, defaults) => [
|
|
1309
|
+
...defaults.filter(action => action.key !== 'forward'),
|
|
1310
|
+
{ label: 'Report', icon: ({ color, size }) => <Flag color={color} size={size} />, onPress: () => report(message) },
|
|
1311
|
+
]}
|
|
1312
|
+
/>
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
After 0.4s the menu opens with a haptic (if `expo-haptics` is installed). The message neither shrinks nor lifts - the chat dims under a black 0.2 scrim and the pressed message stays lit where it is. The menu - a 200-wide card of 48pt rows with icons, in `theme.contextMenu` colors - opens with its right edge just left of your finger and its top at it, unrolling from the top while each row drops into place. The reactions bar above it pops out from its right end with a slight overshoot, with a "thought bubble" tail; reactions you already picked sit smaller in a circle, and the chevron at its end grows the bar into the emoji panel. A picked reaction grows and flies into the message's reaction pill; an action runs once the menu has closed; a tap on the backdrop closes it all. Every animation runs on Reanimated and follows the system Reduce Motion setting. The reaction-only picker (`reactions` without `messageActions`) is the same overlay without actions.
|
|
1316
|
+
|
|
1317
|
+
A fully custom menu - each item is `{ key?, label, icon?, onPress, destructive? }`:
|
|
988
1318
|
|
|
989
1319
|
```tsx
|
|
990
1320
|
import { setStringAsync } from 'expo-clipboard'
|
|
@@ -993,11 +1323,18 @@ import { Copy, Trash2 } from 'lucide-react-native' // optional icons
|
|
|
993
1323
|
<Chat
|
|
994
1324
|
messageActions={message => [
|
|
995
1325
|
{ label: 'Copy', icon: ({ color, size }) => <Copy color={color} size={size} />, onPress: () => setStringAsync(message.text) },
|
|
996
|
-
{ label: 'Delete', destructive: true, onPress: () => deleteMessage(message) },
|
|
1326
|
+
{ label: 'Delete', icon: ({ color, size }) => <Trash2 color={color} size={size} />, destructive: true, onPress: () => deleteMessage(message) },
|
|
997
1327
|
]}
|
|
998
1328
|
/>
|
|
999
1329
|
```
|
|
1000
1330
|
|
|
1331
|
+
`ContextMenu` is exported for custom pickers and menus. Beyond `visible`, `items`, `onDismiss` (called once its exit has played), `position` and the bubble's box (`pageX`, `pageY`, `bubbleWidth`, `bubbleHeight`), it takes these optional props:
|
|
1332
|
+
|
|
1333
|
+
- **`reactions`** _(Object)_ - `{ emojis, onSelect, selected?, containerStyle?, emojiStyle?, renderAccessory?, renderExpandedPicker? }`. `selected` lists the reactions the user already picked (drawn smaller, in a circle); `renderAccessory` adds content at the end of the bar; `renderExpandedPicker` adds the expand button and the panel it opens (see `reactions.renderExpandedPicker` above)
|
|
1334
|
+
- **`touchX`**, **`touchY`** _(Number)_ - Where the finger was, in window coordinates; the menu opens beside it (beside the bubble's middle without them)
|
|
1335
|
+
- **`messagePreview`** _(ReactNode)_ - The copy of the message drawn above the scrim in place; pass the one a custom picker receives
|
|
1336
|
+
- **`children`** _(ReactNode)_ - Drawn above everything else in the overlay, e.g. a full emoji sheet
|
|
1337
|
+
|
|
1001
1338
|
> **Note:** This library no longer depends on `@expo/react-native-action-sheet`. Prefer `messageActions` above. If you specifically want a native action sheet, install it yourself, wrap your tree in `ActionSheetProvider`, and either call `useActionSheet()` in your own `onLongPressMessage` or pass an `actionSheet` prop - the `actionSheet` prop / `context.actionSheet()` escape hatch still works when you provide an implementation. The composer "+" actions use the built-in themed `AttachmentSheet` and need no setup.
|
|
1002
1339
|
|
|
1003
1340
|
</details>
|
|
@@ -1007,7 +1344,7 @@ import { Copy, Trash2 } from 'lucide-react-native' // optional icons
|
|
|
1007
1344
|
<details>
|
|
1008
1345
|
<summary><strong>Keeping native controls tappable</strong></summary>
|
|
1009
1346
|
|
|
1010
|
-
When `reactions` or `messageActions` are enabled, the long-press surface spans the **whole message row** - the bubble *and* the empty space beside it
|
|
1347
|
+
When `reactions` or `messageActions` are enabled, the long-press surface spans the **whole message row** - the bubble *and* the empty space beside it. (A tap gesture is added on top only when `onPressMessage` is set.) Those recognizers do not cancel touches on native subviews, so a `react-native-video` / `expo-video` player rendered through `renderMessageVideo` keeps its native `controls` interactive.
|
|
1011
1348
|
|
|
1012
1349
|
If a message must own every touch that lands on it, set `isMessageGestureEnabled` to `false` for it. The gesture surface then drops *behind* the bubble: the bubble's content takes its touches, and long-pressing the row next to the bubble still opens the picker - so reactions are never lost for that message.
|
|
1013
1350
|
|
|
@@ -1027,21 +1364,31 @@ If a message must own every touch that lands on it, set `isMessageGestureEnabled
|
|
|
1027
1364
|
<details>
|
|
1028
1365
|
<summary><strong>Token groups, runtime switching and themed components</strong></summary>
|
|
1029
1366
|
|
|
1030
|
-
The
|
|
1367
|
+
The default look is a modern messenger style: a classic day theme (pale green outgoing bubbles over a green swirl wallpaper) and a dark blue night theme (a purple-to-blue outgoing gradient fixed to the screen). Every value is a token. Override any subset via `theme` (light) and `darkTheme` (dark); your overrides are deep-merged over `defaultLightTheme` / `defaultDarkTheme`, and the resolved theme switches at runtime with the color scheme (system, or forced via `colorScheme`). Explicit per-component style props still win over the theme.
|
|
1031
1368
|
|
|
1032
1369
|
```tsx
|
|
1033
1370
|
<Chat
|
|
1034
1371
|
theme={{
|
|
1035
|
-
colors: { accent: '#3390EC', outgoingBubble: '#
|
|
1372
|
+
colors: { accent: '#3390EC', outgoingBubble: '#3390EC', outgoingText: '#FFFFFF' },
|
|
1036
1373
|
radii: { bubble: 18 },
|
|
1374
|
+
wallpaper: { colors: ['#7FA381', '#FFF5C5', '#336F55', '#FBE37D'] },
|
|
1037
1375
|
}}
|
|
1038
|
-
darkTheme={{
|
|
1376
|
+
darkTheme={{ bubble: { outgoingGradient: ['#5B3FA8', '#2F6FD6'] } }}
|
|
1039
1377
|
// colorScheme="dark" // optional: force a scheme instead of following the system
|
|
1040
1378
|
{...props}
|
|
1041
1379
|
/>
|
|
1042
1380
|
```
|
|
1043
1381
|
|
|
1044
|
-
Token groups: `colors`, `radii`, `spacing`, `typography`, `avatar`, `sendButton`, `composer`, `voice
|
|
1382
|
+
Token groups: `colors`, `radii`, `spacing`, `typography`, `avatar`, `sendButton`, `composer`, `voice`, plus:
|
|
1383
|
+
|
|
1384
|
+
- **`bubble`** - `hasTail` (a curled tail on the last bubble of a run; drawn with `react-native-svg` when installed), `isTimeInline` (the time on the last line of text when it fits; `false` gives it a row), `outgoingGradient` (stops, top to bottom, or `null` for the solid `colors.outgoingBubble`), `outgoingGradientMode` (`'screen'`: one gradient across the list, each bubble shows its slice as it scrolls; `'bubble'`: each bubble carries the whole gradient), `maxWidthInset` (the text column is `min(width, height) - maxWidthInset`, 80 by default), `bigEmojiMaxCount` (a message of up to this many emoji and nothing else drops its bubble and draws them large, with the time in a service pill; 20 by default, `0` turns it off), `bigEmojiSizes` (font size by emoji count, `40.8, 40.8, 33.6, 26.4, 22.8`).
|
|
1385
|
+
- **`wallpaper`** - `isEnabled`, `colors` (three or four, for the swirl gradient), `isAnimated` (one step per outgoing message), `pattern` (an image tiled over the gradient; no pattern is bundled), `patternOpacity`, `patternColor`. Off, the chat shows `colors.background`. Replace it entirely with the `renderWallpaper` prop, or draw it elsewhere with the exported `ChatWallpaper` component.
|
|
1386
|
+
- **`nameColors`** - the seven sender-name colors, picked per user id. Empty uses `colors.senderName`.
|
|
1387
|
+
- **`avatar.palette` / `avatar.paletteEnd`** - initials avatar gradient stops, picked per user id. An empty `paletteEnd` draws flat colors.
|
|
1388
|
+
|
|
1389
|
+
A few behaviours follow from the tokens: setting `colors.outgoingBubble` turns the gradient off, setting `colors.senderName` empties `nameColors`, and setting `avatar.palette` without `paletteEnd` draws flat avatars - so an app that picks its own colors keeps seeing them. Bubbles in a run (same sender, at most five minutes apart, `utils.isSameGroup`) share one tail and one name, 2pt apart (`spacing.withinGroup`), with 6pt between runs (`spacing.betweenGroups`).
|
|
1390
|
+
|
|
1391
|
+
Build your own theme-aware components with the exported hooks:
|
|
1045
1392
|
|
|
1046
1393
|
```tsx
|
|
1047
1394
|
import { useTheme, useThemedStyles } from '@kesha-antonov/react-native-chat'
|
|
@@ -1056,7 +1403,9 @@ const MyBadge = () => {
|
|
|
1056
1403
|
}
|
|
1057
1404
|
```
|
|
1058
1405
|
|
|
1059
|
-
Also exported: `defaultLightTheme`, `defaultDarkTheme`, and the `ChatTheme` / `PartialChatTheme` types.
|
|
1406
|
+
Also exported: `defaultLightTheme`, `defaultDarkTheme`, `ChatWallpaper`, and the `ChatTheme` / `PartialChatTheme` types.
|
|
1407
|
+
|
|
1408
|
+
The built-in panels have their own token groups: `emojiKeyboard`, `contextMenu`, `attachments` and `chatList`. The full set of tokens and their default values is the `ChatTheme` type and `defaultLightTheme` / `defaultDarkTheme`.
|
|
1060
1409
|
|
|
1061
1410
|
</details>
|
|
1062
1411
|
|
|
@@ -1075,6 +1424,8 @@ All built-in UI strings (composer placeholder, send/cancel, load earlier, today,
|
|
|
1075
1424
|
/>
|
|
1076
1425
|
```
|
|
1077
1426
|
|
|
1427
|
+
Right-to-left layout follows the locale (Arabic, Hebrew, Persian, Urdu and a few others). `forceRTL` overrides the guess: `true` for an RTL language not in that set, `false` to keep a left-to-right layout.
|
|
1428
|
+
|
|
1078
1429
|
Exported helpers: `ChatLabels` (type), `defaultLabels`, `translations`, `resolveLabels`, and the `useLabels` hook for reading the resolved labels in custom components.
|
|
1079
1430
|
|
|
1080
1431
|
</details>
|
|
@@ -1084,7 +1435,7 @@ Exported helpers: `ChatLabels` (type), `defaultLabels`, `translations`, `resolve
|
|
|
1084
1435
|
<details>
|
|
1085
1436
|
<summary><strong>Tick indicators for sent / delivered / read</strong></summary>
|
|
1086
1437
|
|
|
1087
|
-
Set `sent`, `received`, or `
|
|
1438
|
+
Set `sent`, `received`, `pending` or `isFailed` on a message to show its delivery status. The status is yours to set: add a message with `pending: true` in `onSend`, then set `sent` and `received` as your backend confirms. Every outgoing message shows it, voice notes, round notes, files and photos included. They render beside the time: one check once sent, two once received (read), a spinning clock while pending, a red badge when sending failed. `isEdited` or `editedAt` prefix the time with "edited":
|
|
1088
1439
|
|
|
1089
1440
|
```tsx
|
|
1090
1441
|
const message: IMessage = {
|
|
@@ -1131,6 +1482,25 @@ interface MyMessage extends IMessage {
|
|
|
1131
1482
|
|
|
1132
1483
|
</details>
|
|
1133
1484
|
|
|
1485
|
+
### Building blocks
|
|
1486
|
+
|
|
1487
|
+
<details>
|
|
1488
|
+
<summary><strong>Lower-level components and helpers</strong></summary>
|
|
1489
|
+
|
|
1490
|
+
`Chat` is assembled from exported parts, so you can reuse them in your own screens or render props:
|
|
1491
|
+
|
|
1492
|
+
- **Rows and bubbles**: `Message`, `Bubble`, `MessageText`, `MessageImage`, `MessageVideo`, `MessageAudio`, `MessageFile`, `MessageLocation`, `MessageReply`, `SystemMessage`, `Day`, `Time`, `Avatar`, `ChatAvatar`, `UnreadSeparator`, `ChatEmpty`, `LinkPreviewCard`, `MediaCard`
|
|
1493
|
+
- **Composer**: `InputToolbar`, `Composer`, `Send`, `Actions`, `ReplyPreview`, `EmojiGrid`, `AttachmentMenu`, `AttachmentSheet`
|
|
1494
|
+
- **Voice and video**: `VoiceMessageInput`, `WaveformPlayer`, `VideoRecordButton`, `VideoNoteRecorder`, with `isVoiceRecordingAvailable`, `isWaveformAvailable`, `isVideoRecordingAvailable`, `isVisionCameraAvailable`
|
|
1495
|
+
- **Menus and status**: `ContextMenu`, `TypingStatus` (`getTypingText`), `StreamingCursor`, `MarkdownMessageText` (`isMarkdownAvailable`), `BasicMarkdown`
|
|
1496
|
+
- **Lists**: `MessagesContainer`, `ChatList`, `ChatListCell`, `ChatListAvatar`, `ChatListShimmer`
|
|
1497
|
+
- **Hooks**: `useTheme`, `useThemedStyles`, `useColorScheme`, `useIcons`, `useLabels`, `useIsRTL`, `useChatContext`, `useStreamingMessages`, `useChatMessages`, `useChatList`
|
|
1498
|
+
- **Helpers**: `toggleReaction`, `getChatCapabilities`, `buildAttachmentMessages`, `getAttachmentTabs`, `formatFileSize`, `findFirstUrl`, `countEmojiOnly`, `isRTLLocale`, `mirrorPosition`, `formatChatListDate`, `getChatPreview`, `sortChats`, `matchesChatQuery`, `DEFAULT_MESSAGE_ACTION_KEYS`, `EMOJI_CATEGORY_KEYS`, `DEFAULT_RECENT_EMOJIS`
|
|
1499
|
+
|
|
1500
|
+
Components rendered outside `Chat` need a `GestureHandlerRootView` above them.
|
|
1501
|
+
|
|
1502
|
+
</details>
|
|
1503
|
+
|
|
1134
1504
|
---
|
|
1135
1505
|
|
|
1136
1506
|
## 📱 Platform Notes
|
|
@@ -1226,76 +1596,36 @@ Three things to know:
|
|
|
1226
1596
|
|
|
1227
1597
|
## ⚡ Performance
|
|
1228
1598
|
|
|
1229
|
-
|
|
1599
|
+
A message re-renders only when something it shows changes. Each row subscribes to its own message by id, so a send, a status tick, a reaction or a streamed token renders that one row (plus a neighbour only when the bubbles' grouping changes) and leaves the list and the composer alone. Everything the rows share - render props, styles, actions, labels - reaches them through context, kept stable between renders:
|
|
1230
1600
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1601
|
+
- **Event handlers can be inline.** `onPressMessage={() => ...}`, `reply={{ onPress: ... }}`, an action's `onPress`: they are called through a stable proxy that always reaches your latest handler.
|
|
1602
|
+
- **Style and config objects can be inline.** `timeTextStyle={{ left: { color } }}`, `reactions={{ isEnabled: true }}` are compared by content.
|
|
1603
|
+
- **Memoize render functions.** A new `renderBubble` may draw something new, so a new reference re-renders every row - wrap it in `useCallback`.
|
|
1234
1604
|
|
|
1235
|
-
|
|
1605
|
+
```jsx
|
|
1606
|
+
// ✅ Handlers and objects inline; the render function memoized
|
|
1236
1607
|
const renderBubble = useCallback(props => <MyBubble {...props} />, [])
|
|
1237
|
-
const reactions = useMemo(() => ({ isEnabled: true, onReactionPress }), [onReactionPress])
|
|
1238
1608
|
|
|
1239
|
-
<Chat renderBubble={renderBubble}
|
|
1609
|
+
<Chat renderBubble={renderBubble} onPressMessage={message => open(message)} timeTextStyle={{ left: { color: 'gray' } }} />
|
|
1240
1610
|
```
|
|
1241
1611
|
|
|
1242
1612
|
<details>
|
|
1243
|
-
<summary><strong>
|
|
1613
|
+
<summary><strong>Messages, neighbours, context props and virtualization tuning</strong></summary>
|
|
1244
1614
|
|
|
1245
|
-
|
|
1615
|
+
**Keep messages immutable.** Update a message by replacing its object (e.g. `Chat.append(...)`, or `messages.map(m => m._id === id ? { ...m, sent: true } : m)`), never by mutating it in place. A store that rebuilds every message object on each update still only re-renders what changed - unchanged messages are compared by content.
|
|
1246
1616
|
|
|
1247
|
-
**
|
|
1617
|
+
**Neighbours are for grouping.** `previousMessage` / `nextMessage` handed to `renderMessage`, `renderBubble` or `renderAvatar` are kept current for what decides grouping (sender, day, time apart, whether there is one). A row does not re-render because a neighbour's text, status or reactions changed, so do not draw those from a neighbour.
|
|
1248
1618
|
|
|
1249
1619
|
**Theme, icons and labels don't need drilling.** `theme` / `darkTheme`, `icons`, and `labels` are read from context (`useTheme`, `useIcons`, `useLabels`), so passing them once on `<Chat>` is enough; they don't cause per-row churn.
|
|
1250
1620
|
|
|
1251
|
-
**Tune virtualization if needed.**
|
|
1621
|
+
**Tune virtualization if needed.** The list is [Legend List](https://legendapp.com/open-source/list/), which keeps only what is near the viewport mounted. `drawDistance` (in pixels) sets how far beyond the screen it renders; raise it if fast flings show blank space, lower it to mount less. Leave `recycleItems` off: message rows hold state (players, animations) that must not move to another message.
|
|
1252
1622
|
|
|
1253
1623
|
```jsx
|
|
1254
|
-
<Chat listProps={{
|
|
1624
|
+
<Chat listProps={{ drawDistance: 500 }} {...props} />
|
|
1255
1625
|
```
|
|
1256
1626
|
|
|
1257
1627
|
</details>
|
|
1258
1628
|
|
|
1259
|
-
### FlashList (opt-in)
|
|
1260
|
-
|
|
1261
|
-
<details>
|
|
1262
|
-
<summary><strong>Recycling rows on very long histories</strong></summary>
|
|
1263
|
-
|
|
1264
|
-
On long histories `FlatList` can log `VirtualizedList: You have a large list that is slow to update`. [FlashList](https://shopify.github.io/flash-list/) v2 recycles rows instead of keeping them mounted, which removes that class of stall. It is supported as an **optional** dependency - install it yourself and flip one prop:
|
|
1265
|
-
|
|
1266
|
-
```bash
|
|
1267
|
-
yarn add @shopify/flash-list
|
|
1268
|
-
```
|
|
1269
|
-
|
|
1270
|
-
```jsx
|
|
1271
|
-
<Chat messages={messages} user={user} isFlashListEnabled />
|
|
1272
|
-
```
|
|
1273
|
-
|
|
1274
|
-
Everything else keeps working: `isInverted`, the floating day header, `loadEarlierMessagesProps` infinite scroll, the scroll-to-bottom button, and `listProps` (spread last, so it overrides the defaults below).
|
|
1275
|
-
|
|
1276
|
-
The chat sets FlashList's `maintainVisibleContentPosition` for you - `startRenderingFromBottom` when `isInverted={false}`, plus `autoscrollToBottomThreshold: 0.2` so new messages follow the viewport only when you are already at the bottom. Override it through `listProps` if you want different thresholds:
|
|
1277
|
-
|
|
1278
|
-
```jsx
|
|
1279
|
-
<Chat
|
|
1280
|
-
isFlashListEnabled
|
|
1281
|
-
listProps={{
|
|
1282
|
-
maintainVisibleContentPosition: {
|
|
1283
|
-
autoscrollToBottomThreshold: 0.1,
|
|
1284
|
-
animateAutoScrollToBottom: false,
|
|
1285
|
-
},
|
|
1286
|
-
}}
|
|
1287
|
-
{...props}
|
|
1288
|
-
/>
|
|
1289
|
-
```
|
|
1290
|
-
|
|
1291
|
-
Notes:
|
|
1292
|
-
|
|
1293
|
-
- FlashList v2 requires the **New Architecture**. On the old architecture it falls back to a slower JS path.
|
|
1294
|
-
- `FlatList`-only knobs (`windowSize`, `maxToRenderPerBatch`, `initialNumToRender`, `updateCellsBatchingPeriod`, `removeClippedSubviews`) are not forwarded to FlashList - it sizes its own render window.
|
|
1295
|
-
- If `@shopify/flash-list` is not installed, the prop is ignored, a warning is logged, and `FlatList` is used.
|
|
1296
|
-
|
|
1297
|
-
</details>
|
|
1298
|
-
|
|
1299
1629
|
---
|
|
1300
1630
|
|
|
1301
1631
|
## 🧪 Testing
|
|
@@ -1331,7 +1661,7 @@ fireEvent(loadingWrapper, 'layout', {
|
|
|
1331
1661
|
<details>
|
|
1332
1662
|
<summary><strong>Running the demo locally</strong></summary>
|
|
1333
1663
|
|
|
1334
|
-
The repository includes
|
|
1664
|
+
The repository includes an example app with two parts. The **Chats** tab is a small messenger built on the defaults: a chat list (unread badges, pinned and muted chats, "typing…" previews, swipe to archive, long-press selection, a compose button) where each chat is a bare `<Chat>` with seeded history, and sending moves the chat to the top and gets a simulated reply. The **Explore** tab has one screen per feature or customization: streaming AI replies, reactions, the long-press menu, media and voice, theming, localization, links, custom rendering, a Slack-style layout, and more.
|
|
1335
1665
|
|
|
1336
1666
|
```bash
|
|
1337
1667
|
git clone https://github.com/kesha-antonov/react-native-chat.git
|
|
@@ -1349,6 +1679,28 @@ npx expo start --web # Web
|
|
|
1349
1679
|
|
|
1350
1680
|
## ❓ Troubleshooting
|
|
1351
1681
|
|
|
1682
|
+
<details>
|
|
1683
|
+
<summary><strong>"Cannot read property 'Chat' of undefined"</strong></summary>
|
|
1684
|
+
|
|
1685
|
+
This means the package threw while it was being loaded, so the import came back empty. The real cause is the **first** error in the Metro log or red box, logged before this one - almost always a native peer that is missing or out of sync with the installed app:
|
|
1686
|
+
|
|
1687
|
+
- `react-native-reanimated`, `react-native-worklets`, `react-native-gesture-handler` and `react-native-keyboard-controller` are native modules. After installing or upgrading any of them, rebuild the app (`npx expo run:ios`, `npx expo prebuild`, or `pod install` + a native build) - reloading the JS bundle is not enough.
|
|
1688
|
+
- In Expo, install them with `npx expo install` so the versions match your SDK. A plain `npm install` pulls the latest releases, which Expo Go and an existing dev build may not include, and Reanimated throws a version-mismatch error on import.
|
|
1689
|
+
- In bare React Native, check the worklets Babel plugin is in `babel.config.js` (see [Bare React Native Projects](#bare-react-native-projects)), then restart Metro with `--reset-cache`.
|
|
1690
|
+
|
|
1691
|
+
</details>
|
|
1692
|
+
|
|
1693
|
+
<details>
|
|
1694
|
+
<summary><strong>The whole message list is blurred on iOS 26</strong></summary>
|
|
1695
|
+
|
|
1696
|
+
The chat sits under a transparent navigation header - Expo Router 58's default is a transparent Liquid Glass header the screen scrolls under. iOS 26 then blurs scroll content beneath the header with a scroll edge effect, so the messages under the header are blurred. Give the chat screen an opaque header:
|
|
1697
|
+
|
|
1698
|
+
```tsx
|
|
1699
|
+
<Stack.Screen name='chat' options={{ headerTransparent: false }} />
|
|
1700
|
+
```
|
|
1701
|
+
|
|
1702
|
+
</details>
|
|
1703
|
+
|
|
1352
1704
|
<details>
|
|
1353
1705
|
<summary><strong>TextInput is hidden on Android</strong></summary>
|
|
1354
1706
|
|
|
@@ -1424,6 +1776,8 @@ Based on [FaridSafi/react-native-gifted-chat](https://github.com/FaridSafi/react
|
|
|
1424
1776
|
|
|
1425
1777
|
**Maintainer:** [Kesha Antonov](https://github.com/kesha-antonov)
|
|
1426
1778
|
|
|
1779
|
+
I also build **[cryptoc](https://cryptoc-app.web.app/)** - a crypto portfolio app with home screen, lock screen and Watch widgets, no account and no exchange API keys.
|
|
1780
|
+
|
|
1427
1781
|
> I maintained the original project solo for 2 years before deciding to continue development in this repository. If you find this library useful, please consider [becoming a sponsor](https://github.com/sponsors/kesha-antonov) to support continued development. 💖
|
|
1428
1782
|
|
|
1429
1783
|
---
|