react-native-gifted-chat 2.8.2-alpha.0 → 2.8.2-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 (191) hide show
  1. package/README.md +8 -12
  2. package/package.json +20 -21
  3. package/src/Bubble/index.tsx +11 -10
  4. package/src/Bubble/types.ts +2 -2
  5. package/src/Composer.tsx +19 -26
  6. package/src/Constant.ts +0 -1
  7. package/src/GiftedAvatar.tsx +29 -36
  8. package/src/GiftedChat/index.tsx +11 -62
  9. package/src/GiftedChat/types.ts +5 -52
  10. package/src/InputToolbar.tsx +25 -8
  11. package/src/LoadEarlier.tsx +19 -17
  12. package/src/MessageAudio.tsx +19 -7
  13. package/src/MessageContainer/components/DayAnimated/index.tsx +14 -9
  14. package/src/MessageContainer/components/Item/index.tsx +7 -1
  15. package/src/MessageContainer/index.tsx +47 -28
  16. package/src/MessageContainer/types.ts +31 -6
  17. package/src/MessageImage.tsx +18 -6
  18. package/src/MessageText.tsx +18 -23
  19. package/src/MessageVideo.tsx +19 -7
  20. package/src/QuickReplies.tsx +17 -10
  21. package/src/Send.tsx +7 -1
  22. package/src/SystemMessage.tsx +9 -2
  23. package/src/Time.tsx +9 -2
  24. package/src/TypingIndicator/index.tsx +2 -1
  25. package/src/TypingIndicator/types.ts +3 -0
  26. package/src/__tests__/Actions.test.tsx +3 -4
  27. package/src/__tests__/Avatar.test.tsx +5 -6
  28. package/src/__tests__/Bubble.test.tsx +14 -19
  29. package/src/__tests__/Composer.test.tsx +3 -4
  30. package/src/__tests__/Day.test.tsx +5 -8
  31. package/src/__tests__/DayAnimated.test.tsx +11 -13
  32. package/src/__tests__/GiftedAvatar.test.tsx +3 -8
  33. package/src/__tests__/GiftedChat.test.tsx +32 -41
  34. package/src/__tests__/InputToolbar.test.tsx +3 -4
  35. package/src/__tests__/LoadEarlier.test.tsx +3 -4
  36. package/src/__tests__/Message.test.tsx +51 -58
  37. package/src/__tests__/MessageContainer.test.tsx +39 -5
  38. package/src/__tests__/MessageImage.test.tsx +12 -15
  39. package/src/__tests__/MessageText.test.tsx +7 -4
  40. package/src/__tests__/Send.test.tsx +7 -8
  41. package/src/__tests__/SystemMessage.test.tsx +12 -15
  42. package/src/__tests__/Time.test.tsx +5 -8
  43. package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +48 -50
  44. package/src/__tests__/__snapshots__/Composer.test.tsx.snap +1 -2
  45. package/src/__tests__/__snapshots__/Constant.test.tsx.snap +0 -1
  46. package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +2 -2
  47. package/src/__tests__/__snapshots__/Message.test.tsx.snap +146 -150
  48. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +12 -10
  49. package/src/__tests__/__snapshots__/MessageText.test.tsx.snap +12 -8
  50. package/src/__tests__/__snapshots__/Send.test.tsx.snap +2 -0
  51. package/src/reanimatedCompat.ts +27 -0
  52. package/src/types.ts +4 -0
  53. package/lib/Actions.d.ts +0 -14
  54. package/lib/Actions.js +0 -57
  55. package/lib/Actions.js.map +0 -1
  56. package/lib/Avatar.d.ts +0 -18
  57. package/lib/Avatar.js +0 -93
  58. package/lib/Avatar.js.map +0 -1
  59. package/lib/Bubble/index.d.ts +0 -6
  60. package/lib/Bubble/index.js +0 -242
  61. package/lib/Bubble/index.js.map +0 -1
  62. package/lib/Bubble/styles.d.ts +0 -69
  63. package/lib/Bubble/styles.js +0 -72
  64. package/lib/Bubble/styles.js.map +0 -1
  65. package/lib/Bubble/types.d.ts +0 -47
  66. package/lib/Bubble/types.js +0 -2
  67. package/lib/Bubble/types.js.map +0 -1
  68. package/lib/Color.d.ts +0 -18
  69. package/lib/Color.js +0 -18
  70. package/lib/Color.js.map +0 -1
  71. package/lib/Composer.d.ts +0 -20
  72. package/lib/Composer.js +0 -60
  73. package/lib/Composer.js.map +0 -1
  74. package/lib/Constant.d.ts +0 -10
  75. package/lib/Constant.js +0 -17
  76. package/lib/Constant.js.map +0 -1
  77. package/lib/Day/index.d.ts +0 -4
  78. package/lib/Day/index.js +0 -39
  79. package/lib/Day/index.js.map +0 -1
  80. package/lib/Day/styles.d.ts +0 -20
  81. package/lib/Day/styles.js +0 -22
  82. package/lib/Day/styles.js.map +0 -1
  83. package/lib/Day/types.d.ts +0 -9
  84. package/lib/Day/types.js +0 -2
  85. package/lib/Day/types.js.map +0 -1
  86. package/lib/GiftedAvatar.d.ts +0 -11
  87. package/lib/GiftedAvatar.js +0 -104
  88. package/lib/GiftedAvatar.js.map +0 -1
  89. package/lib/GiftedChat/index.d.ts +0 -26
  90. package/lib/GiftedChat/index.js +0 -317
  91. package/lib/GiftedChat/index.js.map +0 -1
  92. package/lib/GiftedChat/styles.d.ts +0 -6
  93. package/lib/GiftedChat/styles.js +0 -7
  94. package/lib/GiftedChat/styles.js.map +0 -1
  95. package/lib/GiftedChat/types.d.ts +0 -112
  96. package/lib/GiftedChat/types.js +0 -2
  97. package/lib/GiftedChat/types.js.map +0 -1
  98. package/lib/GiftedChatContext.d.ts +0 -9
  99. package/lib/GiftedChatContext.js +0 -9
  100. package/lib/GiftedChatContext.js.map +0 -1
  101. package/lib/InputToolbar.d.ts +0 -23
  102. package/lib/InputToolbar.js +0 -56
  103. package/lib/InputToolbar.js.map +0 -1
  104. package/lib/LoadEarlier.d.ts +0 -14
  105. package/lib/LoadEarlier.js +0 -45
  106. package/lib/LoadEarlier.js.map +0 -1
  107. package/lib/Message/index.d.ts +0 -6
  108. package/lib/Message/index.js +0 -80
  109. package/lib/Message/index.js.map +0 -1
  110. package/lib/Message/styles.d.ts +0 -21
  111. package/lib/Message/styles.js +0 -22
  112. package/lib/Message/styles.js.map +0 -1
  113. package/lib/Message/types.d.ts +0 -22
  114. package/lib/Message/types.js +0 -2
  115. package/lib/Message/types.js.map +0 -1
  116. package/lib/MessageAudio.d.ts +0 -2
  117. package/lib/MessageAudio.js +0 -14
  118. package/lib/MessageAudio.js.map +0 -1
  119. package/lib/MessageContainer/components/DayAnimated/index.d.ts +0 -5
  120. package/lib/MessageContainer/components/DayAnimated/index.js +0 -85
  121. package/lib/MessageContainer/components/DayAnimated/index.js.map +0 -1
  122. package/lib/MessageContainer/components/DayAnimated/styles.d.ts +0 -11
  123. package/lib/MessageContainer/components/DayAnimated/styles.js +0 -12
  124. package/lib/MessageContainer/components/DayAnimated/styles.js.map +0 -1
  125. package/lib/MessageContainer/components/DayAnimated/types.d.ts +0 -17
  126. package/lib/MessageContainer/components/DayAnimated/types.js +0 -2
  127. package/lib/MessageContainer/components/DayAnimated/types.js.map +0 -1
  128. package/lib/MessageContainer/components/Item/index.d.ts +0 -23
  129. package/lib/MessageContainer/components/Item/index.js +0 -88
  130. package/lib/MessageContainer/components/Item/index.js.map +0 -1
  131. package/lib/MessageContainer/components/Item/types.d.ts +0 -17
  132. package/lib/MessageContainer/components/Item/types.js +0 -2
  133. package/lib/MessageContainer/components/Item/types.js.map +0 -1
  134. package/lib/MessageContainer/index.d.ts +0 -6
  135. package/lib/MessageContainer/index.js +0 -235
  136. package/lib/MessageContainer/index.js.map +0 -1
  137. package/lib/MessageContainer/styles.d.ts +0 -35
  138. package/lib/MessageContainer/styles.js +0 -32
  139. package/lib/MessageContainer/styles.js.map +0 -1
  140. package/lib/MessageContainer/types.d.ts +0 -51
  141. package/lib/MessageContainer/types.js +0 -2
  142. package/lib/MessageContainer/types.js.map +0 -1
  143. package/lib/MessageImage.d.ts +0 -13
  144. package/lib/MessageImage.js +0 -30
  145. package/lib/MessageImage.js.map +0 -1
  146. package/lib/MessageText.d.ts +0 -19
  147. package/lib/MessageText.js +0 -69
  148. package/lib/MessageText.js.map +0 -1
  149. package/lib/MessageVideo.d.ts +0 -2
  150. package/lib/MessageVideo.js +0 -14
  151. package/lib/MessageVideo.js.map +0 -1
  152. package/lib/QuickReplies.d.ts +0 -15
  153. package/lib/QuickReplies.js +0 -101
  154. package/lib/QuickReplies.js.map +0 -1
  155. package/lib/Send.d.ts +0 -15
  156. package/lib/Send.js +0 -34
  157. package/lib/Send.js.map +0 -1
  158. package/lib/SystemMessage.d.ts +0 -11
  159. package/lib/SystemMessage.js +0 -27
  160. package/lib/SystemMessage.js.map +0 -1
  161. package/lib/Time.d.ts +0 -11
  162. package/lib/Time.js +0 -56
  163. package/lib/Time.js.map +0 -1
  164. package/lib/TypingIndicator/index.d.ts +0 -5
  165. package/lib/TypingIndicator/index.js +0 -94
  166. package/lib/TypingIndicator/index.js.map +0 -1
  167. package/lib/TypingIndicator/styles.d.ts +0 -20
  168. package/lib/TypingIndicator/styles.js +0 -22
  169. package/lib/TypingIndicator/styles.js.map +0 -1
  170. package/lib/TypingIndicator/types.d.ts +0 -3
  171. package/lib/TypingIndicator/types.js +0 -2
  172. package/lib/TypingIndicator/types.js.map +0 -1
  173. package/lib/hooks/useUpdateLayoutEffect.d.ts +0 -8
  174. package/lib/hooks/useUpdateLayoutEffect.js +0 -17
  175. package/lib/hooks/useUpdateLayoutEffect.js.map +0 -1
  176. package/lib/index.d.ts +0 -4
  177. package/lib/index.js +0 -5
  178. package/lib/index.js.map +0 -1
  179. package/lib/logging.d.ts +0 -2
  180. package/lib/logging.js +0 -5
  181. package/lib/logging.js.map +0 -1
  182. package/lib/styles.d.ts +0 -10
  183. package/lib/styles.js +0 -11
  184. package/lib/styles.js.map +0 -1
  185. package/lib/types.d.ts +0 -67
  186. package/lib/types.js +0 -2
  187. package/lib/types.js.map +0 -1
  188. package/lib/utils.d.ts +0 -5
  189. package/lib/utils.js +0 -83
  190. package/lib/utils.js.map +0 -1
  191. package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +0 -108
