react-native-gifted-chat 2.9.0-alpha.0 → 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +234 -319
  2. package/package.json +2 -2
  3. package/src/Avatar.tsx +12 -12
  4. package/src/Bubble/index.tsx +2 -2
  5. package/src/Bubble/types.ts +22 -22
  6. package/src/Composer.tsx +0 -3
  7. package/src/GiftedAvatar.tsx +1 -1
  8. package/src/GiftedChat/index.tsx +56 -145
  9. package/src/GiftedChat/types.ts +40 -52
  10. package/src/InputToolbar.tsx +6 -6
  11. package/src/Message/index.tsx +5 -6
  12. package/src/Message/types.ts +8 -12
  13. package/src/MessageContainer/components/DayAnimated/types.ts +1 -1
  14. package/src/MessageContainer/components/Item/index.tsx +2 -2
  15. package/src/MessageContainer/components/Item/types.ts +1 -1
  16. package/src/MessageContainer/index.tsx +30 -30
  17. package/src/MessageContainer/styles.ts +12 -5
  18. package/src/MessageContainer/types.ts +12 -16
  19. package/src/MessageImage.tsx +100 -67
  20. package/src/MessageText.tsx +1 -1
  21. package/src/Models.ts +63 -0
  22. package/src/QuickReplies.tsx +1 -1
  23. package/src/Send.tsx +30 -31
  24. package/src/SystemMessage.tsx +1 -1
  25. package/src/Time.tsx +1 -1
  26. package/src/__tests__/GiftedChat.test.tsx +0 -28
  27. package/src/__tests__/Message.test.tsx +2 -2
  28. package/src/__tests__/Send.test.tsx +1 -1
  29. package/src/__tests__/__snapshots__/Actions.test.tsx.snap +2 -86
  30. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +31 -54
  31. package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +3 -89
  32. package/src/__tests__/__snapshots__/Message.test.tsx.snap +2 -2
  33. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +1 -1
  34. package/src/__tests__/__snapshots__/Send.test.tsx.snap +10 -142
  35. package/src/__tests__/data.ts +1 -1
  36. package/src/components/TouchableOpacity.tsx +19 -8
  37. package/src/types.ts +1 -63
  38. package/src/utils.ts +1 -1
@@ -8,26 +8,26 @@ import {
8
8
  import {
9
9
  ActionSheetOptions,
10
10
  } from '@expo/react-native-action-sheet'
11
+ import { KeyboardProvider, KeyboardAvoidingViewProps } from 'react-native-keyboard-controller'
11
12
  import { ActionsProps } from '../Actions'
12
13
  import { AvatarProps } from '../Avatar'
13
14
  import { BubbleProps } from '../Bubble'
14
15
  import { ComposerProps } from '../Composer'
15
16
  import { InputToolbarProps } from '../InputToolbar'
16
- import { MessageProps } from '../Message'
17
17
  import { AnimatedList, MessageContainerProps } from '../MessageContainer'
18
18
  import { MessageImageProps } from '../MessageImage'
19
19
  import { MessageTextProps } from '../MessageText'
20
- import { QuickRepliesProps } from '../QuickReplies'
21
- import { SendProps } from '../Send'
22
- import { SystemMessageProps } from '../SystemMessage'
23
- import { TimeProps } from '../Time'
24
20
  import {
25
21
  IMessage,
26
22
  LeftRightStyle,
27
23
  MessageAudioProps,
28
24
  MessageVideoProps,
29
25
  User,
30
- } from '../types'
26
+ } from '../Models'
27
+ import { QuickRepliesProps } from '../QuickReplies'
28
+ import { SendProps } from '../Send'
29
+ import { SystemMessageProps } from '../SystemMessage'
30
+ import { TimeProps } from '../Time'
31
31
 
