react-native-gifted-chat 2.8.0 → 2.8.2-alpha.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 (47) hide show
  1. package/README.md +18 -5
  2. package/lib/Bubble/index.d.ts +3 -27
  3. package/lib/Bubble/index.js +138 -125
  4. package/lib/Bubble/index.js.map +1 -1
  5. package/lib/Bubble/types.d.ts +3 -3
  6. package/lib/GiftedChat/index.js +19 -4
  7. package/lib/GiftedChat/index.js.map +1 -1
  8. package/lib/GiftedChat/types.d.ts +5 -10
  9. package/lib/Message/index.js +7 -12
  10. package/lib/Message/index.js.map +1 -1
  11. package/lib/Message/types.d.ts +2 -2
  12. package/lib/MessageContainer/components/Item/index.js +3 -1
  13. package/lib/MessageContainer/components/Item/index.js.map +1 -1
  14. package/lib/MessageContainer/index.js +69 -46
  15. package/lib/MessageContainer/index.js.map +1 -1
  16. package/lib/MessageContainer/styles.d.ts +3 -2
  17. package/lib/MessageContainer/styles.js +3 -2
  18. package/lib/MessageContainer/styles.js.map +1 -1
  19. package/lib/MessageContainer/types.d.ts +6 -9
  20. package/lib/MessageText.d.ts +11 -7
  21. package/lib/MessageText.js +57 -96
  22. package/lib/MessageText.js.map +1 -1
  23. package/lib/SystemMessage.d.ts +2 -1
  24. package/lib/SystemMessage.js +3 -2
  25. package/lib/SystemMessage.js.map +1 -1
  26. package/lib/utils.d.ts +2 -0
  27. package/lib/utils.js +66 -0
  28. package/lib/utils.js.map +1 -1
  29. package/package.json +37 -30
  30. package/src/Bubble/index.tsx +171 -172
  31. package/src/Bubble/types.ts +3 -3
  32. package/src/GiftedChat/index.tsx +23 -3
  33. package/src/GiftedChat/types.ts +6 -4
  34. package/src/Message/index.tsx +10 -16
  35. package/src/Message/types.ts +2 -2
  36. package/src/MessageContainer/components/Item/index.tsx +1 -0
  37. package/src/MessageContainer/index.tsx +93 -58
  38. package/src/MessageContainer/styles.ts +3 -2
  39. package/src/MessageContainer/types.ts +6 -9
  40. package/src/MessageText.tsx +86 -121
  41. package/src/SystemMessage.tsx +4 -1
  42. package/src/__tests__/DayAnimated.test.tsx +54 -0
  43. package/src/__tests__/GiftedChat.test.tsx +25 -0
  44. package/src/__tests__/__snapshots__/DayAnimated.test.tsx.snap +5 -0
  45. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +25 -0
  46. package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +11 -9
  47. package/src/utils.ts +77 -1
@@ -1,11 +1,11 @@
1
- import React from 'react'
1
+ import React, { JSX, useCallback } from 'react'
2
2
  import {
3
3
  Text,
4
4
  TouchableWithoutFeedback,
5
5
  View,
6
6
  } from 'react-native'
7
7
 
8
- import { GiftedChatContext } from '../GiftedChatContext'
8
+ import { useChatContext } from '../GiftedChatContext'
9
9
  import { QuickReplies } from '../QuickReplies'
10
10
  import { MessageText } from '../MessageText'
11
11
  import { MessageImage } from '../MessageImage'
@@ -22,49 +22,41 @@ import styles from './styles'
22
22
 
23
23
  export * from './types'
24
24
 