@@ -12,9 +12,7 @@ import { LightboxProps } from 'react-native-lightbox-v2'
12
12
  import { ActionsProps } from '../Actions'
13
13
  import { AvatarProps } from '../Avatar'
14
14
  import { ComposerProps } from '../Composer'
15
- import { DayProps } from '../Day'
16
15
  import { InputToolbarProps } from '../InputToolbar'
17
- import { LoadEarlierProps } from '../LoadEarlier'
18
16
  import { MessageProps } from '../Message'
19
17
  import { MessageImageProps } from '../MessageImage'
20
18
  import { MessageTextProps } from '../MessageText'
@@ -23,14 +21,13 @@ import {
23
21
  LeftRightStyle,
24
22
  MessageAudioProps,
25
23
  MessageVideoProps,
26
- Reply,
27
24
  User,
28
25
  } from '../types'
29
26
  import { QuickRepliesProps } from '../QuickReplies'
30
27
  import { SendProps } from '../Send'
31
28
  import { SystemMessageProps } from '../SystemMessage'
32
29
  import { TimeProps } from '../Time'
33
- import { AnimatedList, ListViewProps, MessageContainerProps } from '../MessageContainer'
30
+ import { AnimatedList, MessageContainerProps } from '../MessageContainer'
34
31
  import { BubbleProps } from '../Bubble'