32
32
  export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessageContainerProps<TMessage>> {
33
33
  /* Message container ref */
@@ -35,7 +35,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
35
35
  /* text input ref */
36
36
  textInputRef?: RefObject<TextInput>
37
37
  /* Controls whether or not to show user.name property in the message bubble */
38
- renderUsernameOnMessage?: boolean
38
+ isUsernameVisible?: boolean
39
39
  /* Messages container style */
40
40
  messagesContainerStyle?: StyleProp<ViewStyle>
41
41
  /* Input text; default is undefined, but if specified, it will override GiftedChat's internal state */
@@ -51,26 +51,20 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
51
51
  dateFormat?: string
52
52
  /* Format to use for rendering relative times; Today - for now. See more: https://day.js.org/docs/en/plugin/calendar */
53
53
  dateFormatCalendar?: object
54
- /* 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` */
55
- isKeyboardInternallyHandled?: boolean
56
54
  /* Whether to render an avatar for the current user; default is false, only show avatars for other users */
57
- showUserAvatar?: boolean
55
+ isUserAvatarVisible?: boolean
58
56
  /* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
59
- showAvatarForEveryMessage?: boolean
57
+ isAvatarVisibleForEveryMessage?: boolean
60
58
  /* Render the message avatar at the top of consecutive messages, rather than the bottom; default is false */
61
- renderAvatarOnTop?: boolean
59
+ isAvatarOnTop?: boolean
62
60
  /* Extra props to be passed to the <Image> component created by the default renderMessageImage */
63
61
  imageProps?: MessageImageProps<TMessage>
64
- /* Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar); default is 0 */
65
- keyboardBottomOffset?: number
66
- /* Focus on <TextInput> automatically when opening the keyboard; default is true */
67
- focusOnInputWhenOpeningKeyboard?: boolean
68
62
  /* Minimum height of the input toolbar; default is 44 */
69
63
  minInputToolbarHeight?: number
70
64
  /* Extra props to be passed to the <TextInput>. See https://reactnative.dev/docs/textinput */
71
65
  textInputProps?: Partial<React.ComponentProps<typeof TextInput>>
72
66
  /* Force send button */
73
- alwaysShowSend?: boolean
67
+ isSendButtonAlwaysVisible?: boolean
74
68
  /* Image style */
75
69
  imageStyle?: StyleProp<ViewStyle>
76
70
  /* composer min Height */
@@ -86,73 +80,67 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
86
80
  isCustomViewBottom?: boolean
87
81
  timeTextStyle?: LeftRightStyle<TextStyle>
88
82
  /* Custom action sheet */
89
- actionSheet?(): {
83
+ actionSheet?: () => {
90
84
  showActionSheetWithOptions: (
91
85
  options: ActionSheetOptions,
92
86
  callback: (buttonIndex: number) => void | Promise<void>,
93
87
  ) => void
94
88
  }
95
89
  /* Callback when a message avatar is tapped */
96
- onPressAvatar?(user: User): void
90
+ onPressAvatar?: (user: User) => void
97
91
  /* Callback when a message avatar is tapped */
98
- onLongPressAvatar?(user: User): void
99
- /* Generate an id for new messages. Defaults to UUID v4, generated by uuid */
100
- messageIdGenerator?(message?: TMessage): string
92
+ onLongPressAvatar?: (user: User) => void
93
+ /* Generate an id for new messages. Defaults to a simple random string generator */
94
+ messageIdGenerator?: (message?: TMessage) => string
101
95
  /* Callback when sending a message */
102
- onSend?(messages: TMessage[]): void
96
+ onSend?: (messages: TMessage[]) => void
103
97
  /* Render a loading view when initializing */
104
- renderLoading?(): React.ReactNode
98
+ renderLoading?: () => React.ReactNode
105
99
  /* Custom message avatar; set to null to not render any avatar for the message */
106
100
  renderAvatar?: null | ((props: AvatarProps<TMessage>) => React.ReactNode)
107
101
  /* Custom message bubble */
108
- renderBubble?(props: BubbleProps<TMessage>): React.ReactNode
102
+ renderBubble?: (props: BubbleProps<TMessage>) => React.ReactNode
109
103
  /* Custom system message */
110
- renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
104
+ renderSystemMessage?: (props: SystemMessageProps<TMessage>) => React.ReactNode
111
105
  /* Callback when a message bubble is pressed; default is to do nothing */
112
- onPressMessage?(context: unknown, message: TMessage): void
106
+ onPressMessage?: (context: unknown, message: TMessage) => void
113
107
  /* Callback when a message bubble is long-pressed; default is to show an ActionSheet with "Copy Text" (see example using showActionSheetWithOptions()) */
114
- onLongPressMessage?(context: unknown, message: TMessage): void
108
+ onLongPressMessage?: (context: unknown, message: TMessage) => void
115
109
  /* Custom Username container */
116
- renderUsername?(user: User): React.ReactNode
110
+ renderUsername?: (user: User) => React.ReactNode
117
111
  /* Reverses display order of messages; default is true */
118
112
  /* Custom message text */
119
- renderMessageText?(messageText: MessageTextProps<TMessage>): React.ReactNode
113
+ renderMessageText?: (messageText: MessageTextProps<TMessage>) => React.ReactNode
120
114
  /* Custom message image */
121
- renderMessageImage?(props: MessageImageProps<TMessage>): React.ReactNode
115
+ renderMessageImage?: (props: MessageImageProps<TMessage>) => React.ReactNode
122
116
  /* Custom message video */
123
- renderMessageVideo?(props: MessageVideoProps<TMessage>): React.ReactNode
117
+ renderMessageVideo?: (props: MessageVideoProps<TMessage>) => React.ReactNode
124
118
  /* Custom message video */
125
- renderMessageAudio?(props: MessageAudioProps<TMessage>): React.ReactNode
119
+ renderMessageAudio?: (props: MessageAudioProps<TMessage>) => React.ReactNode
126
120
  /* Custom view inside the bubble */
127
- renderCustomView?(props: BubbleProps<TMessage>): React.ReactNode
121
+ renderCustomView?: (props: BubbleProps<TMessage>) => React.ReactNode
128
122
  /* Custom time inside a message */
129
- renderTime?(props: TimeProps<TMessage>): React.ReactNode
123
+ renderTime?: (props: TimeProps<TMessage>) => React.ReactNode
130
124
  /* Custom component to render below the MessageContainer (separate from the ListView) */
131
- renderChatFooter?(): React.ReactNode
125
+ renderChatFooter?: () => React.ReactNode
132
126
  /* Custom message composer container. Can be a component, element, render function, or null */
133
127
  renderInputToolbar?: React.ComponentType<InputToolbarProps<TMessage>> | React.ReactElement | ((props: InputToolbarProps<TMessage>) => React.ReactNode) | null
134
128
  /* Custom text input message composer */
135
- renderComposer?(props: ComposerProps): React.ReactNode
129
+ renderComposer?: (props: ComposerProps) => React.ReactNode
136
130
  /* Custom action button on the left of the message composer */
137
- renderActions?(props: ActionsProps): React.ReactNode
131
+ renderActions?: (props: ActionsProps) => React.ReactNode
138
132
  /* Custom send button; you can pass children to the original Send component quite easily, for example to use a custom icon (example) */
139
- renderSend?(props: SendProps<TMessage>): React.ReactNode
133
+ renderSend?: (props: SendProps<TMessage>) => React.ReactNode
140
134
  /* Custom second line of actions below the message composer */
141
- renderAccessory?(props: InputToolbarProps<TMessage>): React.ReactNode
135
+ renderAccessory?: (props: InputToolbarProps<TMessage>) => React.ReactNode
142
136
  /* Callback when the Action button is pressed (if set, the default actionSheet will not be used) */
143
- onPressActionButton?(): void
144
- /* Callback when the input text changes */
145
- onInputTextChanged?(text: string): void
137
+ onPressActionButton?: () => void
146
138
  /* Extra props to be passed to the MessageText component */
147
139
  messageTextProps?: Partial<MessageTextProps<TMessage>>
148
- /* Custom parse patterns for react-native-autolink used to linking message content (like URLs and phone numbers) */
149
- matchers?: MessageTextProps<TMessage>['matchers']
150
- renderQuickReplies?(
140
+ renderQuickReplies?: (
151
141
  quickReplies: QuickRepliesProps<TMessage>,
152
- ): React.ReactNode
153
- renderQuickReplySend?(): React.ReactNode
154
- shouldUpdateMessage?(
155
- props: MessageProps<TMessage>,
156
- nextProps: MessageProps<TMessage>,
157
- ): boolean
142
+ ) => React.ReactNode
143
+ renderQuickReplySend?: () => React.ReactNode
144
+ keyboardProviderProps?: React.ComponentProps<typeof KeyboardProvider>
145
+ keyboardAvoidingViewProps?: KeyboardAvoidingViewProps
158
146
  }
@@ -4,8 +4,8 @@ import { StyleSheet, View, StyleProp, ViewStyle, useColorScheme } from 'react-na
4
4
  import { Actions, ActionsProps } from './Actions'
5
5
  import { Color } from './Color'
6
6
  import { Composer, ComposerProps } from './Composer'
7
+ import { IMessage } from './Models'
7
8
  import { Send, SendProps } from './Send'
8
- import { IMessage } from './types'
9
9
  import { renderComponentOrElement } from './utils'
10
10
 
11
11
  export interface InputToolbarProps<TMessage extends IMessage> {
@@ -14,11 +14,11 @@ export interface InputToolbarProps<TMessage extends IMessage> {
14
14
  containerStyle?: StyleProp<ViewStyle>
15
15
  primaryStyle?: StyleProp<ViewStyle>
16
16
  accessoryStyle?: StyleProp<ViewStyle>
17
- renderAccessory?(props: InputToolbarProps<TMessage>): React.ReactNode
18
- renderActions?(props: ActionsProps): React.ReactNode
19
- renderSend?(props: SendProps<TMessage>): React.ReactNode
20
- renderComposer?(props: ComposerProps): React.ReactNode
21
- onPressActionButton?(): void
17
+ renderAccessory?: (props: InputToolbarProps<TMessage>) => React.ReactNode
18
+ renderActions?: (props: ActionsProps) => React.ReactNode
19
+ renderSend?: (props: SendProps<TMessage>) => React.ReactNode
20
+ renderComposer?: (props: ComposerProps) => React.ReactNode
21
+ onPressActionButton?: () => void
22
22
  icon?: () => React.ReactNode
23
23
  wrapperStyle?: StyleProp<ViewStyle>
24
24
  }
@@ -3,9 +3,8 @@ import { View } from 'react-native'
3
3
 
4
4
  import { Avatar } from '../Avatar'
5
5
  import { Bubble } from '../Bubble'
6
+ import { IMessage } from '../Models'
6
7
  import { SystemMessage } from '../SystemMessage'
7
-
8
- import { IMessage } from '../types'
9
8
  import { isSameUser, renderComponentOrElement } from '../utils'
10
9
  import styles from './styles'
11
10
  import { MessageProps } from './types'
@@ -22,7 +21,7 @@ export const Message = <TMessage extends IMessage = IMessage>(props: MessageProp
22
21
  position,
23
22
  containerStyle,
24
23
  user,
25
- showUserAvatar,
24
+ isUserAvatarVisible,
26
25
  } = props
27
26
 
28
27
  const renderBubble = useCallback(() => {
@@ -60,7 +59,7 @@ export const Message = <TMessage extends IMessage = IMessage>(props: MessageProp
60
59
  user?._id &&
61
60
  currentMessage?.user &&
62
61
  user._id === currentMessage.user._id &&
63
- !showUserAvatar
62
+ !isUserAvatarVisible
64
63
  )
65
64
  return null
66
65
 
@@ -80,7 +79,7 @@ export const Message = <TMessage extends IMessage = IMessage>(props: MessageProp
80
79
  props,
81
80
  user,
82
81
  currentMessage,
83
- showUserAvatar,
82
+ isUserAvatarVisible,
84
83
  ])
85
84
 
86
85
  if (!currentMessage)
@@ -99,7 +98,7 @@ export const Message = <TMessage extends IMessage = IMessage>(props: MessageProp
99
98
  style={[
100
99
  styles[position].container,
101
100
  { marginBottom: sameUser ? 2 : 10 },
102
- !props.inverted && { marginBottom: 2 },
101
+ !props.isInverted && { marginBottom: 2 },
103
102
  containerStyle?.[position],
104
103
  ]}
105
104
  >
@@ -2,25 +2,21 @@ import { ViewStyle, LayoutChangeEvent } from 'react-native'
2
2
  import { AvatarProps } from '../Avatar'
3
3
  import { BubbleProps } from '../Bubble'
4
4
  import { DayProps } from '../Day'
5
+ import { IMessage, User, LeftRightStyle } from '../Models'
5
6
  import { SystemMessageProps } from '../SystemMessage'
6
- import { IMessage, User, LeftRightStyle } from '../types'
7
7
 
8
8
  export interface MessageProps<TMessage extends IMessage> {
9
- showUserAvatar?: boolean
9
+ isUserAvatarVisible?: boolean
10
10
  position: 'left' | 'right'
11
11
  currentMessage: TMessage
12
12
  nextMessage?: TMessage
13
13
  previousMessage?: TMessage
14
14
  user: User
15
- inverted?: boolean
15
+ isInverted?: boolean
16
16
  containerStyle?: LeftRightStyle<ViewStyle>
17
- renderBubble?(props: BubbleProps<TMessage>): React.ReactNode
18
- renderDay?(props: DayProps): React.ReactNode
19
- renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
20
- renderAvatar?(props: AvatarProps<TMessage>): React.ReactNode
21
- shouldUpdateMessage?(
22
- props: MessageProps<IMessage>,
23
- nextProps: MessageProps<IMessage>,
24
- ): boolean
25
- onMessageLayout?(event: LayoutChangeEvent): void
17
+ renderBubble?: (props: BubbleProps<TMessage>) => React.ReactNode
18
+ renderDay?: (props: DayProps) => React.ReactNode
19
+ renderSystemMessage?: (props: SystemMessageProps<TMessage>) => React.ReactNode
20
+ renderAvatar?: (props: AvatarProps<TMessage>) => React.ReactNode
21
+ onMessageLayout?: (event: LayoutChangeEvent) => void
26
22
  }
@@ -1,5 +1,5 @@
1
1
  import { DayProps } from '../../../Day'
2
- import { IMessage } from '../../../types'
2
+ import { IMessage } from '../../../Models'
3
3
  import { DaysPositions } from '../../types'
4
4
 
5
5
  export interface DayAnimatedProps extends Omit<DayProps, 'createdAt'> {
@@ -2,8 +2,8 @@ import React, { useCallback, useMemo } from 'react'
2
2
  import { LayoutChangeEvent, View } from 'react-native'
3
3
  import Animated, { interpolate, useAnimatedStyle, useDerivedValue, useSharedValue } from 'react-native-reanimated'
4
4
  import { Day } from '../../../Day'
5
- import { Message,MessageProps } from '../../../Message'
6
- import { IMessage } from '../../../types'
5
+ import { Message, MessageProps } from '../../../Message'
6
+ import { IMessage } from '../../../Models'
7
7
  import { isSameDay } from '../../../utils'
8
8
  import { DaysPositions } from '../../types'
9
9
  import { ItemProps } from './types'
@@ -1,4 +1,4 @@
1
- import { IMessage } from '../../../types'
1
+ import { IMessage } from '../../../Models'
2
2
  import { MessageContainerProps, DaysPositions } from '../../types'
3
3
 
4
4
  export interface ItemProps<TMessage extends IMessage> extends MessageContainerProps<TMessage> {
@@ -11,10 +11,9 @@ import { FlatList } from 'react-native-gesture-handler'
11
11
  import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
12
12
  import { LoadEarlierMessages } from '../LoadEarlierMessages'
13
13
  import { warning } from '../logging'
14
+ import { IMessage } from '../Models'
14
15
  import { ReanimatedScrollEvent } from '../reanimatedCompat'
15
-
16
16
  import stylesCommon from '../styles'
17
- import { IMessage } from '../types'
18
17
  import { TypingIndicator } from '../TypingIndicator'
19
18
  import { isSameDay, useCallbackThrottled } from '../utils'
20
19
  import { DayAnimated } from './components/DayAnimated'
@@ -35,23 +34,23 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
35
34
  user,
36
35
  isTyping = false,
37
36
  renderChatEmpty: renderChatEmptyProp,
38
- inverted = true,
37
+ isInverted = true,
39
38
  listProps,
40
- extraData,
41
39
  isScrollToBottomEnabled = false,
42
40
  scrollToBottomOffset = 200,
43
- alignTop = false,
41
+ isAlignedTop = false,
44
42
  scrollToBottomStyle,
45
43
  loadEarlierMessagesProps,
46
44
  renderTypingIndicator: renderTypingIndicatorProp,
47
45
  renderFooter: renderFooterProp,
48
46
  renderLoadEarlier: renderLoadEarlierProp,
49
47
  forwardRef,
50
- handleOnScroll: handleOnScrollProp,
51
48
  scrollToBottomComponent: scrollToBottomComponentProp,
52
49
  renderDay: renderDayProp,
53
50
  } = props
54
51
 
52
+ const listPropsOnScrollProp = listProps?.onScroll
53
+
55
54
  const scrollToBottomOpacity = useSharedValue(0)
56
55
  const isScrollingDown = useSharedValue(false)
57
56
  const lastScrolledY = useSharedValue(0)
@@ -111,14 +110,14 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
111
110
  isScrollingDown.value = true
112
111
  changeScrollToBottomVisibility(false)
113
112
 
114
- if (inverted)
113
+ if (isInverted)
115
114
  scrollTo({ offset: 0, animated })
116
115
  else if (forwardRef?.current)
117
116
  forwardRef.current.scrollToEnd({ animated })
118
- }, [forwardRef, inverted, scrollTo, isScrollingDown, changeScrollToBottomVisibility])
117
+ }, [forwardRef, isInverted, scrollTo, isScrollingDown, changeScrollToBottomVisibility])
119
118
 
120
119
  const handleOnScroll = useCallback((event: ReanimatedScrollEvent) => {
121
- handleOnScrollProp?.(event)
120
+ listPropsOnScrollProp?.(event as any)
122
121
 
123
122
  const {
124
123
  contentOffset: { y: contentOffsetY },
@@ -127,12 +126,12 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
127
126
  } = event
128
127
 
129
128
  isScrollingDown.value =
130
- (inverted && lastScrolledY.value > contentOffsetY) ||
131
- (!inverted && lastScrolledY.value < contentOffsetY)
129
+ (isInverted && lastScrolledY.value > contentOffsetY) ||
130
+ (!isInverted && lastScrolledY.value < contentOffsetY)
132
131
 
133
132
  lastScrolledY.value = contentOffsetY
134
133
 
135
- if (inverted)
134
+ if (isInverted)
136
135
  if (contentOffsetY > scrollToBottomOffset!)
137
136
  changeScrollToBottomVisibility(true)
138
137
  else
@@ -144,7 +143,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
144
143
  changeScrollToBottomVisibility(false)
145
144
  else
146
145
  changeScrollToBottomVisibility(false)
147
- }, [handleOnScrollProp, inverted, scrollToBottomOffset, changeScrollToBottomVisibility, isScrollingDown, lastScrolledY])
146
+ }, [isInverted, scrollToBottomOffset, changeScrollToBottomVisibility, isScrollingDown, lastScrolledY, listPropsOnScrollProp])
148
147
 
