react-native-gifted-chat 2.6.5 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/README.md +7 -16
  2. package/lib/Actions.d.ts +0 -11
  3. package/lib/Actions.js +2 -14
  4. package/lib/Actions.js.map +1 -1
  5. package/lib/Avatar.d.ts +1 -23
  6. package/lib/Avatar.js +32 -40
  7. package/lib/Avatar.js.map +1 -1
  8. package/lib/Bubble/index.d.ts +30 -0
  9. package/lib/{Bubble.js → Bubble/index.js} +31 -181
  10. package/lib/Bubble/index.js.map +1 -0
  11. package/lib/Bubble/styles.d.ts +69 -0
  12. package/lib/Bubble/styles.js +72 -0
  13. package/lib/Bubble/styles.js.map +1 -0
  14. package/lib/Bubble/types.d.ts +47 -0
  15. package/lib/Bubble/types.js +2 -0
  16. package/lib/Bubble/types.js.map +1 -0
  17. package/lib/Composer.d.ts +0 -17
  18. package/lib/Composer.js +3 -18
  19. package/lib/Composer.js.map +1 -1
  20. package/lib/Constant.d.ts +1 -1
  21. package/lib/Constant.js +1 -1
  22. package/lib/Constant.js.map +1 -1
  23. package/lib/Day/index.d.ts +4 -0
  24. package/lib/Day/index.js +39 -0
  25. package/lib/Day/index.js.map +1 -0
  26. package/lib/Day/styles.d.ts +20 -0
  27. package/lib/Day/styles.js +22 -0
  28. package/lib/Day/styles.js.map +1 -0
  29. package/lib/Day/types.d.ts +9 -0
  30. package/lib/Day/types.js +2 -0
  31. package/lib/Day/types.js.map +1 -0
  32. package/lib/GiftedAvatar.d.ts +1 -11
  33. package/lib/GiftedAvatar.js +26 -33
  34. package/lib/GiftedAvatar.js.map +1 -1
  35. package/lib/GiftedChat/index.d.ts +26 -0
  36. package/lib/{GiftedChat.js → GiftedChat/index.js} +47 -52
  37. package/lib/GiftedChat/index.js.map +1 -0
  38. package/lib/GiftedChat/styles.d.ts +6 -0
  39. package/lib/GiftedChat/styles.js +7 -0
  40. package/lib/GiftedChat/styles.js.map +1 -0
  41. package/lib/{GiftedChat.d.ts → GiftedChat/types.d.ts} +27 -37
  42. package/lib/GiftedChat/types.js +2 -0
  43. package/lib/GiftedChat/types.js.map +1 -0
  44. package/lib/InputToolbar.d.ts +1 -14
  45. package/lib/InputToolbar.js +0 -12
  46. package/lib/InputToolbar.js.map +1 -1
  47. package/lib/LoadEarlier.d.ts +0 -14
  48. package/lib/LoadEarlier.js +2 -16
  49. package/lib/LoadEarlier.js.map +1 -1
  50. package/lib/Message/index.d.ts +6 -0
  51. package/lib/Message/index.js +85 -0
  52. package/lib/Message/index.js.map +1 -0
  53. package/lib/Message/styles.d.ts +21 -0
  54. package/lib/Message/styles.js +22 -0
  55. package/lib/Message/styles.js.map +1 -0
  56. package/lib/Message/types.d.ts +22 -0
  57. package/lib/Message/types.js +2 -0
  58. package/lib/Message/types.js.map +1 -0
  59. package/lib/MessageAudio.js +1 -2
  60. package/lib/MessageAudio.js.map +1 -1
  61. package/lib/MessageContainer/components/DayAnimated/index.d.ts +5 -0
  62. package/lib/MessageContainer/components/DayAnimated/index.js +85 -0
  63. package/lib/MessageContainer/components/DayAnimated/index.js.map +1 -0
  64. package/lib/MessageContainer/components/DayAnimated/styles.d.ts +11 -0
  65. package/lib/MessageContainer/components/DayAnimated/styles.js +12 -0
  66. package/lib/MessageContainer/components/DayAnimated/styles.js.map +1 -0
  67. package/lib/MessageContainer/components/DayAnimated/types.d.ts +17 -0
  68. package/lib/MessageContainer/components/DayAnimated/types.js +2 -0
  69. package/lib/MessageContainer/components/DayAnimated/types.js.map +1 -0
  70. package/lib/MessageContainer/components/Item/index.d.ts +22 -0
  71. package/lib/MessageContainer/components/Item/index.js +69 -0
  72. package/lib/MessageContainer/components/Item/index.js.map +1 -0
  73. package/lib/MessageContainer/components/Item/types.d.ts +18 -0
  74. package/lib/MessageContainer/components/Item/types.js +2 -0
  75. package/lib/MessageContainer/components/Item/types.js.map +1 -0
  76. package/lib/MessageContainer/index.d.ts +6 -0
  77. package/lib/MessageContainer/index.js +175 -0
  78. package/lib/MessageContainer/index.js.map +1 -0
  79. package/lib/MessageContainer/styles.d.ts +34 -0
  80. package/lib/MessageContainer/styles.js +31 -0
  81. package/lib/MessageContainer/styles.js.map +1 -0
  82. package/lib/MessageContainer/types.d.ts +54 -0
  83. package/lib/MessageContainer/types.js +2 -0
  84. package/lib/MessageContainer/types.js.map +1 -0
  85. package/lib/MessageImage.d.ts +1 -12
  86. package/lib/MessageImage.js +2 -12
  87. package/lib/MessageImage.js.map +1 -1
  88. package/lib/MessageText.d.ts +1 -24
  89. package/lib/MessageText.js +0 -22
  90. package/lib/MessageText.js.map +1 -1
  91. package/lib/MessageVideo.js +1 -2
  92. package/lib/MessageVideo.js.map +1 -1
  93. package/lib/QuickReplies.d.ts +1 -12
  94. package/lib/QuickReplies.js +10 -20
  95. package/lib/QuickReplies.js.map +1 -1
  96. package/lib/Send.d.ts +2 -16
  97. package/lib/Send.js +0 -13
  98. package/lib/Send.js.map +1 -1
  99. package/lib/SystemMessage.d.ts +1 -10
  100. package/lib/SystemMessage.js +2 -12
  101. package/lib/SystemMessage.js.map +1 -1
  102. package/lib/Time.d.ts +1 -17
  103. package/lib/Time.js +0 -15
  104. package/lib/Time.js.map +1 -1
  105. package/lib/TypingIndicator/index.d.ts +5 -0
  106. package/lib/{TypingIndicator.js → TypingIndicator/index.js} +9 -30
  107. package/lib/TypingIndicator/index.js.map +1 -0
  108. package/lib/TypingIndicator/styles.d.ts +20 -0
  109. package/lib/TypingIndicator/styles.js +22 -0
  110. package/lib/TypingIndicator/styles.js.map +1 -0
  111. package/lib/TypingIndicator/types.d.ts +3 -0
  112. package/lib/TypingIndicator/types.js +2 -0
  113. package/lib/TypingIndicator/types.js.map +1 -0
  114. package/lib/index.d.ts +0 -1
  115. package/lib/index.js +0 -1
  116. package/lib/index.js.map +1 -1
  117. package/lib/styles.d.ts +10 -0
  118. package/lib/styles.js +11 -0
  119. package/lib/styles.js.map +1 -0
  120. package/lib/{Models.d.ts → types.d.ts} +1 -1
  121. package/lib/types.js +2 -0
  122. package/lib/types.js.map +1 -0
  123. package/lib/utils.d.ts +1 -3
  124. package/lib/utils.js +0 -7
  125. package/lib/utils.js.map +1 -1
  126. package/package.json +21 -29
  127. package/src/Actions.tsx +3 -15
  128. package/src/Avatar.tsx +43 -52
  129. package/src/{Bubble.tsx → Bubble/index.tsx} +52 -269
  130. package/src/Bubble/styles.ts +73 -0
  131. package/src/Bubble/types.ts +90 -0
  132. package/src/Composer.tsx +3 -19
  133. package/src/Constant.ts +1 -1
  134. package/src/Day/index.tsx +63 -0
  135. package/src/Day/styles.ts +22 -0
  136. package/src/Day/types.ts +14 -0
  137. package/src/GiftedAvatar.tsx +31 -38
  138. package/src/GiftedChat/index.tsx +503 -0
  139. package/src/GiftedChat/styles.ts +7 -0
  140. package/src/GiftedChat/types.ts +206 -0
  141. package/src/InputToolbar.tsx +1 -14
  142. package/src/LoadEarlier.tsx +2 -17
  143. package/src/Message/index.tsx +135 -0
  144. package/src/Message/styles.ts +22 -0
  145. package/src/Message/types.ts +26 -0
  146. package/src/MessageAudio.tsx +1 -4
  147. package/src/MessageContainer/components/DayAnimated/index.tsx +143 -0
  148. package/src/MessageContainer/components/DayAnimated/styles.ts +12 -0
  149. package/src/MessageContainer/components/DayAnimated/types.ts +12 -0
  150. package/src/MessageContainer/components/Item/index.tsx +136 -0
  151. package/src/MessageContainer/components/Item/types.ts +13 -0
  152. package/src/MessageContainer/index.tsx +316 -0
  153. package/src/MessageContainer/styles.ts +31 -0
  154. package/src/MessageContainer/types.ts +60 -0
  155. package/src/MessageImage.tsx +3 -14
  156. package/src/MessageText.tsx +1 -24
  157. package/src/MessageVideo.tsx +1 -4
  158. package/src/QuickReplies.tsx +14 -25
  159. package/src/Send.tsx +1 -15
  160. package/src/SystemMessage.tsx +3 -14
  161. package/src/Time.tsx +1 -17
  162. package/src/{TypingIndicator.tsx → TypingIndicator/index.tsx} +12 -35
  163. package/src/TypingIndicator/styles.ts +22 -0
  164. package/src/TypingIndicator/types.ts +3 -0
  165. package/src/__tests__/Bubble.test.tsx +7 -4
  166. package/src/__tests__/GiftedAvatar.test.tsx +6 -2
  167. package/src/__tests__/GiftedChat.test.tsx +20 -14
  168. package/src/__tests__/Message.test.tsx +4 -1
  169. package/src/__tests__/__snapshots__/Actions.test.tsx.snap +6 -2
  170. package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +3 -1
  171. package/src/__tests__/__snapshots__/Composer.test.tsx.snap +2 -0
  172. package/src/__tests__/__snapshots__/Constant.test.tsx.snap +1 -1
  173. package/src/__tests__/__snapshots__/Day.test.tsx.snap +1 -33
  174. package/src/__tests__/__snapshots__/GiftedAvatar.test.tsx.snap +4 -2
  175. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +22 -9
  176. package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +2 -0
  177. package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +3 -1
  178. package/src/__tests__/__snapshots__/Message.test.tsx.snap +21 -100
  179. package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +282 -82
  180. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +8 -4
  181. package/src/__tests__/__snapshots__/SystemMessage.test.tsx.snap +5 -1
  182. package/src/__tests__/data.ts +1 -1
  183. package/src/index.ts +0 -2
  184. package/src/styles.ts +11 -0
  185. package/src/{Models.ts → types.ts} +1 -1
  186. package/src/utils.ts +1 -9
  187. package/lib/Actions.js.flow +0 -21
  188. package/lib/Avatar.js.flow +0 -27
  189. package/lib/Bubble.d.ts +0 -148
  190. package/lib/Bubble.js.flow +0 -69
  191. package/lib/Bubble.js.map +0 -1
  192. package/lib/Composer.js.flow +0 -24
  193. package/lib/Day.d.ts +0 -15
  194. package/lib/Day.js +0 -36
  195. package/lib/Day.js.flow +0 -23
  196. package/lib/Day.js.map +0 -1
  197. package/lib/GiftedAvatar.js.flow +0 -17
  198. package/lib/GiftedChat.js.flow +0 -163
  199. package/lib/GiftedChat.js.map +0 -1
  200. package/lib/InputToolbar.js.flow +0 -31
  201. package/lib/LoadEarlier.js.flow +0 -20
  202. package/lib/Message.d.ts +0 -67
  203. package/lib/Message.js +0 -157
  204. package/lib/Message.js.flow +0 -32
  205. package/lib/Message.js.map +0 -1
  206. package/lib/MessageAudio.js.flow +0 -15
  207. package/lib/MessageContainer.d.ts +0 -105
  208. package/lib/MessageContainer.js +0 -224
  209. package/lib/MessageContainer.js.flow +0 -39
  210. package/lib/MessageContainer.js.map +0 -1
  211. package/lib/MessageImage.js.flow +0 -20
  212. package/lib/MessageText.js.flow +0 -23
  213. package/lib/MessageVideo.js.flow +0 -16
  214. package/lib/Models.js +0 -2
  215. package/lib/Models.js.map +0 -1
  216. package/lib/QuickReplies.js.flow +0 -25
  217. package/lib/Send.js.flow +0 -19
  218. package/lib/SystemMessage.js.flow +0 -18
  219. package/lib/Time.js.flow +0 -19
  220. package/lib/TypingIndicator.d.ts +0 -6
  221. package/lib/TypingIndicator.js.map +0 -1
  222. package/lib/index.js.flow +0 -2
  223. package/lib/types.js.flow +0 -43
  224. package/lib/utils.js.flow +0 -16
  225. package/src/Day.tsx +0 -71
  226. package/src/GiftedChat.tsx +0 -689
  227. package/src/Message.tsx +0 -229
  228. package/src/MessageContainer.tsx +0 -361