35
32
 
36
33
  export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessageContainerProps<TMessage>> {
@@ -38,27 +35,13 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
38
35
  messageContainerRef?: RefObject<AnimatedList<TMessage>>
39
36
  /* text input ref */
40
37
  textInputRef?: RefObject<TextInput>
41
- /* Messages to display */
42
- messages?: TMessage[]
43
- /* Typing Indicator state */
44
- isTyping?: boolean
45
38
  /* Controls whether or not to show user.name property in the message bubble */
46
39
  renderUsernameOnMessage?: boolean
47
40
  /* Messages container style */
48
41
  messagesContainerStyle?: StyleProp<ViewStyle>
49
42
  /* Input text; default is undefined, but if specified, it will override GiftedChat's internal state */
50
43
  text?: string
51
- /* Controls whether or not the message bubbles appear at the top of the chat */
52
- alignTop?: boolean
53
- /* enables the isScrollToBottomEnabled Component */
54
- isScrollToBottomEnabled?: boolean
55
- /* Scroll to bottom wrapper style */
56
- scrollToBottomStyle?: StyleProp<ViewStyle>
57
44
  initialText?: string
58
- /* Placeholder when text is empty; default is 'Type a message...' */
59
- placeholder?: string
60
- /* Makes the composer not editable */
61
- disableComposer?: boolean
62
45
  /* User sending the messages: { _id, name, avatar } */
63
46
  user?: User
64
47
  /* Locale to localize the dates */
@@ -69,10 +52,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
69
52
  dateFormat?: string
70
53
  /* Format to use for rendering relative times; Today - for now. See more: https://day.js.org/docs/en/plugin/calendar */
71
54
  dateFormatCalendar?: object
72
- /* Enables the "Load earlier messages" button */
73
- loadEarlier?: boolean
74
- /* Display an ActivityIndicator when loading earlier messages */
75
- isLoadingEarlier?: boolean
76
55
  /* 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
56
  isKeyboardInternallyHandled?: boolean
78
57
  /* Completely disable react-native-keyboard-controller. Useful when using react-native-navigation or other conflicting keyboard libraries; default is `false` */
@@ -83,7 +62,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
83
62
  showAvatarForEveryMessage?: boolean
84
63
  /* Render the message avatar at the top of consecutive messages, rather than the bottom; default is false */
85
64
  renderAvatarOnTop?: boolean
86
- inverted?: boolean
87
65
  /* Extra props to be passed to the <Image> component created by the default renderMessageImage */
88
66
  imageProps?: MessageImageProps<TMessage>
89
67
  /* Extra props to be passed to the MessageImage's Lightbox */
@@ -94,20 +72,12 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
94
72
  focusOnInputWhenOpeningKeyboard?: boolean
95
73
  /* Minimum height of the input toolbar; default is 44 */
96
74
  minInputToolbarHeight?: number
97
- /* Extra props to be passed to the messages <ListView>; some props can't be overridden, see the code in MessageContainer.render() for details */
98
- listViewProps?: ListViewProps
99
- /* Extra props to be passed to the <TextInput> */
100
- textInputProps?: object
101
- /* Determines whether the keyboard should stay visible after a tap; see <ScrollView> docs */
102
- keyboardShouldPersistTaps?: 'always' | 'never' | 'handled'
103
- /* Max message composer TextInput length */
104
- maxInputLength?: number
75
+ /* Extra props to be passed to the <TextInput>. See https://reactnative.dev/docs/textinput */
76
+ textInputProps?: Partial<React.ComponentProps<typeof TextInput>>
105
77
  /* Force send button */
106
78
  alwaysShowSend?: boolean
107
79
  /* Image style */
108
80
  imageStyle?: StyleProp<ViewStyle>
109
- /* This can be used to pass unknown data which needs to be re-rendered */
110
- extraData?: object
111
81
  /* composer min Height */
112
82
  minComposerHeight?: number
113
83
  /* composer min Height */
@@ -119,8 +89,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
119
89
  quickReplyContainerStyle?: StyleProp<ViewStyle>
120
90
  /* optional prop used to place customView below text, image and video views; default is false */
121
91
  isCustomViewBottom?: boolean
122
- /* infinite scroll up when reach the top of messages container, automatically call onLoadEarlier function if exist */
123
- infiniteScroll?: boolean
124
92
  timeTextStyle?: LeftRightStyle<TextStyle>
125
93
  /* Custom action sheet */
126
94
  actionSheet?(): {
@@ -137,12 +105,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
137
105
  messageIdGenerator?(message?: TMessage): string
138
106
  /* Callback when sending a message */
139
107
  onSend?(messages: TMessage[]): void
140
- /* Callback when loading earlier messages */
141
- onLoadEarlier?(): void
142
108
  /* Render a loading view when initializing */
143
109
  renderLoading?(): React.ReactNode
144
- /* Custom "Load earlier messages" button */
145
- renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode
146
110
  /* Custom message avatar; set to null to not render any avatar for the message */
147
111
  renderAvatar?: null | ((props: AvatarProps<TMessage>) => React.ReactNode)
148
112
  /* Custom message bubble */
@@ -150,14 +114,12 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
150
114
  /* Custom system message */
151
115
  renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
152
116
  /* Callback when a message bubble is pressed; default is to do nothing */
153
- onPress?(context: unknown, message: TMessage): void
117
+ onPressMessage?(context: unknown, message: TMessage): void
154
118
  /* Callback when a message bubble is long-pressed; default is to show an ActionSheet with "Copy Text" (see example using showActionSheetWithOptions()) */
155
- onLongPress?(context: unknown, message: TMessage): void
119
+ onLongPressMessage?(context: unknown, message: TMessage): void
156
120
  /* Custom Username container */
157
121
  renderUsername?(user: User): React.ReactNode
158
122
  /* Reverses display order of messages; default is true */
159
- /* Custom message container */
160
- renderMessage?(message: MessageProps<TMessage>): React.ReactElement
161
123
  /* Custom message text */
162
124
  renderMessageText?(messageText: MessageTextProps<TMessage>): React.ReactNode
163
125
  /* Custom message image */
@@ -168,14 +130,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
168
130
  renderMessageAudio?(props: MessageAudioProps<TMessage>): React.ReactNode
169
131
  /* Custom view inside the bubble */
170
132
  renderCustomView?(props: BubbleProps<TMessage>): React.ReactNode
171
- /* Custom day above a message */
172
- renderDay?(props: DayProps): React.ReactNode
173
133
  /* Custom time inside a message */
174
134
  renderTime?(props: TimeProps<TMessage>): React.ReactNode
175
- /* Custom footer component on the ListView, e.g. 'User is typing...' */
176
- renderFooter?(props: MessageContainerProps<TMessage>): React.ReactNode
177
- /* Custom component to render in the ListView when messages are empty */
178
- renderChatEmpty?(): React.ReactNode
179
135
  /* Custom component to render below the MessageContainer (separate from the ListView) */
180
136
  renderChatFooter?(): React.ReactNode
181
137
  /* Custom message composer container */
@@ -194,13 +150,10 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
194
150
  onInputTextChanged?(text: string): void
195
151
  /* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */
196
152
  matchers?: MessageTextProps<TMessage>['matchers']
197
- onQuickReply?(replies: Reply[]): void
198
153
  renderQuickReplies?(
199
154
  quickReplies: QuickRepliesProps<TMessage>,
200
155
  ): React.ReactNode
201
156
  renderQuickReplySend?(): React.ReactNode
202
- /* Scroll to bottom custom component */
203
- scrollToBottomComponent?(): React.ReactNode
204
157
  shouldUpdateMessage?(
205
158
  props: MessageProps<TMessage>,
206
159
  nextProps: MessageProps<TMessage>,
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo } from 'react'
2
- import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native'
2
+ import { StyleSheet, View, StyleProp, ViewStyle, useColorScheme } from 'react-native'
3
3
 
4
4
  import { Composer, ComposerProps } from './Composer'
5
5
  import { Send, SendProps } from './Send'
@@ -38,6 +38,8 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
38
38
  containerStyle,
39
39
  } = props
40
40
 
41
+ const colorScheme = useColorScheme()
42
+
41
43
  const actionsFragment = useMemo(() => {
42
44
  const props = {
43
45
  onPressActionButton,
@@ -69,18 +71,29 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
69
71
  )
70
72
  }, [renderComposer, props])
71
73
 
74
+ const sendFragment = useMemo(() => {
75
+ return renderSend?.(props) || <Send {...props} />
76
+ }, [renderSend, props])
77
+
78
+ const accessoryFragment = useMemo(() => {
79
+ if (!renderAccessory)
80
+ return null
81
+
82
+ return (
83
+ <View style={[styles.accessory, props.accessoryStyle]}>
84
+ {renderAccessory(props)}
85
+ </View>
86
+ )
87
+ }, [renderAccessory, props])
88
+
72
89
  return (
73
- <View style={[styles.container, containerStyle]}>
90
+ <View style={[styles.container, styles[`container_${colorScheme}`], containerStyle]}>
74
91
  <View style={[styles.primary, props.primaryStyle]}>
75
92
  {actionsFragment}
76
93
  {composerFragment}
77
- {renderSend?.(props) || <Send {...props} />}
94
+ {sendFragment}
78
95
  </View>
79
- {renderAccessory && (
80
- <View style={[styles.accessory, props.accessoryStyle]}>
81
- {renderAccessory(props)}
82
- </View>
83
- )}
96
+ {accessoryFragment}
84
97
  </View>
85
98
  )
86
99
  }
