@kesha-antonov/react-native-chat 5.0.1 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +486 -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 -13
- package/lib/Bubble/index.d.ts.map +1 -1
- package/lib/Bubble/index.js +379 -509
- 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 -161
- 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 +289 -119
- 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 +153 -51
- 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.js +318 -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">
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<img width="300" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/
|
|
19
|
+
<img width="300" src="https://raw.githubusercontent.com/kesha-antonov/react-native-chat/main/media/showcase.gif" alt="Chat list, photo viewer, reactions, swipe-to-reply, emoji keyboard, photo attachments, a voice note, a streamed AI reply and swipe-to-archive" />
|
|
20
20
|
</p>
|
|
21
21
|
|
|
22
22
|
<p align="center">
|
|
@@ -44,6 +44,17 @@
|
|
|
44
44
|
<sub>Using it in production? A ⭐ helps other developers find the library.</sub>
|
|
45
45
|
</p>
|
|
46
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
|
+
|
|
47
58
|
<hr />
|
|
48
59
|
|
|
49
60
|
<table align="center">
|
|
@@ -55,8 +66,10 @@
|
|
|
55
66
|
<br />
|
|
56
67
|
<sub>Scan to install</sub>
|
|
57
68
|
<br /><br />
|
|
69
|
+
<!-- App Store button hidden for now
|
|
58
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>
|
|
59
71
|
<br />
|
|
72
|
+
-->
|
|
60
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>
|
|
61
74
|
</td>
|
|
62
75
|
<td valign="top">
|
|
@@ -78,6 +91,7 @@
|
|
|
78
91
|
</table>
|
|
79
92
|
|
|
80
93
|
<hr />
|
|
94
|
+
<!-- cryptoc-promo:end -->
|
|
81
95
|
|
|
82
96
|
## Quick start
|
|
83
97
|
|
|
@@ -113,14 +127,23 @@ That is the whole setup - everything below is optional.
|
|
|
113
127
|
|
|
114
128
|
## ✨ Features
|
|
115
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
|
|
116
131
|
- 🌗 **[Dark mode & theming](#theming--dark-mode)** - full light/dark token system, switchable at runtime
|
|
117
132
|
- 🤖 **[Streaming AI messages](#streaming-ai-messages)** - token-by-token replies with a typing caret and stop control
|
|
118
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
|
|
119
136
|
- 🎥 **[Video & audio messages](#-whats-new-vs-react-native-gifted-chat)** - real inline playback, with a tappable fallback
|
|
120
|
-
-
|
|
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
|
|
121
144
|
- 📍 **[Location messages](#-whats-new-vs-react-native-gifted-chat)** - map card that opens the system maps app
|
|
122
145
|
- ↩️ **[Swipe to reply](#reply-to-messages)** - reply preview and message threading
|
|
123
|
-
- 📋 **[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
|
|
124
147
|
- ⚡ **[Quick replies](#quick-replies)** - bot-style reply buttons
|
|
125
148
|
- 🔗 **[Smart link parsing](#smart-link-parsing)** - URLs, emails, phones, hashtags, mentions
|
|
126
149
|
- 👤 **[Avatars](#avatars)** - user initials or custom images
|
|
@@ -138,11 +161,23 @@ That is the whole setup - everything below is optional.
|
|
|
138
161
|
Actively maintained, New Architecture ready, built for the latest Reanimated / Gesture Handler.
|
|
139
162
|
|
|
140
163
|
<p align="center">
|
|
141
|
-
<img width="200" src="https://
|
|
142
|
-
 
|
|
143
|
-
<img width="200" src="https://
|
|
144
|
-
 
|
|
145
|
-
<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" />
|
|
146
181
|
</p>
|
|
147
182
|
|
|
148
183
|
---
|
|
@@ -157,16 +192,19 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
157
192
|
| Added in this fork | react-native-gifted-chat | @kesha-antonov/react-native-chat |
|
|
158
193
|
| --- | :---: | :---: |
|
|
159
194
|
| Active maintenance | 💤 sporadic | ✅ active |
|
|
160
|
-
| Modern default UI (
|
|
195
|
+
| Modern default UI (modern messenger look) | dated 2020 look | ✅ wallpaper, tails, inline time, fully overridable |
|
|
161
196
|
| Light/Dark **theme system** | per-component color props | ✅ `theme` / `darkTheme` tokens, runtime switch |
|
|
162
197
|
| Streaming (AI) messages | ❌ | ✅ token-by-token + typing cursor |
|
|
163
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 |
|
|
164
202
|
| Swipe-to-reply + reply preview | ❌ | ✅ built in |
|
|
165
203
|
| **Video / audio messages** | "not implemented, render your own" | ✅ inline players + tappable fallback |
|
|
166
|
-
| **Voice notes** (hold-to-record + waveform) | ❌ | ✅ optional
|
|
167
|
-
| **Video messages** (round camera notes) | ❌ | ✅ optional
|
|
204
|
+
| **Voice notes** (hold-to-record + waveform) | ❌ | ✅ optional |
|
|
205
|
+
| **Video messages** (round camera notes) | ❌ | ✅ optional |
|
|
168
206
|
| **Location messages** | ❌ ignored | ✅ map card → opens system maps |
|
|
169
|
-
| Bubble tails +
|
|
207
|
+
| Bubble tails, inline time + run grouping | flat bubbles | ✅ |
|
|
170
208
|
|
|
171
209
|
</details>
|
|
172
210
|
|
|
@@ -189,12 +227,14 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
189
227
|
### Voice, video and location
|
|
190
228
|
|
|
191
229
|
<details>
|
|
192
|
-
<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.
|
|
193
233
|
|
|
194
234
|
```jsx
|
|
195
235
|
<Chat
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
198
238
|
// location messages render automatically for any IMessage with a `location`
|
|
199
239
|
{...props}
|
|
200
240
|
/>
|
|
@@ -203,8 +243,82 @@ Kept in sync with upstream [`react-native-gifted-chat`](https://github.com/Farid
|
|
|
203
243
|
```bash
|
|
204
244
|
# Optional inline media playback + recording:
|
|
205
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
|
|
251
|
+
```
|
|
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
|
+
]
|
|
206
310
|
```
|
|
207
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
|
+
|
|
208
322
|
</details>
|
|
209
323
|
|
|
210
324
|
### Custom icons (e.g. Lucide)
|
|
@@ -260,6 +374,7 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
260
374
|
- [Data Structure](#-data-structure)
|
|
261
375
|
- [Props Reference](#-props-reference)
|
|
262
376
|
- [Guides](#-guides)
|
|
377
|
+
- [Chat List](#chat-list)
|
|
263
378
|
- [Reply to Messages](#reply-to-messages)
|
|
264
379
|
- [Maintaining Scroll Position (AI Chatbots)](#maintaining-scroll-position-ai-chatbots)
|
|
265
380
|
- [Streaming (AI) Messages](#streaming-ai-messages)
|
|
@@ -270,6 +385,7 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
270
385
|
- [Localization (i18n)](#localization-i18n)
|
|
271
386
|
- [Message Status](#message-status)
|
|
272
387
|
- [TypeScript](#typescript)
|
|
388
|
+
- [Building blocks](#building-blocks)
|
|
273
389
|
- [Platform Notes](#-platform-notes)
|
|
274
390
|
- [Performance](#-performance)
|
|
275
391
|
- [Testing](#-testing)
|
|
@@ -283,9 +399,11 @@ Overridable names: `send`, `mic`, `camera`, `play`, `pause`, `check`, `checkAll`
|
|
|
283
399
|
|
|
284
400
|
## 📋 Requirements
|
|
285
401
|
|
|
286
|
-
| React Native | iOS | Android | Expo | TypeScript |
|
|
287
|
-
|
|
288
|
-
| >= 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.
|
|
289
407
|
|
|
290
408
|
---
|
|
291
409
|
|
|
@@ -302,26 +420,51 @@ npx expo install @kesha-antonov/react-native-chat react-native-reanimated react-
|
|
|
302
420
|
<details>
|
|
303
421
|
<summary><strong>Three steps</strong></summary>
|
|
304
422
|
|
|
305
|
-
**1.** Install the packages:
|
|
423
|
+
**1.** Install the packages. Reanimated 4 also needs `react-native-worklets`; leave it out on Reanimated 3:
|
|
306
424
|
|
|
307
425
|
```bash
|
|
308
|
-
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
|
|
309
427
|
```
|
|
310
428
|
|
|
311
429
|
```bash
|
|
312
|
-
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
|
|
313
431
|
```
|
|
314
432
|
|
|
315
|
-
**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:
|
|
316
436
|
|
|
317
437
|
```bash
|
|
318
438
|
npx pod-install
|
|
319
439
|
```
|
|
320
440
|
|
|
321
|
-
**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).
|
|
322
|
-
|
|
323
441
|
</details>
|
|
324
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
|
+
|
|
325
468
|
---
|
|
326
469
|
|
|
327
470
|
## 🔄 Migrating from react-native-gifted-chat
|
|
@@ -370,14 +513,37 @@ interface IMessage {
|
|
|
370
513
|
createdAt: Date | number
|
|
371
514
|
user: User
|
|
372
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
|
|
373
518
|
video?: string
|
|
519
|
+
/** Render `video` as a round video note */
|
|
520
|
+
videoNote?: boolean
|
|
374
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
|
|
375
530
|
system?: boolean
|
|
376
531
|
sent?: boolean
|
|
377
532
|
received?: boolean
|
|
378
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
|
|
379
539
|
/** True while the text is still streaming in (shows a typing cursor) */
|
|
380
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[]
|
|
381
547
|
quickReplies?: QuickReplies
|
|
382
548
|
replyMessage?: ReplyMessage
|
|
383
549
|
reactions?: MessageReaction[]
|
|
@@ -385,6 +551,24 @@ interface IMessage {
|
|
|
385
551
|
latitude: number
|
|
386
552
|
longitude: number
|
|
387
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
|
|
388
572
|
}
|
|
389
573
|
|
|
390
574
|
interface ReplyMessage {
|
|
@@ -426,14 +610,15 @@ Every group below is collapsed - open the one you need.
|
|
|
426
610
|
- **`messageIdGenerator`** _(Function)_ - Generate an id for new messages. Defaults to a simple random string generator.
|
|
427
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'`)
|
|
428
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`.
|
|
429
|
-
- **`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`.
|
|
430
615
|
- **`darkTheme`** _(Object)_ - Same as `theme`, applied when the resolved color scheme is dark (deep-merged over `defaultDarkTheme`).
|
|
431
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).
|
|
432
617
|
- **`labels`** _(Object)_ - Override any UI string. See [Localization (i18n)](#localization-i18n).
|
|
433
618
|
|
|
434
619
|
### Refs
|
|
435
620
|
|
|
436
|
-
- **`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
|
|
437
622
|
- **`textInputRef`** _(TextInput ref)_ - Ref to the text input
|
|
438
623
|
|
|
439
624
|
</details>
|
|
@@ -449,7 +634,7 @@ Every group below is collapsed - open the one you need.
|
|
|
449
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.
|
|
450
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)).
|
|
451
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.
|
|
452
|
-
- **`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.
|
|
453
638
|
- **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
|
|
454
639
|
|
|
455
640
|
#### Understanding `keyboardVerticalOffset`
|
|
@@ -477,6 +662,7 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
477
662
|
|
|
478
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.
|
|
479
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`
|
|
480
666
|
- **`isSendButtonAlwaysVisible`** _(Bool)_ - Always show send button in input text composer; default `false`, show only when text input is not empty
|
|
481
667
|
- **`isTextOptional`** _(Bool)_ - Allow sending messages without text (useful for media-only messages); default `false`. Use with `isSendButtonAlwaysVisible` for media attachments.
|
|
482
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).
|
|
@@ -485,16 +671,19 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
485
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))
|
|
486
672
|
- **`renderActions`** _(Component | Function)_ - Custom action button on the left of the message composer
|
|
487
673
|
- **`renderAccessory`** _(Component | Function)_ - Custom second line of actions below the message composer
|
|
488
|
-
- **`
|
|
489
|
-
- **`
|
|
490
|
-
- **`
|
|
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.
|
|
491
679
|
- **`textInputProps`** _(Object)_ - props to be passed to the [`<TextInput>`](https://reactnative.dev/docs/textinput).
|
|
492
680
|
|
|
493
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.
|
|
494
682
|
|
|
495
683
|
### Actions & Action Sheet
|
|
496
684
|
|
|
497
|
-
- **`
|
|
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.
|
|
498
687
|
- **`onPressActionButton`** _(Function)_ - Callback when the "+" button is pressed (if set, the built-in `AttachmentSheet` is not shown)
|
|
499
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.
|
|
500
689
|
- **`actionSheetOptionTintColor`** _(String)_ - Tint color for action labels in the attachment sheet
|
|
@@ -508,25 +697,42 @@ If you do, sanity-check it on device: a toolbar behind the keyboard means the va
|
|
|
508
697
|
|
|
509
698
|
- **`messagesContainerStyle`** _(Object)_ - Custom style for the messages container
|
|
510
699
|
- **`renderMessage`** _(Component | Function)_ - Custom message container
|
|
511
|
-
- **`renderLoading`** _(Component | Function)_ - Render a loading view
|
|
512
|
-
- **`
|
|
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`.
|
|
513
707
|
- **`renderChatFooter`** _(Component | Function)_ - Custom component to render below the MessagesContainer (separate from the ListView)
|
|
514
|
-
- **`listProps`** _(Object)_ - Extra props
|
|
515
|
-
- **`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.
|
|
516
709
|
|
|
517
710
|
### Message Bubbles & Content
|
|
518
711
|
|
|
519
712
|
- **`renderBubble`** _(Component | Function(`props: BubbleProps`))_ - Custom message bubble. Receives [BubbleProps](src/Bubble/types.ts) as parameter.
|
|
520
713
|
- **`renderMessageText`** _(Component | Function)_ - Custom message text
|
|
521
|
-
- **`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
|
|
522
715
|
- **`renderMessageVideo`** _(Component | Function)_ - Custom message video
|
|
523
716
|
- **`renderMessageAudio`** _(Component | Function)_ - Custom message audio
|
|
524
717
|
- **`renderMessageLocation`** _(Component | Function)_ - Custom renderer for `IMessage.location`; defaults to a map card that opens the system maps app on tap
|
|
525
|
-
- **`
|
|
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.
|
|
526
732
|
- **`renderCustomView`** _(Component | Function)_ - Custom view inside the bubble
|
|
527
733
|
- **`isCustomViewBottom`** _(Bool)_ - Determine whether renderCustomView is displayed before or after the text, image and video views; default is `false`
|
|
528
734
|
- **`onPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is pressed
|
|
529
|
-
- **`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
|
|
530
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).
|
|
531
737
|
- **`imageProps`** _(Object)_ - Extra props to be passed to the [`<Image>`](https://reactnative.dev/docs/image) component created by the default `renderMessageImage`
|
|
532
738
|
- **`imageStyle`** _(Object)_ - Custom style for message images
|
|
@@ -597,6 +803,10 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
597
803
|
|
|
598
804
|
### Avatars
|
|
599
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
|
|
600
810
|
- **`renderAvatar`** _(Component | Function)_ - Custom message avatar; set to `null` to not render any avatar for the message
|
|
601
811
|
- **`isUserAvatarVisible`** _(Bool)_ - Whether to render an avatar for the current user; default is `false`, only show avatars for other users
|
|
602
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`
|
|
@@ -606,7 +816,7 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
606
816
|
|
|
607
817
|
### Username
|
|
608
818
|
|
|
609
|
-
- **`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`)
|
|
610
820
|
- **`renderUsername`** _(Component | Function)_ - Custom Username container
|
|
611
821
|
|
|
612
822
|
### Date & Time
|
|
@@ -645,13 +855,13 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
645
855
|
- **`loadEarlierMessagesProps`** _(Object)_ - Props to pass to the LoadEarlierMessages component. The button is only visible when `isAvailable` is `true`:
|
|
646
856
|
- `isAvailable` - Controls button visibility (default: false)
|
|
647
857
|
- `onPress` - Callback when button is pressed
|
|
648
|
-
- `isLoading` -
|
|
649
|
-
- `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`
|
|
650
860
|
- `label` - Override the default "Load earlier messages" text
|
|
651
861
|
- `containerStyle` / `wrapperStyle` / `textStyle` - Custom styles for the button
|
|
652
862
|
- `activityIndicatorStyle` - Custom style for the loading indicator
|
|
653
|
-
- `activityIndicatorColor` - Color of the
|
|
654
|
-
- `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
|
|
655
865
|
- **`renderLoadEarlier`** _(Component | Function)_ - Custom "Load earlier messages" button
|
|
656
866
|
|
|
657
867
|
### Typing Indicator
|
|
@@ -660,6 +870,7 @@ See the full example in [LinksExample](example/components/chat-examples/LinksExa
|
|
|
660
870
|
- **`renderTypingIndicator`** _(Component | Function)_ - Custom typing indicator component
|
|
661
871
|
- **`typingIndicatorStyle`** _(StyleProp<ViewStyle>)_ - Custom style for the TypingIndicator component.
|
|
662
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
|
|
663
874
|
|
|
664
875
|
### Quick Replies
|
|
665
876
|
|
|
@@ -674,9 +885,12 @@ See the [quick replies example in messages.ts](example/example-expo/data/message
|
|
|
674
885
|
|
|
675
886
|
### Scroll to Bottom
|
|
676
887
|
|
|
677
|
-
|
|
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`
|
|
678
892
|
- **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
|
|
679
|
-
- **`scrollToBottomOffset`** _(Integer)_ -
|
|
893
|
+
- **`scrollToBottomOffset`** _(Integer)_ - How far to scroll before the button shows or hides; default `100`
|
|
680
894
|
- **`scrollToBottomStyle`** _(Object)_ - Custom style for Scroll To Bottom wrapper (position, bottom, right, etc.)
|
|
681
895
|
- **`scrollToBottomContentStyle`** _(Object)_ - Custom style for Scroll To Bottom content (size, background, shadow, etc.)
|
|
682
896
|
|
|
@@ -686,6 +900,76 @@ See the [quick replies example in messages.ts](example/example-expo/data/message
|
|
|
686
900
|
|
|
687
901
|
## 🧩 Guides
|
|
688
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
|
+
|
|
689
973
|
### Reply to Messages
|
|
690
974
|
|
|
691
975
|
<details>
|
|
@@ -709,13 +993,20 @@ Swipe on a message to reply to it, showing a reply preview in the input toolbar
|
|
|
709
993
|
/>
|
|
710
994
|
```
|
|
711
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
|
+
|
|
712
1000
|
#### Reply Props (Grouped)
|
|
713
1001
|
|
|
714
1002
|
```typescript
|
|
715
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
|
+
|
|
716
1007
|
// Swipe gesture configuration
|
|
717
1008
|
swipe?: {
|
|
718
|
-
isEnabled?: boolean //
|
|
1009
|
+
isEnabled?: boolean // Swipe-to-reply; default true (false to turn it off)
|
|
719
1010
|
direction?: 'left' | 'right' // Swipe direction; default 'left'
|
|
720
1011
|
onSwipe?: (message: TMessage) => void // Callback when swiped
|
|
721
1012
|
renderAction?: ( // Custom swipe action component
|
|
@@ -747,7 +1038,7 @@ interface ReplyProps<TMessage> {
|
|
|
747
1038
|
// Callbacks and state
|
|
748
1039
|
message?: ReplyMessage // Controlled reply state
|
|
749
1040
|
onClear?: () => void // Called when reply cleared
|
|
750
|
-
onPress?: (message:
|
|
1041
|
+
onPress?: (message: ReplyMessage) => void // Quote tapped; default jumps to the quoted message and flashes it
|
|
751
1042
|
|
|
752
1043
|
// Custom renderers
|
|
753
1044
|
renderPreview?: (props: ReplyPreviewProps) => React.ReactNode
|
|
@@ -807,41 +1098,11 @@ The reply preview animates automatically - it expands from zero height with a fa
|
|
|
807
1098
|
<details>
|
|
808
1099
|
<summary><strong>Keep the reading position while long answers stream in</strong></summary>
|
|
809
1100
|
|
|
810
|
-
|
|
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`:
|
|
811
1102
|
|
|
812
1103
|
```tsx
|
|
813
|
-
//
|
|
814
|
-
<Chat
|
|
815
|
-
listProps={{
|
|
816
|
-
maintainVisibleContentPosition: {
|
|
817
|
-
minIndexForVisible: 0,
|
|
818
|
-
},
|
|
819
|
-
}}
|
|
820
|
-
/>
|
|
821
|
-
|
|
822
|
-
// With auto-scroll threshold - auto-scroll if within 10 pixels of newest content
|
|
823
|
-
<Chat
|
|
824
|
-
listProps={{
|
|
825
|
-
maintainVisibleContentPosition: {
|
|
826
|
-
minIndexForVisible: 0,
|
|
827
|
-
autoscrollToTopThreshold: 10,
|
|
828
|
-
},
|
|
829
|
-
}}
|
|
830
|
-
/>
|
|
831
|
-
|
|
832
|
-
// Conditionally enable based on scroll state (recommended for chatbots)
|
|
833
|
-
const [isScrolledUp, setIsScrolledUp] = useState(false)
|
|
834
|
-
|
|
835
|
-
<Chat
|
|
836
|
-
listProps={{
|
|
837
|
-
onScroll: (event) => {
|
|
838
|
-
setIsScrolledUp(event.contentOffset.y > 50)
|
|
839
|
-
},
|
|
840
|
-
maintainVisibleContentPosition: isScrolledUp
|
|
841
|
-
? { minIndexForVisible: 0, autoscrollToTopThreshold: 10 }
|
|
842
|
-
: undefined,
|
|
843
|
-
}}
|
|
844
|
-
/>
|
|
1104
|
+
// Never follow new content, even at the newest message
|
|
1105
|
+
<Chat listProps={{ maintainScrollAtEnd: false }} />
|
|
845
1106
|
```
|
|
846
1107
|
|
|
847
1108
|
</details>
|
|
@@ -857,14 +1118,14 @@ Render AI assistant replies token-by-token. Incoming chunks are batched with `re
|
|
|
857
1118
|
<details>
|
|
858
1119
|
<summary><strong>useStreamingMessages, stop control and a full example</strong></summary>
|
|
859
1120
|
|
|
860
|
-
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.
|
|
861
1122
|
|
|
862
1123
|
- **`IMessage.streaming`** - flag a message as streaming (shows the caret)
|
|
863
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`.
|
|
864
1125
|
|
|
865
1126
|
```tsx
|
|
866
1127
|
import { useCallback } from 'react'
|
|
867
|
-
import { Chat, IMessage, useStreamingMessages } from '@kesha-antonov/react-native-chat'
|
|
1128
|
+
import { Chat, IMessage, Send, SendProps, useStreamingMessages } from '@kesha-antonov/react-native-chat'
|
|
868
1129
|
|
|
869
1130
|
function Bot () {
|
|
870
1131
|
const { messages, append, startStream, isStreaming, stop } = useStreamingMessages<IMessage>()
|
|
@@ -880,7 +1141,14 @@ function Bot () {
|
|
|
880
1141
|
})
|
|
881
1142
|
}, [append, startStream])
|
|
882
1143
|
|
|
883
|
-
|
|
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} />
|
|
884
1152
|
}
|
|
885
1153
|
```
|
|
886
1154
|
|
|
@@ -912,30 +1180,36 @@ There are two renderers and you get the best available one automatically:
|
|
|
912
1180
|
npx expo install react-native-streamdown react-native-enriched-markdown remend katex
|
|
913
1181
|
```
|
|
914
1182
|
|
|
915
|
-
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:
|
|
916
1184
|
|
|
917
1185
|
```tsx
|
|
918
|
-
<Chat
|
|
1186
|
+
<Chat
|
|
1187
|
+
messageTextProps={{
|
|
1188
|
+
markdown: true,
|
|
1189
|
+
markdownProps: { markdownStyle: { codeBlock: { backgroundColor: '#0d1117' } } },
|
|
1190
|
+
}}
|
|
1191
|
+
{...props}
|
|
1192
|
+
/>
|
|
919
1193
|
```
|
|
920
1194
|
|
|
921
1195
|
</details>
|
|
922
1196
|
|
|
923
1197
|
### Emoji Reactions
|
|
924
1198
|
|
|
925
|
-
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.
|
|
926
1200
|
|
|
927
1201
|
<p align="center">
|
|
928
|
-
<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" />
|
|
929
1203
|
|
|
930
|
-
<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" />
|
|
931
1205
|
|
|
932
|
-
<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" />
|
|
933
1207
|
</p>
|
|
934
1208
|
|
|
935
1209
|
<details>
|
|
936
1210
|
<summary><strong>Wiring up the toggle, and the full prop list</strong></summary>
|
|
937
1211
|
|
|
938
|
-
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:
|
|
939
1213
|
|
|
940
1214
|
```tsx
|
|
941
1215
|
interface IChatMessage extends IMessage {
|
|
@@ -945,27 +1219,7 @@ interface IChatMessage extends IMessage {
|
|
|
945
1219
|
const CURRENT_USER_ID = 1
|
|
946
1220
|
|
|
947
1221
|
const handleReactionPress = useCallback((message: IChatMessage, emoji: string) => {
|
|
948
|
-
setMessages(prev =>
|
|
949
|
-
prev.map(m => {
|
|
950
|
-
if (m._id !== message._id)
|
|
951
|
-
return m
|
|
952
|
-
|
|
953
|
-
const existing = (m.reactions ?? []).find(r => r.emoji === emoji)
|
|
954
|
-
if (!existing)
|
|
955
|
-
return { ...m, reactions: [...(m.reactions ?? []), { emoji, userIds: [CURRENT_USER_ID] }] }
|
|
956
|
-
|
|
957
|
-
const userIds = existing.userIds.includes(CURRENT_USER_ID)
|
|
958
|
-
? existing.userIds.filter(id => id !== CURRENT_USER_ID)
|
|
959
|
-
: [...existing.userIds, CURRENT_USER_ID]
|
|
960
|
-
|
|
961
|
-
return {
|
|
962
|
-
...m,
|
|
963
|
-
reactions: userIds.length === 0
|
|
964
|
-
? (m.reactions ?? []).filter(r => r.emoji !== emoji)
|
|
965
|
-
: (m.reactions ?? []).map(r => (r.emoji === emoji ? { ...r, userIds } : r)),
|
|
966
|
-
}
|
|
967
|
-
})
|
|
968
|
-
)
|
|
1222
|
+
setMessages(prev => Chat.toggleReaction(prev, message._id, emoji, CURRENT_USER_ID))
|
|
969
1223
|
}, [])
|
|
970
1224
|
|
|
971
1225
|
<Chat
|
|
@@ -973,7 +1227,6 @@ const handleReactionPress = useCallback((message: IChatMessage, emoji: string) =
|
|
|
973
1227
|
onSend={onSend}
|
|
974
1228
|
user={{ _id: CURRENT_USER_ID }}
|
|
975
1229
|
reactions={{
|
|
976
|
-
isEnabled: true,
|
|
977
1230
|
onReactionPress: handleReactionPress,
|
|
978
1231
|
// Optional: provide a richer picker (e.g. a full emoji browser).
|
|
979
1232
|
// See example/components/chat-examples/ReactionsExample.tsx
|
|
@@ -982,13 +1235,20 @@ const handleReactionPress = useCallback((message: IChatMessage, emoji: string) =
|
|
|
982
1235
|
/>
|
|
983
1236
|
```
|
|
984
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
|
+
|
|
985
1242
|
#### Reactions Props (Grouped)
|
|
986
1243
|
|
|
987
|
-
- **`isEnabled`** _(Bool)_ - Enable emoji reactions
|
|
1244
|
+
- **`isEnabled`** _(Bool)_ - Enable emoji reactions; default is on whenever `onReactionPress` is passed
|
|
988
1245
|
- **`emojis`** _(String[])_ - Emojis shown in the quick picker (default `['👍', '❤️', '😂', '😮', '😢', '👎']`)
|
|
989
|
-
- **`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)
|
|
990
1248
|
- **`renderReactions`** _(Function)_ - Override the reactions-display component rendered below the bubble
|
|
991
|
-
- **`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`
|
|
992
1252
|
- **`containerStyle`**, **`reactionStyle`**, **`reactionActiveStyle`**, **`reactionTextStyle`**, **`reactionCountStyle`** - Styles for the reaction pills
|
|
993
1253
|
- **`pickerContainerStyle`**, **`pickerEmojiStyle`** - Styles for the quick picker
|
|
994
1254
|
|
|
@@ -1027,9 +1287,34 @@ For full control, pass custom `matchers` (`{ type, pattern, getLinkUrl?, getLink
|
|
|
1027
1287
|
### Message actions (long-press context menu)
|
|
1028
1288
|
|
|
1029
1289
|
<details>
|
|
1030
|
-
<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
|
+
```
|
|
1303
|
+
|
|
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.
|
|
1031
1316
|
|
|
1032
|
-
|
|
1317
|
+
A fully custom menu - each item is `{ key?, label, icon?, onPress, destructive? }`:
|
|
1033
1318
|
|
|
1034
1319
|
```tsx
|
|
1035
1320
|
import { setStringAsync } from 'expo-clipboard'
|
|
@@ -1038,11 +1323,18 @@ import { Copy, Trash2 } from 'lucide-react-native' // optional icons
|
|
|
1038
1323
|
<Chat
|
|
1039
1324
|
messageActions={message => [
|
|
1040
1325
|
{ label: 'Copy', icon: ({ color, size }) => <Copy color={color} size={size} />, onPress: () => setStringAsync(message.text) },
|
|
1041
|
-
{ label: 'Delete', destructive: true, onPress: () => deleteMessage(message) },
|
|
1326
|
+
{ label: 'Delete', icon: ({ color, size }) => <Trash2 color={color} size={size} />, destructive: true, onPress: () => deleteMessage(message) },
|
|
1042
1327
|
]}
|
|
1043
1328
|
/>
|
|
1044
1329
|
```
|
|
1045
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
|
+
|
|
1046
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.
|
|
1047
1339
|
|
|
1048
1340
|
</details>
|
|
@@ -1052,7 +1344,7 @@ import { Copy, Trash2 } from 'lucide-react-native' // optional icons
|
|
|
1052
1344
|
<details>
|
|
1053
1345
|
<summary><strong>Keeping native controls tappable</strong></summary>
|
|
1054
1346
|
|
|
1055
|
-
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.
|
|
1056
1348
|
|
|
1057
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.
|
|
1058
1350
|
|
|
@@ -1072,21 +1364,31 @@ If a message must own every touch that lands on it, set `isMessageGestureEnabled
|
|
|
1072
1364
|
<details>
|
|
1073
1365
|
<summary><strong>Token groups, runtime switching and themed components</strong></summary>
|
|
1074
1366
|
|
|
1075
|
-
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.
|
|
1076
1368
|
|
|
1077
1369
|
```tsx
|
|
1078
1370
|
<Chat
|
|
1079
1371
|
theme={{
|
|
1080
|
-
colors: { accent: '#3390EC', outgoingBubble: '#
|
|
1372
|
+
colors: { accent: '#3390EC', outgoingBubble: '#3390EC', outgoingText: '#FFFFFF' },
|
|
1081
1373
|
radii: { bubble: 18 },
|
|
1374
|
+
wallpaper: { colors: ['#7FA381', '#FFF5C5', '#336F55', '#FBE37D'] },
|
|
1082
1375
|
}}
|
|
1083
|
-
darkTheme={{
|
|
1376
|
+
darkTheme={{ bubble: { outgoingGradient: ['#5B3FA8', '#2F6FD6'] } }}
|
|
1084
1377
|
// colorScheme="dark" // optional: force a scheme instead of following the system
|
|
1085
1378
|
{...props}
|
|
1086
1379
|
/>
|
|
1087
1380
|
```
|
|
1088
1381
|
|
|
1089
|
-
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:
|
|
1090
1392
|
|
|
1091
1393
|
```tsx
|
|
1092
1394
|
import { useTheme, useThemedStyles } from '@kesha-antonov/react-native-chat'
|
|
@@ -1101,7 +1403,9 @@ const MyBadge = () => {
|
|
|
1101
1403
|
}
|
|
1102
1404
|
```
|
|
1103
1405
|
|
|
1104
|
-
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`.
|
|
1105
1409
|
|
|
1106
1410
|
</details>
|
|
1107
1411
|
|
|
@@ -1120,6 +1424,8 @@ All built-in UI strings (composer placeholder, send/cancel, load earlier, today,
|
|
|
1120
1424
|
/>
|
|
1121
1425
|
```
|
|
1122
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
|
+
|
|
1123
1429
|
Exported helpers: `ChatLabels` (type), `defaultLabels`, `translations`, `resolveLabels`, and the `useLabels` hook for reading the resolved labels in custom components.
|
|
1124
1430
|
|
|
1125
1431
|
</details>
|
|
@@ -1129,7 +1435,7 @@ Exported helpers: `ChatLabels` (type), `defaultLabels`, `translations`, `resolve
|
|
|
1129
1435
|
<details>
|
|
1130
1436
|
<summary><strong>Tick indicators for sent / delivered / read</strong></summary>
|
|
1131
1437
|
|
|
1132
|
-
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":
|
|
1133
1439
|
|
|
1134
1440
|
```tsx
|
|
1135
1441
|
const message: IMessage = {
|
|
@@ -1176,6 +1482,25 @@ interface MyMessage extends IMessage {
|
|
|
1176
1482
|
|
|
1177
1483
|
</details>
|
|
1178
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
|
+
|
|
1179
1504
|
---
|
|
1180
1505
|
|
|
1181
1506
|
## 📱 Platform Notes
|
|
@@ -1271,74 +1596,34 @@ Three things to know:
|
|
|
1271
1596
|
|
|
1272
1597
|
## ⚡ Performance
|
|
1273
1598
|
|
|
1274
|
-
|
|
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:
|
|
1275
1600
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
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`.
|
|
1279
1604
|
|
|
1280
|
-
|
|
1605
|
+
```jsx
|
|
1606
|
+
// ✅ Handlers and objects inline; the render function memoized
|
|
1281
1607
|
const renderBubble = useCallback(props => <MyBubble {...props} />, [])
|
|
1282
|
-
const reactions = useMemo(() => ({ isEnabled: true, onReactionPress }), [onReactionPress])
|
|
1283
1608
|
|
|
1284
|
-
<Chat renderBubble={renderBubble}
|
|
1609
|
+
<Chat renderBubble={renderBubble} onPressMessage={message => open(message)} timeTextStyle={{ left: { color: 'gray' } }} />
|
|
1285
1610
|
```
|
|
1286
1611
|
|
|
1287
1612
|
<details>
|
|
1288
|
-
<summary><strong>
|
|
1613
|
+
<summary><strong>Messages, neighbours, context props and virtualization tuning</strong></summary>
|
|
1289
1614
|
|
|
1290
|
-
|
|
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.
|
|
1291
1616
|
|
|
1292
|
-
**
|
|
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.
|
|
1293
1618
|
|
|
1294
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.
|
|
1295
1620
|
|
|
1296
|
-
**Tune virtualization if needed.**
|
|
1297
|
-
|
|
1298
|
-
```jsx
|
|
1299
|
-
<Chat listProps={{ windowSize: 7, removeClippedSubviews: true }} {...props} />
|
|
1300
|
-
```
|
|
1301
|
-
|
|
1302
|
-
</details>
|
|
1303
|
-
|
|
1304
|
-
### FlashList (opt-in)
|
|
1305
|
-
|
|
1306
|
-
<details>
|
|
1307
|
-
<summary><strong>Recycling rows on very long histories</strong></summary>
|
|
1308
|
-
|
|
1309
|
-
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:
|
|
1310
|
-
|
|
1311
|
-
```bash
|
|
1312
|
-
yarn add @shopify/flash-list
|
|
1313
|
-
```
|
|
1314
|
-
|
|
1315
|
-
```jsx
|
|
1316
|
-
<Chat messages={messages} user={user} isFlashListEnabled />
|
|
1317
|
-
```
|
|
1318
|
-
|
|
1319
|
-
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).
|
|
1320
|
-
|
|
1321
|
-
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:
|
|
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.
|
|
1322
1622
|
|
|
1323
1623
|
```jsx
|
|
1324
|
-
<Chat
|
|
1325
|
-
isFlashListEnabled
|
|
1326
|
-
listProps={{
|
|
1327
|
-
maintainVisibleContentPosition: {
|
|
1328
|
-
autoscrollToBottomThreshold: 0.1,
|
|
1329
|
-
animateAutoScrollToBottom: false,
|
|
1330
|
-
},
|
|
1331
|
-
}}
|
|
1332
|
-
{...props}
|
|
1333
|
-
/>
|
|
1624
|
+
<Chat listProps={{ drawDistance: 500 }} {...props} />
|
|
1334
1625
|
```
|
|
1335
1626
|
|
|
1336
|
-
Notes:
|
|
1337
|
-
|
|
1338
|
-
- FlashList v2 requires the **New Architecture**. On the old architecture it falls back to a slower JS path.
|
|
1339
|
-
- `FlatList`-only knobs (`windowSize`, `maxToRenderPerBatch`, `initialNumToRender`, `updateCellsBatchingPeriod`, `removeClippedSubviews`) are not forwarded to FlashList - it sizes its own render window.
|
|
1340
|
-
- If `@shopify/flash-list` is not installed, the prop is ignored, a warning is logged, and `FlatList` is used.
|
|
1341
|
-
|
|
1342
1627
|
</details>
|
|
1343
1628
|
|
|
1344
1629
|
---
|
|
@@ -1376,7 +1661,7 @@ fireEvent(loadingWrapper, 'layout', {
|
|
|
1376
1661
|
<details>
|
|
1377
1662
|
<summary><strong>Running the demo locally</strong></summary>
|
|
1378
1663
|
|
|
1379
|
-
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.
|
|
1380
1665
|
|
|
1381
1666
|
```bash
|
|
1382
1667
|
git clone https://github.com/kesha-antonov/react-native-chat.git
|
|
@@ -1394,6 +1679,28 @@ npx expo start --web # Web
|
|
|
1394
1679
|
|
|
1395
1680
|
## ❓ Troubleshooting
|
|
1396
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
|
+
|
|
1397
1704
|
<details>
|
|
1398
1705
|
<summary><strong>TextInput is hidden on Android</strong></summary>
|
|
1399
1706
|
|