@@ -1,689 +0,0 @@
1
- import React, {
2
- createRef,
3
- useEffect,
4
- useMemo,
5
- useRef,
6
- useState,
7
- useCallback,
8
- MutableRefObject,
9
- } from 'react'
10
- import {
11
- ActionSheetOptions,
12
- ActionSheetProvider,
13
- ActionSheetProviderRef,
14
- } from '@expo/react-native-action-sheet'
15
- import dayjs from 'dayjs'
16
- import localizedFormat from 'dayjs/plugin/localizedFormat'
17
- import {
18
- FlatList,
19
- Platform,
20
- StyleProp,
21
- StyleSheet,
22
- TextInput,
23
- TextStyle,
24
- View,
25
- ViewStyle,
26
- LayoutChangeEvent,
27
- } from 'react-native'
28
- import { LightboxProps } from 'react-native-lightbox-v2'
29
- import { v4 as uuidv4 } from 'uuid'
30
- import { Actions, ActionsProps } from './Actions'
31
- import { Avatar, AvatarProps } from './Avatar'
32
- import Bubble from './Bubble'
33
- import { Composer, ComposerProps } from './Composer'
34
- import { MAX_COMPOSER_HEIGHT, MIN_COMPOSER_HEIGHT, TEST_ID } from './Constant'
35
- import { Day, DayProps } from './Day'
36
- import { GiftedAvatar } from './GiftedAvatar'
37
- import { GiftedChatContext } from './GiftedChatContext'
38
- import { InputToolbar, InputToolbarProps } from './InputToolbar'
39
- import { LoadEarlier, LoadEarlierProps } from './LoadEarlier'
40
- import Message from './Message'
41
- import MessageContainer from './MessageContainer'
42
- import { MessageImage, MessageImageProps } from './MessageImage'
43
- import { MessageText, MessageTextProps } from './MessageText'
44
- import {
45
- IMessage,
46
- LeftRightStyle,
47
- MessageAudioProps,
48
- MessageVideoProps,
49
- Reply,
50
- User,
51
- } from './Models'
52
- import { QuickRepliesProps } from './QuickReplies'
53
- import { Send, SendProps } from './Send'
54
- import { SystemMessage, SystemMessageProps } from './SystemMessage'
55
- import { Time, TimeProps } from './Time'
56
- import * as utils from './utils'
57
- import Animated, {
58
- useAnimatedKeyboard,
59
- useAnimatedStyle,
60
- useAnimatedReaction,
61
- useSharedValue,
62
- withTiming,
63
- runOnJS,
64
- } from 'react-native-reanimated'
65
- import { useSafeAreaInsets } from 'react-native-safe-area-context'
66
-
67
- dayjs.extend(localizedFormat)
68
-
69
- export interface GiftedChatProps<TMessage extends IMessage = IMessage> extends Partial<Omit<MessageContainer<TMessage>, 'scrollToBottom'>> {
70
- /* Message container ref */
71
- messageContainerRef?: React.RefObject<FlatList<IMessage>>
72
- /* text input ref */
73
- textInputRef?: React.RefObject<TextInput>
74
- /* Messages to display */
75
- messages?: TMessage[]
76
- /* Typing Indicator state */
77
- isTyping?: boolean
78
- /* Controls whether or not to show user.name property in the message bubble */
79
- renderUsernameOnMessage?: boolean
80
- /* Messages container style */
81
- messagesContainerStyle?: StyleProp<ViewStyle>
82
- /* Input text; default is undefined, but if specified, it will override GiftedChat's internal state */
83
- text?: string
84
- /* Controls whether or not the message bubbles appear at the top of the chat */
85
- alignTop?: boolean
86
- /* enables the scrollToBottom Component */
87
- scrollToBottom?: boolean
88
- /* Scroll to bottom wrapper style */
89
- scrollToBottomStyle?: StyleProp<ViewStyle>
90
- initialText?: string
91
- /* Placeholder when text is empty; default is 'Type a message...' */
92
- placeholder?: string
93
- /* Makes the composer not editable */
94
- disableComposer?: boolean
95
- /* User sending the messages: { _id, name, avatar } */
96
- user?: User
97
- /* Locale to localize the dates */
98
- locale?: string
99
- /* Format to use for rendering times; default is 'LT' */
100
- timeFormat?: string
101
- /* Format to use for rendering dates; default is 'll' */
102
- dateFormat?: string
103
- /* Enables the "Load earlier messages" button */
104
- loadEarlier?: boolean
105
- /* Display an ActivityIndicator when loading earlier messages */
106
- isLoadingEarlier?: boolean
107
- /* Determine whether to handle keyboard awareness inside the plugin. If you have your own keyboard handling outside the plugin set this to false; default is `true` */
108
- isKeyboardInternallyHandled?: boolean
109
- /* Whether to render an avatar for the current user; default is false, only show avatars for other users */
110
- showUserAvatar?: boolean
111
- /* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
112
- showAvatarForEveryMessage?: boolean
113
- /* Render the message avatar at the top of consecutive messages, rather than the bottom; default is false */
114
- renderAvatarOnTop?: boolean
115
- inverted?: boolean
116
- /* Extra props to be passed to the <Image> component created by the default renderMessageImage */
117
- imageProps?: Message<TMessage>['props']
118
- /* Extra props to be passed to the MessageImage's Lightbox */
119
- lightboxProps?: LightboxProps
120
- /* Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar); default is 0 */
121
- bottomOffset?: number
122
- /* Focus on <TextInput> automatically when opening the keyboard; default is true */
123
- focusOnInputWhenOpeningKeyboard?: boolean
124
- /* Minimum height of the input toolbar; default is 44 */
125
- minInputToolbarHeight?: number
126
- /* Extra props to be passed to the messages <ListView>; some props can't be overridden, see the code in MessageContainer.render() for details */
127
- listViewProps?: object
128
- /* Extra props to be passed to the <TextInput> */
129
- textInputProps?: object
130
- /* Determines whether the keyboard should stay visible after a tap; see <ScrollView> docs */
131
- keyboardShouldPersistTaps?: 'always' | 'never' | 'handled'
132
- /* Max message composer TextInput length */
133
- maxInputLength?: number
134
- /* Force send button */
135
- alwaysShowSend?: boolean
136
- /* Image style */
137
- imageStyle?: StyleProp<ViewStyle>
138
- /* This can be used to pass unknown data which needs to be re-rendered */
139
- extraData?: object
140
- /* composer min Height */
141
- minComposerHeight?: number
142
- /* composer min Height */
143
- maxComposerHeight?: number
144
- options?: { [key: string]: () => void }
145
- optionTintColor?: string
146
- quickReplyStyle?: StyleProp<ViewStyle>
147
- quickReplyTextStyle?: StyleProp<TextStyle>
148
- quickReplyContainerStyle?: StyleProp<ViewStyle>
149
- /* optional prop used to place customView below text, image and video views; default is false */
150
- isCustomViewBottom?: boolean
151
- /* infinite scroll up when reach the top of messages container, automatically call onLoadEarlier function if exist */
152
- infiniteScroll?: boolean
153
- timeTextStyle?: LeftRightStyle<TextStyle>
154
- /** If you use translucent status bar on Android, set this option to true. Ignored on iOS. */
155
- isStatusBarTranslucentAndroid?: boolean
156
- /* Custom action sheet */
157
- actionSheet?(): {
158
- showActionSheetWithOptions: (
159
- options: ActionSheetOptions,
160
- callback: (buttonIndex: number) => void | Promise<void>,
161
- ) => void
162
- }
163
- /* Callback when a message avatar is tapped */
164
- onPressAvatar?(user: User): void
165
- /* Callback when a message avatar is tapped */
166
- onLongPressAvatar?(user: User): void
167
- /* Generate an id for new messages. Defaults to UUID v4, generated by uuid */
168
- messageIdGenerator?(message?: TMessage): string
169
- /* Callback when sending a message */
170
- onSend?(messages: TMessage[]): void
171
- /* Callback when loading earlier messages */
172
- onLoadEarlier?(): void
173
- /* Render a loading view when initializing */
174
- renderLoading?(): React.ReactNode
175
- /* Custom "Load earlier messages" button */
176
- renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode
177
- /* Custom message avatar; set to null to not render any avatar for the message */
178
- renderAvatar?: null | ((props: AvatarProps<TMessage>) => React.ReactNode)
179
- /* Custom message bubble */
180
- renderBubble?(props: Bubble<TMessage>['props']): React.ReactNode
181
- /* Custom system message */
182
- renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
183
- /* Callback when a message bubble is pressed; default is to do nothing */
184
- onPress?(context: unknown, message: TMessage): void
185
- /* Callback when a message bubble is long-pressed; default is to show an ActionSheet with "Copy Text" (see example using showActionSheetWithOptions()) */
186
- onLongPress?(context: unknown, message: TMessage): void
187
- /* Custom Username container */
188
- renderUsername?(user: User): React.ReactNode
189
- /* Reverses display order of messages; default is true */
190
- /* Custom message container */
191
- renderMessage?(message: Message<TMessage>['props']): React.ReactElement
192
- /* Custom message text */
193
- renderMessageText?(messageText: MessageTextProps<TMessage>): React.ReactNode
194
- /* Custom message image */
195
- renderMessageImage?(props: MessageImageProps<TMessage>): React.ReactNode
196
- /* Custom message video */
197
- renderMessageVideo?(props: MessageVideoProps<TMessage>): React.ReactNode
198
- /* Custom message video */
199
- renderMessageAudio?(props: MessageAudioProps<TMessage>): React.ReactNode
200
- /* Custom view inside the bubble */
201
- renderCustomView?(props: Bubble<TMessage>['props']): React.ReactNode
202
- /* Custom day above a message */
203
- renderDay?(props: DayProps<TMessage>): React.ReactNode
204
- /* Custom time inside a message */
205
- renderTime?(props: TimeProps<TMessage>): React.ReactNode
206
- /* Custom footer component on the ListView, e.g. 'User is typing...' */
207
- renderFooter?(): React.ReactNode
208
- /* Custom component to render in the ListView when messages are empty */
209
- renderChatEmpty?(): React.ReactNode
210
- /* Custom component to render below the MessageContainer (separate from the ListView) */
211
- renderChatFooter?(): React.ReactNode
212
- /* Custom message composer container */
213
- renderInputToolbar?(props: InputToolbarProps<TMessage>): React.ReactNode
214
- /* Custom text input message composer */
215
- renderComposer?(props: ComposerProps): React.ReactNode
216
- /* Custom action button on the left of the message composer */
217
- renderActions?(props: ActionsProps): React.ReactNode
218
- /* Custom send button; you can pass children to the original Send component quite easily, for example to use a custom icon (example) */
219
- renderSend?(props: SendProps<TMessage>): React.ReactNode
220
- /* Custom second line of actions below the message composer */
221
- renderAccessory?(props: InputToolbarProps<TMessage>): React.ReactNode
222
- /* Callback when the Action button is pressed (if set, the default actionSheet will not be used) */
223
- onPressActionButton?(): void
224
- /* Callback when the input text changes */
225
- onInputTextChanged?(text: string): void
226
- /* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */
227
- parsePatterns?: (linkStyle?: TextStyle) => { type?: string, pattern?: RegExp, style?: StyleProp<TextStyle> | object, onPress?: unknown, renderText?: unknown }[]
228
- onQuickReply?(replies: Reply[]): void
229
- renderQuickReplies?(
230
- quickReplies: QuickRepliesProps<TMessage>,
231
- ): React.ReactNode
232
- renderQuickReplySend?(): React.ReactNode
233
- /* Scroll to bottom custom component */
234
- scrollToBottomComponent?(): React.ReactNode
235
- shouldUpdateMessage?(
236
- props: Message<TMessage>['props'],
237
- nextProps: Message<TMessage>['props'],
238
- ): boolean
239
- }
240
-
241
- function GiftedChat<TMessage extends IMessage = IMessage> (
242
- props: GiftedChatProps
243
- ) {
244
- const {
245
- messages = [],
246
- initialText = '',
247
- isTyping,
248
- messageIdGenerator = () => uuidv4(),
249
- user = {},
250
- onSend,
251
- locale = 'en',
252
- renderLoading,
253
- actionSheet = null,
254
- textInputProps,
255
- renderChatFooter = null,
256
- renderInputToolbar = null,
257
- bottomOffset = 0,
258
- focusOnInputWhenOpeningKeyboard = true,
259
- keyboardShouldPersistTaps = Platform.select({
260
- ios: 'never',
261
- android: 'always',
262
- default: 'never',
263
- }),
264
- onInputTextChanged = null,
265
- maxInputLength = null,
266
- inverted = true,
267
- minComposerHeight = MIN_COMPOSER_HEIGHT,
268
- maxComposerHeight = MAX_COMPOSER_HEIGHT,
269
- isKeyboardInternallyHandled = true,
270
- isStatusBarTranslucentAndroid,
271
- } = props
272
-
273
- const actionSheetRef = useRef<ActionSheetProviderRef>(null)
274
-
275
- const messageContainerRef = useMemo(
276
- () => props.messageContainerRef || createRef<FlatList<IMessage>>(),
277
- [props.messageContainerRef]
278
- )
279
-
280
- const textInputRef = useMemo(
281
- () => props.textInputRef || createRef<TextInput>(),
282
- [props.textInputRef]
283
- )
284
-
285
- const isTextInputWasFocused: MutableRefObject<boolean> = useRef(false)
286
-
287
- const [isInitialized, setIsInitialized] = useState<boolean>(false)
288
- const [composerHeight, setComposerHeight] = useState<number>(
289
- minComposerHeight!
290
- )
291
- const [text, setText] = useState<string | undefined>(() => props.text || '')
292
- const [isTypingDisabled, setIsTypingDisabled] = useState<boolean>(false)
293
-
294
- const keyboard = useAnimatedKeyboard({ isStatusBarTranslucentAndroid })
295
- const trackingKeyboardMovement = useSharedValue(false)
296
- const debounceEnableTypingTimeoutId = useRef<ReturnType<typeof setTimeout>>()
297
- const insets = useSafeAreaInsets()
298
- const keyboardOffsetBottom = useSharedValue(0)
299
-
300
- const contentStyleAnim = useAnimatedStyle(
301
- () => ({
302
- transform: [
303
- { translateY: -keyboard.height.value + keyboardOffsetBottom.value },
304
- ],
305
- }),
306
- [keyboard, keyboardOffsetBottom]
307
- )
308
-
309
- const getTextFromProp = useCallback(
310
- (fallback: string) => {
311
- if (props.text === undefined)
312
- return fallback
313
-
314
- return props.text
315
- },
316
- [props.text]
317
- )
318
-
319
- /**
320
- * Store text input focus status when keyboard hide to retrieve
321
- * it afterwards if needed.
322
- * `onKeyboardWillHide` may be called twice in sequence so we
323
- * make a guard condition (eg. showing image picker)
324
- */
325
- const handleTextInputFocusWhenKeyboardHide = useCallback(() => {
326
- if (!isTextInputWasFocused.current)
327
- isTextInputWasFocused.current =
328
- textInputRef.current?.isFocused() || false
329
- }, [textInputRef])
330
-
331
- /**
332
- * Refocus the text input only if it was focused before showing keyboard.
333
- * This is needed in some cases (eg. showing image picker).
334
- */
335
- const handleTextInputFocusWhenKeyboardShow = useCallback(() => {
336
- if (
337
- textInputRef.current &&
338
- isTextInputWasFocused.current &&
339
- !textInputRef.current.isFocused()
340
- )
341
- textInputRef.current.focus()
342
-
343
- // Reset the indicator since the keyboard is shown
344
- isTextInputWasFocused.current = false
345
- }, [textInputRef])
346
-
347
- const disableTyping = useCallback(() => {
348
- clearTimeout(debounceEnableTypingTimeoutId.current)
349
- setIsTypingDisabled(true)
350
- }, [])
351
-
352
- const enableTyping = useCallback(() => {
353
- clearTimeout(debounceEnableTypingTimeoutId.current)
354
- setIsTypingDisabled(false)
355
- }, [])
356
-
357
- const debounceEnableTyping = useCallback(() => {
358
- clearTimeout(debounceEnableTypingTimeoutId.current)
359
- debounceEnableTypingTimeoutId.current = setTimeout(() => {
360
- enableTyping()
361
- }, 50)
362
- }, [enableTyping])
363
-
364
- const scrollToBottom = useCallback(
365
- (isAnimated = true) => {
366
- if (!messageContainerRef?.current)
367
- return
368
-
369
- if (inverted) {
370
- messageContainerRef.current.scrollToOffset({
371
- offset: 0,
372
- animated: isAnimated,
373
- })
374
- return
375
- }
376
-
377
- messageContainerRef.current.scrollToEnd({ animated: isAnimated })
378
- },
379
- [inverted, messageContainerRef]
380
- )
381
-
382
- const renderMessages = useMemo(() => {
383
- if (!isInitialized)
384
- return null
385
-
386
- const { messagesContainerStyle, ...messagesContainerProps } = props
387
-
388
- const fragment = (
389
- <View style={[styles.fill, messagesContainerStyle]}>
390
- <MessageContainer
391
- {...messagesContainerProps}
392
- invertibleScrollViewProps={{
393
- inverted,
394
- keyboardShouldPersistTaps,
395
- }}
396
- messages={messages}
397
- forwardRef={messageContainerRef}
398
- isTyping={isTyping}
399
- />
400
- {renderChatFooter?.()}
401
- </View>
402
- )
403
-
404
- return fragment
405
- }, [
406
- isInitialized,
407
- isTyping,
408
- messages,
409
- props,
410
- inverted,
411
- keyboardShouldPersistTaps,
412
- messageContainerRef,
413
- renderChatFooter,
414
- ])
415
-
416
- const notifyInputTextReset = useCallback(() => {
417
- onInputTextChanged?.('')
418
- }, [onInputTextChanged])
419
-
420
- const resetInputToolbar = useCallback(() => {
421
- textInputRef.current?.clear()
422
-
423
- notifyInputTextReset()
424
-
425
- setComposerHeight(minComposerHeight!)
426
- setText(getTextFromProp(''))
427
- enableTyping()
428
- }, [
429
- minComposerHeight,
430
- getTextFromProp,
431
- textInputRef,
432
- notifyInputTextReset,
433
- enableTyping,
434
- ])
435
-
436
- const _onSend = useCallback(
437
- (messages: TMessage[] = [], shouldResetInputToolbar = false) => {
438
- if (!Array.isArray(messages))
439
- messages = [messages]
440
-
441
- const newMessages: TMessage[] = messages.map(message => {
442
- return {
443
- ...message,
444
- user: user!,
445
- createdAt: new Date(),
446
- _id: messageIdGenerator?.(),
447
- }
448
- })
449
-
450
- if (shouldResetInputToolbar === true) {
451
- disableTyping()
452
-
453
- resetInputToolbar()
454
- }
455
-
456
- onSend?.(newMessages)
457
- },
458
- [messageIdGenerator, onSend, user, resetInputToolbar, disableTyping]
459
- )
460
-
461
- const onInputSizeChanged = useCallback(
462
- (size: { height: number }) => {
463
- const newComposerHeight = Math.max(
464
- minComposerHeight!,
465
- Math.min(maxComposerHeight!, size.height)
466
- )
467
-
468
- setComposerHeight(newComposerHeight)
469
- },
470
- [maxComposerHeight, minComposerHeight]
471
- )
472
-
473
- const _onInputTextChanged = useCallback(
474
- (_text: string) => {
475
- if (isTypingDisabled)
476
- return
477
-
478
- onInputTextChanged?.(_text)
479
-
480
- // Only set state if it's not being overridden by a prop.
481
- if (props.text === undefined)
482
- setText(_text)
483
- },
484
- [onInputTextChanged, isTypingDisabled, props.text]
485
- )
486
-
487
- const onInitialLayoutViewLayout = useCallback(
488
- (e: LayoutChangeEvent) => {
489
- if (isInitialized)
490
- return
491
-
492
- const { layout } = e.nativeEvent
493
-
494
- if (layout.height <= 0)
495
- return
496
-
497
- notifyInputTextReset()
498
-
499
- setIsInitialized(true)
500
- setComposerHeight(minComposerHeight!)
501
- setText(getTextFromProp(initialText))
502
- },
503
- [isInitialized, initialText, minComposerHeight, notifyInputTextReset, getTextFromProp]
504
- )
505
-
506
- const inputToolbarFragment = useMemo(() => {
507
- if (!isInitialized)
508
- return null
509
-
510
- const inputToolbarProps = {
511
- ...props,
512
- text: getTextFromProp(text!),
513
- composerHeight: Math.max(minComposerHeight!, composerHeight),
514
- onSend: _onSend,
515
- onInputSizeChanged,
516
- onTextChanged: _onInputTextChanged,
517
- textInputProps: {
518
- ...textInputProps,
519
- ref: textInputRef,
520
- maxLength: isTypingDisabled ? 0 : maxInputLength,
521
- },
522
- }
523
-
524
- if (renderInputToolbar)
525
- return renderInputToolbar(inputToolbarProps)
526
-
527
- return <InputToolbar {...inputToolbarProps} />
528
- }, [
529
- isInitialized,
530
- _onSend,
531
- getTextFromProp,
532
- maxInputLength,
533
- minComposerHeight,
534
- onInputSizeChanged,
535
- props,
536
- text,
537
- renderInputToolbar,
538
- composerHeight,
539
- isTypingDisabled,
540
- textInputRef,
541
- textInputProps,
542
- _onInputTextChanged,
543
- ])
544
-
545
- const contextValues = useMemo(
546
- () => ({
547
- actionSheet:
548
- actionSheet ||
549
- (() => ({
550
- showActionSheetWithOptions:
551
- actionSheetRef.current!.showActionSheetWithOptions,
552
- })),
553
- getLocale: () => locale,
554
- }),
555
- [actionSheet, locale]
556
- )
557
-
558
- useEffect(() => {
559
- if (props.text != null)
560
- setText(props.text)
561
- }, [props.text])
562
-
563
- useEffect(() => {
564
- if (!inverted && messages?.length)
565
- setTimeout(() => scrollToBottom(false), 200)
566
- }, [messages?.length, inverted, scrollToBottom])
567
-
568
- useAnimatedReaction(
569
- () => keyboard.height.value,
570
- (value, prevValue) => {
571
- if (prevValue !== null && value !== prevValue) {
572
- const isKeyboardMovingUp = value > prevValue
573
- if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
574
- trackingKeyboardMovement.value = isKeyboardMovingUp
575
- keyboardOffsetBottom.value = withTiming(
576
- isKeyboardMovingUp ? insets.bottom + bottomOffset : 0,
577
- {
578
- // If `bottomOffset` exists, we change the duration to a smaller value to fix the delay in the keyboard animation speed
579
- duration: bottomOffset ? 150 : 400,
580
- }
581
- )
582
-
583
- if (focusOnInputWhenOpeningKeyboard)
584
- if (isKeyboardMovingUp)
585
- runOnJS(handleTextInputFocusWhenKeyboardShow)()
586
- else
587
- runOnJS(handleTextInputFocusWhenKeyboardHide)()
588
-
589
- if (value === 0) {
590
- runOnJS(enableTyping)()
591
- } else {
592
- runOnJS(disableTyping)()
593
- runOnJS(debounceEnableTyping)()
594
- }
595
- }
596
- }
597
- },
598
- [
599
- keyboard,
600
- trackingKeyboardMovement,
601
- focusOnInputWhenOpeningKeyboard,
602
- insets,
603
- handleTextInputFocusWhenKeyboardHide,
604
- handleTextInputFocusWhenKeyboardShow,
605
- enableTyping,
606
- disableTyping,
607
- debounceEnableTyping,
608
- ]
609
- )
610
-
611
- return (
612
- <GiftedChatContext.Provider value={contextValues}>
613
- <ActionSheetProvider ref={actionSheetRef}>
614
- <View
615
- testID={TEST_ID.WRAPPER}
616
- style={[styles.fill, styles.contentContainer]}
617
- onLayout={onInitialLayoutViewLayout}
618
- >
619
- {isInitialized
620
- ? (
621
- <Animated.View style={[styles.fill, isKeyboardInternallyHandled && contentStyleAnim]}>
622
- {renderMessages}
623
- {inputToolbarFragment}
624
- </Animated.View>
625
- )
626
- : (
627
- renderLoading?.()
628
- )}
629
- </View>
630
- </ActionSheetProvider>
631
- </GiftedChatContext.Provider>
632
- )
633
- }
634
-
635
- GiftedChat.append = <TMessage extends IMessage>(
636
- currentMessages: TMessage[] = [],
637
- messages: TMessage[],
638
- inverted = true
639
- ) => {
640
- if (!Array.isArray(messages))
641
- messages = [messages]
642
-
643
- return inverted
644
- ? messages.concat(currentMessages)
645
- : currentMessages.concat(messages)
646
- }
647
-
648
- GiftedChat.prepend = <TMessage extends IMessage>(
649
- currentMessages: TMessage[] = [],
650
- messages: TMessage[],
651
- inverted = true
652
- ) => {
653
- if (!Array.isArray(messages))
654
- messages = [messages]
655
-
656
- return inverted
657
- ? currentMessages.concat(messages)
658
- : messages.concat(currentMessages)
659
- }
660
-
661
- const styles = StyleSheet.create({
662
- fill: {
663
- flex: 1,
664
- },
665
- contentContainer: {
666
- overflow: 'hidden',
667
- },
668
- })
669
-
670
- export * from './Models'
671
- export {
672
- GiftedChat,
673
- Actions,
674
- Avatar,
675
- Bubble,
676
- SystemMessage,
677
- MessageImage,
678
- MessageText,
679
- Composer,
680
- Day,
681
- InputToolbar,
682
- LoadEarlier,
683
- Message,
684
- MessageContainer,
685
- Send,
686
- Time,
687
- GiftedAvatar,
688
- utils
689
- }