@@ -91,6 +104,10 @@ const styles = StyleSheet.create({
91
104
  borderTopColor: Color.defaultColor,
92
105
  backgroundColor: Color.white,
93
106
  },
107
+ container_dark: {
108
+ backgroundColor: '#1a1a1a',
109
+ borderTopColor: '#444',
110
+ },
94
111
  primary: {
95
112
  flexDirection: 'row',
96
113
  alignItems: 'flex-end',
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import {
3
3
  ActivityIndicator,
4
4
  Platform,
@@ -63,6 +63,23 @@ export function LoadEarlier ({
63
63
  activityIndicatorSize = 'small',
64
64
  activityIndicatorStyle,
65
65
  }: LoadEarlierProps): React.ReactElement {
66
+ const loadingContent = useMemo(() => (
67
+ <View>
68
+ <Text style={[styles.text, textStyle, { opacity: 0 }]}>
69
+ {label}
70
+ </Text>
71
+ <ActivityIndicator
72
+ color={activityIndicatorColor!}
73
+ size={activityIndicatorSize!}
74
+ style={[styles.activityIndicator, activityIndicatorStyle]}
75
+ />
76
+ </View>
77
+ ), [label, textStyle, activityIndicatorColor, activityIndicatorSize, activityIndicatorStyle])
78
+
79
+ const labelContent = useMemo(() => (
80
+ <Text style={[styles.text, textStyle]}>{label}</Text>
81
+ ), [label, textStyle])
82
+
66
83
  return (
67
84
  <TouchableOpacity
68
85
  style={[styles.container, containerStyle]}
@@ -71,22 +88,7 @@ export function LoadEarlier ({
71
88
  accessibilityRole='button'
72
89
  >
73
90
  <View style={[stylesCommon.centerItems, styles.wrapper, wrapperStyle]}>
74
- {isLoadingEarlier
75
- ? (
76
- <View>
77
- <Text style={[styles.text, textStyle, { opacity: 0 }]}>
78
- {label}
79
- </Text>
80
- <ActivityIndicator
81
- color={activityIndicatorColor!}
82
- size={activityIndicatorSize!}
83
- style={[styles.activityIndicator, activityIndicatorStyle]}
84
- />
85
- </View>
86
- )
87
- : (
88
- <Text style={[styles.text, textStyle]}>{label}</Text>
89
- )}
91
+ {isLoadingEarlier ? loadingContent : labelContent}
90
92
  </View>
91
93
  </TouchableOpacity>
92
94
  )
@@ -1,16 +1,28 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import Color from './Color'
3
- import { View, Text } from 'react-native'
3
+ import { View, Text, StyleSheet } from 'react-native'
4
+
5
+ const styles = StyleSheet.create({
6
+ container: {
7
+ padding: 20,
8
+ },
9
+ text: {
10
+ color: Color.alizarin,
11
+ fontWeight: '600',
12
+ },
13
+ })
4
14
 
5
15
  export function MessageAudio () {
6
- return (
7
- <View style={{ padding: 20 }}>
8
- <Text style={{ color: Color.alizarin, fontWeight: '600' }}>
16
+ const content = useMemo(() => (
17
+ <View style={styles.container}>
18
+ <Text style={styles.text}>
9
19
  {'Audio is not implemented by GiftedChat.'}
10
20
  </Text>
11
- <Text style={{ color: Color.alizarin, fontWeight: '600' }}>
21
+ <Text style={styles.text}>
12
22
  {'\nYou need to provide your own implementation by using renderMessageAudio prop.'}
13
23
  </Text>
14
24
  </View>
15
- )
25
+ ), [])
26
+
27
+ return content
16
28
  }
@@ -114,6 +114,19 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
114
114
  isLoadingEarlierAnim.value = isLoadingEarlier
115
115
  }, [isLoadingEarlierAnim, isLoadingEarlier])
116
116
 
117
+ const dayContent = useMemo(() => {
118
+ if (!createdAt)
119
+ return null
120
+
121
+ return renderDay
122
+ ? renderDay({ ...rest, createdAt })
123
+ : <Day
124
+ {...rest}
125
+ containerStyle={[styles.dayAnimatedDayContainerStyle, rest.containerStyle]}
126
+ createdAt={createdAt}
127
+ />
128
+ }, [createdAt, renderDay, rest])
129
+
117
130
  if (!createdAt)
118
131
  return null
119
132
 
@@ -126,15 +139,7 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
126
139
  style={contentStyle}
127
140
  pointerEvents='none'
128
141
  >
129
- {
130
- renderDay
131
- ? renderDay({ ...rest, createdAt })
132
- : <Day
133
- {...rest}
134
- containerStyle={[styles.dayAnimatedDayContainerStyle, rest.containerStyle]}
135
- createdAt={createdAt}
136
- />
137
- }
142
+ {dayContent}
138
143
  </Animated.View>
139
144
  </Animated.View>
140
145
  )
@@ -33,7 +33,13 @@ export const useRelativeScrolledPositionToBottomOfDay = (
33
33
  const absoluteScrolledPositionToBottomOfDay = useAbsoluteScrolledPositionToBottomOfDay(listHeight, scrolledY, containerHeight, dayBottomMargin, dayTopOffset)
34
34
 
35
35
  // sorted array of days positions by y
36
- const daysPositionsArray = useDerivedValue(() => Object.values(daysPositions.value).sort((a, b) => a.y - b.y))
36
+ const daysPositionsArray = useDerivedValue(() => {
37
+ return Object.values(daysPositions.value).sort((a, b) => {
38
+ 'worklet'
39
+
40
+ return a.y - b.y
41
+ })
42
+ })
37
43
 
38
44
  // find current day position by scrolled position
39
45
  const currentDayPosition = useDerivedValue(() => {
@@ -10,7 +10,7 @@ import {
10
10
  CellRendererProps,
11
11
  } from 'react-native'
12
12
  import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
13
- import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes'
13
+ import { ReanimatedScrollEvent } from '../reanimatedCompat'
14
14
  import DayAnimated from './components/DayAnimated'
15
15
  import Item from './components/Item'
16
16
 
@@ -39,9 +39,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
39
39
  onLoadEarlier,
40
40
  inverted = true,
41
41
  loadEarlier = false,
42
- listViewProps,
43
- invertibleScrollViewProps,
44
- extraData = null,
42
+ listProps,
43
+ extraData,
45
44
  isScrollToBottomEnabled = false,
46
45
  scrollToBottomOffset = 200,
47
46
  alignTop = false,
@@ -73,8 +72,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
73
72
  if (renderTypingIndicatorProp)
74
73
  return renderTypingIndicatorProp()
75
74
 
76
- return <TypingIndicator isTyping={isTyping} />
77
- }, [isTyping, renderTypingIndicatorProp])
75
+ return <TypingIndicator isTyping={isTyping} style={props.typingIndicatorStyle} />
76
+ }, [isTyping, renderTypingIndicatorProp, props.typingIndicatorStyle])
78
77
 
79
78
  const ListFooterComponent = useMemo(() => {
80
79
  if (renderFooterProp)
@@ -151,6 +150,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
151
150
  changeScrollToBottomVisibility(false)
152
151
  }, [handleOnScrollProp, inverted, scrollToBottomOffset, changeScrollToBottomVisibility, isScrollingDown, lastScrolledY])
153
152
 
153
+ const restProps = useMemo(() => {
154
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
155
+ const { messages: _, ...rest } = props
156
+ return rest
157
+ }, [props])
158
+
154
159
  const renderItem = useCallback(({ item, index }: ListRenderItemInfo<unknown>): React.ReactElement | null => {
155
160
  const messageItem = item as TMessage
156
161
 
@@ -167,8 +172,6 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
167
172
  messageItem.user = { _id: 0 }
168
173
  }
169
174
 
170
- const { messages, ...restProps } = props
171
-
172
175
  if (messages && user) {
173
176
  const previousMessage =
174
177
  (inverted ? messages[index + 1] : messages[index - 1]) || {}
@@ -192,22 +195,29 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
192
195
  }
193
196
 
194
197
  return null
195
- }, [props, inverted, scrolledY, daysPositions, listHeight, user])
198
+ }, [messages, restProps, inverted, scrolledY, daysPositions, listHeight, user])
199
+
200
+ const emptyContent = useMemo(() => {
201
+ if (!renderChatEmptyProp)
202
+ return null
203
+
204
+ return renderChatEmptyProp()
205
+ }, [renderChatEmptyProp])
196
206
 