25
- export default class Bubble<
26
- TMessage extends IMessage = IMessage,
27
- > extends React.Component<BubbleProps<TMessage>> {
28
- static contextType = GiftedChatContext
29
-
30
- onPress = () => {
31
- if (this.props.onPress)
32
- this.props.onPress(this.context, this.props.currentMessage)
33
- }
34
-
35
- onLongPress = () => {
36
- const {
37
- currentMessage,
38
- onLongPress,
39
- optionTitles,
40
- } = this.props
41
-
42
- if (onLongPress) {
43
- onLongPress(this.context, currentMessage)
44
- return
45
- }
46
-
47
- if (!optionTitles?.length)
48
- return
49
-
50
- const options = optionTitles
51
- const cancelButtonIndex = options.length - 1
52
-
53
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
- ;(this.context as any).actionSheet().showActionSheetWithOptions(
55
- {
56
- options,
57
- cancelButtonIndex,
58
- },
59
- (buttonIndex: number) => {
60
- console.log('onLongPress', { buttonIndex })
61
- }
62
- )
63
- }
64
-
65
- styledBubbleToNext () {
66
- const { currentMessage, nextMessage, position, containerToNextStyle } =
67
- this.props
25
+ const Bubble = <TMessage extends IMessage = IMessage>(props: BubbleProps<TMessage>): JSX.Element => {
26
+ const {
27
+ currentMessage,
28
+ nextMessage,
29
+ position,
30
+ containerToNextStyle,
31
+ previousMessage,
32
+ containerToPreviousStyle,
33
+ onQuickReply,
34
+ renderQuickReplySend,
35
+ quickReplyStyle,
36
+ quickReplyTextStyle,
37
+ quickReplyContainerStyle,
38
+ containerStyle,
39
+ wrapperStyle,
40
+ bottomContainerStyle,
41
+ onPress: onPressProp,
42
+ onLongPress: onLongPressProp,
43
+ } = props
44
+
45
+ const context = useChatContext()
46
+
47
+ const onPress = useCallback(() => {
48
+ onPressProp?.(context, currentMessage)
49
+ }, [onPressProp, context, currentMessage])
50
+
51
+ const onLongPress = useCallback(() => {
52
+ onLongPressProp?.(context, currentMessage)
53
+ }, [
54
+ currentMessage,
55
+ context,
56
+ onLongPressProp,
57
+ ])
58
+
59
+ const styledBubbleToNext = useCallback(() => {
68
60
  if (
69
61
  currentMessage &&
70
62
  nextMessage &&
@@ -78,15 +70,14 @@ export default class Bubble<
78
70
  ]
79
71
 
80
72
  return null
81
- }
82
-
83
- styledBubbleToPrevious () {
84
- const {
85
- currentMessage,
86
- previousMessage,
87
- position,
88
- containerToPreviousStyle,
89
- } = this.props
73
+ }, [
74
+ currentMessage,
75
+ nextMessage,
76
+ position,
77
+ containerToNextStyle,
78
+ ])
79
+
80
+ const styledBubbleToPrevious = useCallback(() => {
90
81
  if (
91
82
  currentMessage &&
92
83
  previousMessage &&
@@ -96,23 +87,18 @@ export default class Bubble<
96
87
  )
97
88
  return [
98
89
  styles[position].containerToPrevious,
99
- containerToPreviousStyle && containerToPreviousStyle[position],
90
+ containerToPreviousStyle?.[position],
100
91
  ]
101
92
 
102
93
  return null
103
- }
104
-
105
- renderQuickReplies () {
106
- const {
107
- currentMessage,
108
- onQuickReply,
109
- nextMessage,
110
- renderQuickReplySend,
111
- quickReplyStyle,
112
- quickReplyTextStyle,
113
- quickReplyContainerStyle,
114
- } = this.props
115
-
94
+ }, [
95
+ currentMessage,
96
+ previousMessage,
97
+ position,
98
+ containerToPreviousStyle,
99
+ ])
100
+
101
+ const renderQuickReplies = useCallback(() => {
116
102
  if (currentMessage?.quickReplies) {
117
103
  const {
118
104
  /* eslint-disable @typescript-eslint/no-unused-vars */
@@ -120,10 +106,10 @@ export default class Bubble<
120
106
  wrapperStyle,
121
107
  /* eslint-enable @typescript-eslint/no-unused-vars */
122
108
  ...quickReplyProps
123
- } = this.props
109
+ } = props
124
110
 
125
- if (this.props.renderQuickReplies)
126
- return this.props.renderQuickReplies(quickReplyProps)
111
+ if (props.renderQuickReplies)
112
+ return props.renderQuickReplies(quickReplyProps)
127
113
 
128
114
  return (
129
115
  <QuickReplies
@@ -139,46 +125,55 @@ export default class Bubble<
139
125
  }
140
126
 
141
127
  return null
142
- }
143
-
144
- renderMessageText () {
145
- if (this.props.currentMessage?.text) {
128
+ }, [
129
+ currentMessage,
130
+ onQuickReply,
131
+ renderQuickReplySend,
132
+ quickReplyStyle,
133
+ quickReplyTextStyle,
134
+ quickReplyContainerStyle,
135
+ nextMessage,
136
+ props,
137
+ ])
138
+
139
+ const renderMessageText = useCallback(() => {
140
+ if (currentMessage?.text) {
146
141
  const {
147
142
  /* eslint-disable @typescript-eslint/no-unused-vars */
148
143
  containerStyle,
149
144
  wrapperStyle,
150
- optionTitles,
151
145
  /* eslint-enable @typescript-eslint/no-unused-vars */
152
146
  ...messageTextProps
153
- } = this.props
154
- if (this.props.renderMessageText)
155
- return this.props.renderMessageText(messageTextProps)
147
+ } = props
148
+
149
+ if (props.renderMessageText)
150
+ return props.renderMessageText(messageTextProps)
156
151
 
157
152
  return <MessageText {...messageTextProps} />
158
153
  }
159
154
  return null
160
- }
155
+ }, [props, currentMessage])
161
156
 
162
- renderMessageImage () {
163
- if (this.props.currentMessage?.image) {
157
+ const renderMessageImage = useCallback(() => {
158
+ if (currentMessage?.image) {
164
159
  const {
165
160
  /* eslint-disable @typescript-eslint/no-unused-vars */
166
161
  containerStyle,
167
162
  wrapperStyle,
168
163
  /* eslint-enable @typescript-eslint/no-unused-vars */
169
164
  ...messageImageProps
170
- } = this.props
165
+ } = props
171
166
 
172
- if (this.props.renderMessageImage)
173
- return this.props.renderMessageImage(messageImageProps)
167
+ if (props.renderMessageImage)
168
+ return props.renderMessageImage(messageImageProps)
174
169
 
175
170
  return <MessageImage {...messageImageProps} />
176
171
  }
177
172
  return null
178
- }
173
+ }, [props, currentMessage])
179
174
 
180
- renderMessageVideo () {
181
- if (!this.props.currentMessage?.video)
175
+ const renderMessageVideo = useCallback(() => {
176
+ if (!currentMessage?.video)
182
177
  return null
183
178
 
184
179
  const {
@@ -187,16 +182,16 @@ export default class Bubble<
187
182
  wrapperStyle,
188
183
  /* eslint-enable @typescript-eslint/no-unused-vars */
189
184
  ...messageVideoProps
190
- } = this.props
185
+ } = props
191
186
 
192
- if (this.props.renderMessageVideo)
193
- return this.props.renderMessageVideo(messageVideoProps)
187
+ if (props.renderMessageVideo)
188
+ return props.renderMessageVideo(messageVideoProps)
194
189
 
195
190
  return <MessageVideo />
196
- }
191
+ }, [props, currentMessage])
197
192
 
198
- renderMessageAudio () {
199
- if (!this.props.currentMessage?.audio)
193
+ const renderMessageAudio = useCallback(() => {
194
+ if (!currentMessage?.audio)
200
195
  return null
201
196
 
202
197
  const {
@@ -205,20 +200,19 @@ export default class Bubble<
205
200
  wrapperStyle,
206
201
  /* eslint-enable @typescript-eslint/no-unused-vars */
207
202
  ...messageAudioProps
208
- } = this.props
203
+ } = props
209
204
 
210
- if (this.props.renderMessageAudio)
211
- return this.props.renderMessageAudio(messageAudioProps)
205
+ if (props.renderMessageAudio)
206
+ return props.renderMessageAudio(messageAudioProps)
212
207
 
213
208
  return <MessageAudio />
214
- }
209
+ }, [props, currentMessage])
215
210
 