149
148
  const restProps = useMemo(() => {
150
149
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -170,9 +169,9 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
170
169
 
171
170
  if (messages && user) {
172
171
  const previousMessage =
173
- (inverted ? messages[index + 1] : messages[index - 1]) || {}
172
+ (isInverted ? messages[index + 1] : messages[index - 1]) || {}
174
173
  const nextMessage =
175
- (inverted ? messages[index - 1] : messages[index + 1]) || {}
174
+ (isInverted ? messages[index - 1] : messages[index + 1]) || {}
176
175
 
177
176
  const messageProps: ItemProps<TMessage> = {
178
177
  ...restProps,
@@ -191,7 +190,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
191
190
  }
192
191
 
193
192
  return null
194
- }, [messages, restProps, inverted, scrolledY, daysPositions, listHeight, user])
193
+ }, [messages, restProps, isInverted, scrolledY, daysPositions, listHeight, user])
195
194
 
196
195
  const emptyContent = useMemo(() => {
197
196
  if (!renderChatEmptyProp)
@@ -202,7 +201,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
202
201
 
203
202
  const renderChatEmpty = useCallback(() => {
204
203
  if (renderChatEmptyProp)
205
- return inverted
204
+ return isInverted
206
205
  ? (
207
206
  emptyContent
208
207
  )
@@ -213,7 +212,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
213
212
  )
214
213
 
215
214
  return <View style={stylesCommon.fill} />
216
- }, [inverted, renderChatEmptyProp, emptyContent])
215
+ }, [isInverted, renderChatEmptyProp, emptyContent])
217
216
 
