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