216
- renderTicks () {
211
+ const renderTicks = useCallback(() => {
217
212
  const {
218
- currentMessage,
219
213
  renderTicks,
220
214
  user,
221
- } = this.props
215
+ } = props
222
216
 
223
217
  if (renderTicks && currentMessage)
224
218
  return renderTicks(currentMessage)
@@ -237,17 +231,17 @@ export default class Bubble<
237
231
  return (
238
232
  <View style={styles.content.tickView}>
239
233
  {!!currentMessage.sent && (
240
- <Text style={[styles.content.tick, this.props.tickStyle]}>
234
+ <Text style={[styles.content.tick, props.tickStyle]}>
241
235
  {'✓'}
242
236
  </Text>
243
237
  )}
244
238
  {!!currentMessage.received && (
245
- <Text style={[styles.content.tick, this.props.tickStyle]}>
239
+ <Text style={[styles.content.tick, props.tickStyle]}>
246
240
  {'✓'}
247
241
  </Text>
248
242
  )}
249
243
  {!!currentMessage.pending && (
250
- <Text style={[styles.content.tick, this.props.tickStyle]}>
244
+ <Text style={[styles.content.tick, props.tickStyle]}>
251
245
  {'🕓'}
252
246
  </Text>
253
247
  )}
@@ -255,10 +249,13 @@ export default class Bubble<
255
249
  )
256
250
 
257
251
  return null
258
- }
252
+ }, [
253
+ props,
254
+ currentMessage,
255
+ ])
259
256
 