197
207
  const renderChatEmpty = useCallback(() => {
198
208
  if (renderChatEmptyProp)
199
209
  return inverted
200
210
  ? (
201
- renderChatEmptyProp()
211
+ emptyContent
202
212
  )
203
213
  : (
204
214
  <View style={[stylesCommon.fill, styles.emptyChatContainer]}>
205
- {renderChatEmptyProp()}
215
+ {emptyContent}
206
216
  </View>
207
217
  )
208
218
 
209
219
  return <View style={stylesCommon.fill} />
210
- }, [inverted, renderChatEmptyProp])
220
+ }, [inverted, renderChatEmptyProp, emptyContent])
211
221
 
212
222
  const ListHeaderComponent = useMemo(() => {
213
223
  const content = renderLoadEarlier()
@@ -227,6 +237,25 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
227
237
  return <Text>{'V'}</Text>
228
238
  }, [scrollToBottomComponentProp])
229
239
 
240
+ const handleScrollToBottomPress = useCallback(() => {
241
+ doScrollToBottom()
242
+ }, [doScrollToBottom])
243
+
244
+ const scrollToBottomContent = useMemo(() => {
245
+ return (
246
+ <Animated.View
247
+ style={[
248
+ stylesCommon.centerItems,
249
+ styles.scrollToBottomContent,
250
+ scrollToBottomStyle,
251
+ scrollToBottomStyleAnim,
252
+ ]}
253
+ >
254
+ {renderScrollBottomComponent()}
255
+ </Animated.View>
256
+ )
257
+ }, [scrollToBottomStyle, scrollToBottomStyleAnim, renderScrollBottomComponent])
258
+
230
259
  const ScrollToBottomWrapper = useCallback(() => {
231
260
  if (!isScrollToBottomEnabled)
232
261
  return null
@@ -237,21 +266,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
237
266
  return (
238
267
  <Pressable
239
268
  style={styles.scrollToBottom}
240
- onPress={() => doScrollToBottom()}
269
+ onPress={handleScrollToBottomPress}
241
270
  >
242
- <Animated.View
243
- style={[
244
- stylesCommon.centerItems,
245
- styles.scrollToBottomContent,
246
- scrollToBottomStyle,
247
- scrollToBottomStyleAnim,
248
- ]}
249
- >
250
- {renderScrollBottomComponent()}
251
- </Animated.View>
271
+ {scrollToBottomContent}
252
272
  </Pressable>
253
273
  )
254
- }, [scrollToBottomStyle, renderScrollBottomComponent, doScrollToBottom, scrollToBottomStyleAnim, isScrollToBottomEnabled, isScrollToBottomVisible])
274
+ }, [isScrollToBottomEnabled, isScrollToBottomVisible, handleScrollToBottomPress, scrollToBottomContent])
255
275
 