218
217
  const ListHeaderComponent = useMemo(() => {
219
218
  const content = renderLoadEarlier()
@@ -273,7 +272,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
273
272
  listHeight.value = event.nativeEvent.layout.height
274
273
 
275
274
  if (
276
- !inverted &&
275
+ !isInverted &&
277
276
  messages?.length &&
278
277
  isScrollToBottomEnabled
279
278
  )
@@ -282,7 +281,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
282
281
  }, 500)
283
282
 
284
283
  listProps?.onLayout?.(event)
285
- }, [inverted, messages, doScrollToBottom, listHeight, listProps, isScrollToBottomEnabled])
284
+ }, [isInverted, messages, doScrollToBottom, listHeight, listProps, isScrollToBottomEnabled])
286
285
 
287
286
  const onEndReached = useCallback(() => {
288
287
  if (
@@ -326,7 +325,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
326
325
  }
327
326
 
328
327
  for (const [key, item] of Object.entries(value))
329
- if (isSameDay(newValue.createdAt, item.createdAt) && (inverted ? item.y <= newValue.y : item.y >= newValue.y)) {
328
+ if (isSameDay(newValue.createdAt, item.createdAt) && (isInverted ? item.y <= newValue.y : item.y >= newValue.y)) {
330
329
  delete value[key]
331
330
  break
332
331
  }
@@ -345,7 +344,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
345
344
  {children}
346
345
  </View>
347
346
  )
348
- }, [daysPositions, inverted])
347
+ }, [daysPositions, isInverted])
349
348
 