260
- renderTime () {
261
- if (this.props.currentMessage?.createdAt) {
257
+ const renderTime = useCallback(() => {
258
+ if (currentMessage?.createdAt) {
262
259
  const {
263
260
  /* eslint-disable @typescript-eslint/no-unused-vars */
264
261
  containerStyle,
@@ -266,24 +263,23 @@ export default class Bubble<
266
263
  textStyle,
267
264
  /* eslint-enable @typescript-eslint/no-unused-vars */
268
265
  ...timeProps
269
- } = this.props
266
+ } = props
270
267
 
271
- if (this.props.renderTime)
272
- return this.props.renderTime(timeProps)
268
+ if (props.renderTime)
269
+ return props.renderTime(timeProps)
273
270
 
274
271
  return <Time {...timeProps} />
275
272
  }
276
273
  return null
277
- }
274
+ }, [props, currentMessage])
278
275
 
279
- renderUsername () {
276
+ const renderUsername = useCallback(() => {
280
277
  const {
281
- currentMessage,
282
278
  user,
283
279
  renderUsername,
284
- } = this.props
280
+ } = props
285
281
 
286
- if (this.props.renderUsernameOnMessage && currentMessage) {
282
+ if (props.renderUsernameOnMessage && currentMessage) {
287
283
  if (user && currentMessage.user._id === user._id)
288
284
  return null
289
285
 
@@ -294,7 +290,7 @@ export default class Bubble<
294
290
  <View style={styles.content.usernameView}>
295
291
  <Text
296
292
  style={
297
- [styles.content.username, this.props.usernameStyle]
293
+ [styles.content.username, props.usernameStyle]
298
294
  }
299
295
  >
300
296
  {'~ '}
@@ -305,75 +301,78 @@ export default class Bubble<
305
301
  }
306
302
 
307
303
  return null
308
- }
304
+ }, [
305
+ currentMessage,
306
+ props,
307
+ ])
309
308
 
310
- renderCustomView () {
311
- if (this.props.renderCustomView)
312
- return this.props.renderCustomView(this.props)
309
+ const renderCustomView = useCallback(() => {
310
+ if (props.renderCustomView)
311
+ return props.renderCustomView(props)
313
312
 
314
313
  return null
315
- }
314
+ }, [props])
316
315
 