256
276
  const onLayoutList = useCallback((event: LayoutChangeEvent) => {
257
277
  listHeight.value = event.nativeEvent.layout.height
@@ -265,8 +285,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
265
285
  doScrollToBottom(false)
266
286
  }, 500)
267
287
 
268
- listViewProps?.onLayout?.(event)
269
- }, [inverted, messages, doScrollToBottom, listHeight, listViewProps, isScrollToBottomEnabled])
288
+ listProps?.onLayout?.(event)
289
+ }, [inverted, messages, doScrollToBottom, listHeight, listProps, isScrollToBottomEnabled])
270
290
 
271
291
  const onEndReached = useCallback(() => {
272
292
  if (
@@ -378,7 +398,6 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
378
398
  inverted={inverted}
379
399
  automaticallyAdjustContentInsets={false}
380
400
  style={stylesCommon.fill}
381
- {...invertibleScrollViewProps}
382
401
  ListEmptyComponent={renderChatEmpty}
383
402
  ListFooterComponent={
384
403
  inverted ? ListHeaderComponent : ListFooterComponent
@@ -390,7 +409,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
390
409
  scrollEventThrottle={1}
391
410
  onEndReached={onEndReached}
392
411
  onEndReachedThreshold={0.1}
393
- {...listViewProps}
412
+ {...listProps}
394
413
  onLayout={onLayoutList}
395
414
  CellRendererComponent={renderCell}
396
415
  />
@@ -9,38 +9,63 @@ import {
9
9
  import { LoadEarlierProps } from '../LoadEarlier'
10
10
  import { MessageProps } from '../Message'
11
11
  import { User, IMessage, Reply, DayProps } from '../types'
12
- import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes'
12
+ import { ReanimatedScrollEvent } from '../reanimatedCompat'
13
+ import { TypingIndicatorProps } from '../TypingIndicator/types'
13
14
 
14
- export type ListViewProps<TMessage extends IMessage = IMessage> = Partial<FlatListProps<TMessage>>
15
+ export type ListProps<TMessage extends IMessage = IMessage> = Partial<FlatListProps<TMessage>>
15
16
 
16
17
  export type AnimatedList<TMessage> = FlatList<TMessage>
17
18
 
18
- export interface MessageContainerProps<TMessage extends IMessage = IMessage> {
19
+ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
20
+ extends Omit<TypingIndicatorProps, 'style'> {
21
+ /** Ref for the FlatList message container */
19
22
  forwardRef?: RefObject<AnimatedList<TMessage>>
23
+ /** Messages to display */
20
24
  messages?: TMessage[]
21
- isTyping?: boolean
25
+ /** User sending the messages: { _id, name, avatar } */
22
26
  user?: User
23
- listViewProps?: ListViewProps
27
+ /** Additional props for FlatList */
28
+ listProps?: ListProps<TMessage>
29
+ /** Reverses display order of messages; default is true */
24
30
  inverted?: boolean
31
+ /** Enables the "Load earlier messages" button */
25
32
  loadEarlier?: boolean
33
+ /** Controls whether or not the message bubbles appear at the top of the chat */
26
34
  alignTop?: boolean
35
+ /** Enables the isScrollToBottomEnabled Component */
27
36
  isScrollToBottomEnabled?: boolean
37
+ /** Scroll to bottom wrapper style */
28
38
  scrollToBottomStyle?: StyleProp<ViewStyle>
29
- invertibleScrollViewProps?: object
39
+ /** This can be used to pass unknown data which needs to be re-rendered */
30
40
  extraData?: object
41
+ /** Distance from bottom before showing scroll to bottom button */
31
42
  scrollToBottomOffset?: number
43
+ /** Custom component to render when messages are empty */
32
44
  renderChatEmpty?(): React.ReactNode
45
+ /** Custom footer component on the ListView, e.g. 'User is typing...' */
33
46
  renderFooter?(props: MessageContainerProps<TMessage>): React.ReactNode
47
+ /** Custom message container */
34
48
  renderMessage?(props: MessageProps<TMessage>): React.ReactElement
49
+ /** Custom day above a message */
35
50
  renderDay?(props: DayProps): React.ReactNode
51
+ /** Custom "Load earlier messages" button */
36
52
  renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode
53
+ /** Custom typing indicator */
37
54
  renderTypingIndicator?(): React.ReactNode
55
+ /** Scroll to bottom custom component */
38
56
  scrollToBottomComponent?(): React.ReactNode
57
+ /** Callback when loading earlier messages */
39
58
  onLoadEarlier?(): void
59
+ /** Callback when quick reply is sent */
40
60
  onQuickReply?(replies: Reply[]): void
61
+ /** Infinite scroll up when reach the top of messages container, automatically call onLoadEarlier function if exist */
41
62
  infiniteScroll?: boolean
63
+ /** Display an ActivityIndicator when loading earlier messages */
42
64
  isLoadingEarlier?: boolean
65
+ /** Custom scroll event handler */
43
66
  handleOnScroll?(event: ReanimatedScrollEvent): void
67
+ /** Style for TypingIndicator component */
68
+ typingIndicatorStyle?: StyleProp<ViewStyle>
44
69
  }
45
70
 
46
71
  export interface State {
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import {
3
3
  Image,
4
4
  StyleSheet,
@@ -44,6 +44,20 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
44
44
  imageStyle,
45
45
  currentMessage,
46
46
  }: MessageImageProps<TMessage>) {
47
+ const imageSource = useMemo(() => ({
48
+ ...imageSourceProps,
49
+ uri: currentMessage?.image,
50
+ }), [imageSourceProps, currentMessage?.image])
51
+
52
+ const computedImageStyle = useMemo(() => [
53
+ styles.image,
54
+ imageStyle,
55
+ ], [imageStyle])
56
+
57
+ const activePropsStyle = useMemo(() => [{
58
+ style: [stylesCommon.fill, styles.imageActive],
59
+ }], [])
60
+
47
61
  if (currentMessage == null)
48
62
  return null
49
63
 
@@ -51,15 +65,13 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
51
65
  <View style={containerStyle}>
52
66
  {/* @ts-expect-error: Lightbox types are not fully compatible */}
53
67
  <Lightbox
54
- activeProps={{
55
- style: [stylesCommon.fill, styles.imageActive],
56
- }}
68
+ activeProps={activePropsStyle}
57
69
  {...lightboxProps}
58
70
  >
59
71
  <Image
60
72
  {...imageProps}
61
- style={[styles.image, imageStyle]}
62
- source={{ ...imageSourceProps, uri: currentMessage.image }}
73
+ style={computedImageStyle}
74
+ source={imageSource}
63
75
  />
64
76
  </Lightbox>
65
77
  </View>