350
349
  const scrollHandler = useAnimatedScrollHandler({
351
350
  onScroll: event => {
@@ -362,7 +361,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
362
361
  let shouldRemove = messageIndex === -1
363
362
 
364
363
  if (!shouldRemove) {
365
- const prevMessage = messages[messageIndex + (inverted ? 1 : -1)]
364
+ const prevMessage = messages[messageIndex + (isInverted ? 1 : -1)]
366
365
  const message = messages[messageIndex]
367
366
  shouldRemove = !!prevMessage && isSameDay(message, prevMessage)
368
367
  }
@@ -375,36 +374,37 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
375
374
  return value
376
375
  })
377
376
  })
378
- }, [messages, daysPositions, inverted])
377
+ }, [messages, daysPositions, isInverted])
379
378
 
380
379
  return (
381
380
  <View
382
381
  style={[
383
382
  styles.contentContainerStyle,
384
- alignTop ? styles.containerAlignTop : stylesCommon.fill,
383
+ isAlignedTop ? styles.containerAlignTop : stylesCommon.fill,
385
384
  ]}
386
385
  >
387
386
  <AnimatedFlatList
388
- extraData={extraData}
389
387
  ref={forwardRef}
390
388
  keyExtractor={keyExtractor}
391
389
  data={messages}
392
390
  renderItem={renderItem}
393
- inverted={inverted}
391
+ inverted={isInverted}
394
392
  automaticallyAdjustContentInsets={false}
395
393
  style={stylesCommon.fill}
396
394
  ListEmptyComponent={renderChatEmpty}
397
395
  ListFooterComponent={
398
- inverted ? ListHeaderComponent : ListFooterComponent
396
+ isInverted ? ListHeaderComponent : ListFooterComponent
399
397
  }
400
398
  ListHeaderComponent={
401
- inverted ? ListFooterComponent : ListHeaderComponent
399
+ isInverted ? ListFooterComponent : ListHeaderComponent
402
400
  }
403
- onScroll={scrollHandler}
404
401
  scrollEventThrottle={1}
405
402
  onEndReached={onEndReached}
406
403
  onEndReachedThreshold={0.1}
404
+ keyboardDismissMode='interactive'
405
+ keyboardShouldPersistTaps='handled'
407
406
  {...listProps}
407
+ onScroll={scrollHandler}
408
408
  onLayout={onLayoutList}
409
409
  CellRendererComponent={renderCell}
410
410
  />
@@ -1,4 +1,4 @@
1
- import { StyleSheet } from 'react-native'
1
+ import { Platform, StyleSheet } from 'react-native'
2
2
  import { Color } from '../Color'
3
3
 
4
4
  export default StyleSheet.create({
@@ -24,9 +24,16 @@ export default StyleSheet.create({
24
24
  width: 40,
25
25
  borderRadius: 20,
26
26
  backgroundColor: Color.white,
27
- shadowColor: Color.black,
28
- shadowOpacity: 0.5,
29
- shadowOffset: { width: 0, height: 0 },
30
- shadowRadius: 1,
27
+ ...Platform.select({
28
+ ios: {
29
+ shadowColor: Color.black,
30
+ shadowOpacity: 0.5,
31
+ shadowOffset: { width: 0, height: 0 },
32
+ shadowRadius: 1,
33
+ },
34
+ android: {
35
+ elevation: 5,
36
+ },
37
+ }),
31
38
  },
32
39
  })
@@ -6,10 +6,10 @@ import {
6
6
  } from 'react-native'
7
7
  import { FlatList } from 'react-native-gesture-handler'
8
8
 
9
+ import { DayProps } from '../Day'
9
10
  import { LoadEarlierMessagesProps } from '../LoadEarlierMessages'
10
11
  import { MessageProps } from '../Message'
11
- import { ReanimatedScrollEvent } from '../reanimatedCompat'
12
- import { User, IMessage, Reply, DayProps } from '../types'
12
+ import { User, IMessage, Reply } from '../Models'
13
13
  import { TypingIndicatorProps } from '../TypingIndicator/types'
14
14
 
15
15
  export type ListProps<TMessage extends IMessage = IMessage> = Partial<FlatListProps<TMessage>>
@@ -27,37 +27,33 @@ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
27
27
  /** Additional props for FlatList */
28
28
  listProps?: ListProps<TMessage>
29
29
  /** Reverses display order of messages; default is true */
30
- inverted?: boolean
30
+ isInverted?: boolean
31
31
  /** Controls whether or not the message bubbles appear at the top of the chat */
32
- alignTop?: boolean
32
+ isAlignedTop?: boolean
33
33
  /** Enables the isScrollToBottomEnabled Component */
34
34
  isScrollToBottomEnabled?: boolean
35
35
  /** Scroll to bottom wrapper style */
36
36
  scrollToBottomStyle?: StyleProp<ViewStyle>
37
- /** This can be used to pass unknown data which needs to be re-rendered */
38
- extraData?: object
39
37
  /** Distance from bottom before showing scroll to bottom button */
40
38
  scrollToBottomOffset?: number
41
39
  /** Custom component to render when messages are empty */
42
- renderChatEmpty?(): React.ReactNode
40
+ renderChatEmpty?: () => React.ReactNode
43
41
  /** Custom footer component on the ListView, e.g. 'User is typing...' */
44
- renderFooter?(props: MessageContainerProps<TMessage>): React.ReactNode
42
+ renderFooter?: (props: MessageContainerProps<TMessage>) => React.ReactNode
45
43
  /** Custom message container */
46
- renderMessage?(props: MessageProps<TMessage>): React.ReactElement
44
+ renderMessage?: (props: MessageProps<TMessage>) => React.ReactElement
47
45
  /** Custom day above a message */
48
- renderDay?(props: DayProps): React.ReactNode
46
+ renderDay?: (props: DayProps) => React.ReactNode
49
47
  /** Custom "Load earlier messages" button */
50
- renderLoadEarlier?(props: LoadEarlierMessagesProps): React.ReactNode
48
+ renderLoadEarlier?: (props: LoadEarlierMessagesProps) => React.ReactNode
51
49
  /** Custom typing indicator */
52
- renderTypingIndicator?(): React.ReactNode
50
+ renderTypingIndicator?: () => React.ReactNode
53
51
  /** Scroll to bottom custom component */
54
- scrollToBottomComponent?(): React.ReactNode
52
+ scrollToBottomComponent?: () => React.ReactNode
55
53
  /** Callback when quick reply is sent */
56
- onQuickReply?(replies: Reply[]): void
54
+ onQuickReply?: (replies: Reply[]) => void
57
55
  /** Props to pass to the LoadEarlierMessages component. The LoadEarlierMessages button is only visible when isAvailable is true. Includes isAvailable (controls button visibility), isInfiniteScrollEnabled (infinite scroll up when reach the top of messages container, automatically call onPress function if it exists - not yet supported for web), onPress (callback when button is pressed), isLoading (display loading indicator), label (override default "Load earlier messages" text), and styling props (containerStyle, wrapperStyle, textStyle, activityIndicatorStyle, activityIndicatorColor, activityIndicatorSize). */
58
56
  loadEarlierMessagesProps?: LoadEarlierMessagesProps
59
- /** Custom scroll event handler */
60
- handleOnScroll?(event: ReanimatedScrollEvent): void
61
57
  /** Style for TypingIndicator component */
62
58
  typingIndicatorStyle?: StyleProp<ViewStyle>
63
59
  }