317
- renderBubbleContent () {
316
+ const renderBubbleContent = useCallback(() => {
318
317
  return (
319
318
  <View>
320
- {!this.props.isCustomViewBottom && this.renderCustomView()}
321
- {this.renderMessageImage()}
322
- {this.renderMessageVideo()}
323
- {this.renderMessageAudio()}
324
- {this.renderMessageText()}
325
- {this.props.isCustomViewBottom && this.renderCustomView()}
319
+ {!props.isCustomViewBottom && renderCustomView()}
320
+ {renderMessageImage()}
321
+ {renderMessageVideo()}
322
+ {renderMessageAudio()}
323
+ {renderMessageText()}
324
+ {props.isCustomViewBottom && renderCustomView()}
326
325
  </View>
327
326
  )
328
- }
329
-
330
- render () {
331
- const {
332
- position,
333
- containerStyle,
334
- wrapperStyle,
335
- bottomContainerStyle,
336
- } = this.props
337
-
338
- return (
327
+ }, [
328
+ renderCustomView,
329
+ renderMessageImage,
330
+ renderMessageVideo,
331
+ renderMessageAudio,
332
+ renderMessageText,
333
+ props.isCustomViewBottom,
334
+ ])
335
+
336
+ return (
337
+ <View
338
+ style={[
339
+ stylesCommon.fill,
340
+ styles[position].container,
341
+ containerStyle && containerStyle[position],
342
+ ]}
343
+ >
339
344
  <View
340
345
  style={[
341
- stylesCommon.fill,
342
- styles[position].container,
343
- containerStyle && containerStyle[position],
346
+ styles[position].wrapper,
347
+ styledBubbleToNext(),
348
+ styledBubbleToPrevious(),
349
+ wrapperStyle && wrapperStyle[position],
344
350
  ]}
345
351
  >
346
- <View
347
- style={[
348
- styles[position].wrapper,
349
- this.styledBubbleToNext(),
350
- this.styledBubbleToPrevious(),
351
- wrapperStyle && wrapperStyle[position],
352
- ]}
352
+ <TouchableWithoutFeedback
353
+ onPress={onPress}
354
+ onLongPress={onLongPress}
355
+ accessibilityRole='text'
356
+ {...props.touchableProps}
353
357
  >
354
- <TouchableWithoutFeedback
355
- onPress={this.onPress}
356
- onLongPress={this.onLongPress}
357
- accessibilityRole='text'
358
- {...this.props.touchableProps}
359
- >
360
- <View>
361
- {this.renderBubbleContent()}
362
- <View
363
- style={[
364
- styles[position].bottom,
365
- bottomContainerStyle && bottomContainerStyle[position],
366
- ]}
367
- >
368
- {this.renderUsername()}
369
- {this.renderTime()}
370
- {this.renderTicks()}
371
- </View>
358
+ <View>
359
+ {renderBubbleContent()}
360
+ <View
361
+ style={[
362
+ styles[position].bottom,
363
+ bottomContainerStyle?.[position],
364
+ ]}
365
+ >
366
+ {renderUsername()}
367
+ {renderTime()}
368
+ {renderTicks()}
372
369
  </View>
373
- </TouchableWithoutFeedback>
374
- </View>
375
- {this.renderQuickReplies()}
370
+ </View>
371
+ </TouchableWithoutFeedback>
376
372
  </View>
377
- )
378
- }
373
+ {renderQuickReplies()}
374
+ </View>
375
+ )
379
376
  }
377
+
378
+ export default Bubble
@@ -5,7 +5,7 @@ import {
5
5
  TextStyle,
6
6
  } from 'react-native'
7
7
  import { QuickRepliesProps } from '../QuickReplies'
8
- import { MessageTextProps } from '../MessageText'
8
+ import { MessageTextProps, MessageOption } from '../MessageText'
9
9
  import { MessageImageProps } from '../MessageImage'
10
10
  import { TimeProps } from '../Time'
11
11
  import {
@@ -39,7 +39,7 @@ export type RenderMessageAudioProps<TMessage extends IMessage> = Omit<
39
39
 
40
40
  export type RenderMessageTextProps<TMessage extends IMessage> = Omit<
41
41
  BubbleProps<TMessage>,
42
- 'containerStyle' | 'wrapperStyle'
42
+ 'containerStyle' | 'wrapperStyle' | 'options'
43
43
  > &
44
44
  MessageTextProps<TMessage>
45
45
  /* eslint-enable no-use-before-define */
@@ -54,7 +54,7 @@ export interface BubbleProps<TMessage extends IMessage> {
54
54
  currentMessage: TMessage
55
55
  nextMessage?: TMessage
56
56
  previousMessage?: TMessage
57
- optionTitles?: string[]
57
+ options?: MessageOption[]
58
58
  containerStyle?: LeftRightStyle<ViewStyle>
59
59
  wrapperStyle?: LeftRightStyle<ViewStyle>
60
60
  textStyle?: LeftRightStyle<TextStyle>
@@ -89,6 +89,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
89
89
  minComposerHeight = MIN_COMPOSER_HEIGHT,
90
90
  maxComposerHeight = MAX_COMPOSER_HEIGHT,
91
91
  isKeyboardInternallyHandled = true,
92
+ disableKeyboardController = false,
92
93
  } = props
93
94
 
94
95
  const actionSheetRef = useRef<ActionSheetProviderRef>(null)
@@ -112,7 +113,16 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
112
113
  const [text, setText] = useState<string | undefined>(() => props.text || '')
113
114
  const [isTypingDisabled, setIsTypingDisabled] = useState<boolean>(false)
114
115
 
115
- const keyboard = useReanimatedKeyboardAnimation()
116
+ // Always call the hook, but conditionally use its data
117
+ const keyboardControllerData = useReanimatedKeyboardAnimation()
118
+
119
+ // Create a mock keyboard object when disabled
120
+ const keyboard = useMemo(() => {
121
+ if (disableKeyboardController)
122
+ return { height: { value: 0 } }
123
+ return keyboardControllerData
124
+ }, [disableKeyboardController, keyboardControllerData])
125
+
116
126
  const trackingKeyboardMovement = useSharedValue(false)
117
127
  const debounceEnableTypingTimeoutId = useRef<ReturnType<typeof setTimeout>>(undefined)
118
128
  const keyboardOffsetBottom = useSharedValue(0)
@@ -380,9 +390,14 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
380
390
  setText(props.text)
381
391
  }, [props.text])
382
392
 
393
+ // Only set up keyboard animation when keyboard controller is enabled
383
394
  useAnimatedReaction(
384
- () => -keyboard.height.value,
395
+ () => disableKeyboardController ? 0 : -keyboard.height.value,
385
396
  (value, prevValue) => {
397
+ // Skip keyboard handling when disabled
398
+ if (disableKeyboardController)
399
+ return
400
+
386
401
  if (prevValue !== null && value !== prevValue) {
387
402
  const isKeyboardMovingUp = value > prevValue
388
403
  if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
@@ -420,6 +435,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
420
435
  disableTyping,
421
436
  debounceEnableTyping,
422
437
  bottomOffset,
438
+ disableKeyboardController,
423
439
  ]
424
440
  )
425
441
 
@@ -433,7 +449,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
433
449
  >
434
450
  {isInitialized
435
451
  ? (
436
- <Animated.View style={[stylesCommon.fill, isKeyboardInternallyHandled && contentStyleAnim]}>
452
+ <Animated.View style={[stylesCommon.fill, (isKeyboardInternallyHandled && !disableKeyboardController) && contentStyleAnim]}>
437
453
  {renderMessages}
438
454
  {inputToolbarFragment}
439
455
  </Animated.View>
@@ -448,6 +464,10 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
448
464
  }
449
465
 
450
466
  function GiftedChatWrapper<TMessage extends IMessage = IMessage> (props: GiftedChatProps<TMessage>) {
467
+ // Don't use KeyboardProvider when keyboard controller is disabled
468
+ if (props.disableKeyboardController)
469
+ return <GiftedChat<TMessage> {...props} />
470
+
451
471
  return (
452
472
  <KeyboardProvider>
453
473
  <GiftedChat<TMessage> {...props} />
@@ -31,7 +31,7 @@ import { SendProps } from '../Send'
31
31
  import { SystemMessageProps } from '../SystemMessage'
32
32
  import { TimeProps } from '../Time'
33
33
  import { AnimatedList, ListViewProps, MessageContainerProps } from '../MessageContainer'
34
- import Bubble from '../Bubble'
34
+ import { BubbleProps } from '../Bubble'
35
35
 
36
36
  export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessageContainerProps<TMessage>> {
37
37
  /* Message container ref */
@@ -75,6 +75,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
75
75
  isLoadingEarlier?: boolean
76
76
  /* 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` */
77
77
  isKeyboardInternallyHandled?: boolean
78
+ /* Completely disable react-native-keyboard-controller. Useful when using react-native-navigation or other conflicting keyboard libraries; default is `false` */
79
+ disableKeyboardController?: boolean
78
80
  /* Whether to render an avatar for the current user; default is false, only show avatars for other users */
79
81
  showUserAvatar?: boolean
80
82
  /* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
@@ -144,7 +146,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
144
146
  /* Custom message avatar; set to null to not render any avatar for the message */
145
147
  renderAvatar?: null | ((props: AvatarProps<TMessage>) => React.ReactNode)
146
148
  /* Custom message bubble */
147
- renderBubble?(props: Bubble<TMessage>['props']): React.ReactNode
149
+ renderBubble?(props: BubbleProps<TMessage>): React.ReactNode
148
150
  /* Custom system message */
149
151
  renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
150
152
  /* Callback when a message bubble is pressed; default is to do nothing */
@@ -165,7 +167,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
165
167
  /* Custom message video */
166
168
  renderMessageAudio?(props: MessageAudioProps<TMessage>): React.ReactNode
167
169
  /* Custom view inside the bubble */
168
- renderCustomView?(props: Bubble<TMessage>['props']): React.ReactNode
170
+ renderCustomView?(props: BubbleProps<TMessage>): React.ReactNode
169
171
  /* Custom day above a message */
170
172
  renderDay?(props: DayProps): React.ReactNode
171
173
  /* Custom time inside a message */
@@ -191,7 +193,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
191
193
  /* Callback when the input text changes */
192
194
  onInputTextChanged?(text: string): void
193
195
  /* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */
194
- parsePatterns?: (linkStyle?: TextStyle) => { type?: string, pattern?: RegExp, style?: StyleProp<TextStyle> | object, onPress?: unknown, renderText?: unknown }[]
196
+ matchers?: MessageTextProps<TMessage>['matchers']
195
197
  onQuickReply?(replies: Reply[]): void
196
198
  renderQuickReplies?(
197
199
  quickReplies: QuickRepliesProps<TMessage>,
@@ -114,22 +114,16 @@ let Message: React.FC<MessageProps<IMessage>> = (props: MessageProps<IMessage>)
114
114
  }
115
115
 
116
116
  Message = memo(Message, (props, nextProps) => {
117
- const next = nextProps.currentMessage!
118
- const current = props.currentMessage!
119
- const { previousMessage, nextMessage } = props
120
- const nextPropsMessage = nextProps.nextMessage
121
- const nextPropsPreviousMessage = nextProps.previousMessage
122
-
123
- let shouldUpdate =
124
- props.shouldUpdateMessage?.(props, nextProps) || false
125
-
126
- shouldUpdate =
127
- shouldUpdate ||
128
- !isEqual(current, next) ||
129
- !isEqual(previousMessage, nextPropsPreviousMessage) ||
130
- !isEqual(nextMessage, nextPropsMessage)
131
-
132
- return shouldUpdate
117
+ const shouldUpdate =
118
+ props.shouldUpdateMessage?.(props, nextProps) ||
119
+ !isEqual(props.currentMessage!, nextProps.currentMessage!) ||
120
+ !isEqual(props.previousMessage, nextProps.previousMessage) ||
121
+ !isEqual(props.nextMessage, nextProps.nextMessage)
122
+
123
+ if (shouldUpdate)
124
+ return false
125
+
126
+ return true
133
127
  })
134
128
 
135
129
  export default Message