react-native-gifted-chat 2.8.1 → 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 (195) hide show
  1. package/README.md +18 -17
  2. package/package.json +41 -35
  3. package/src/Bubble/index.tsx +15 -39
  4. package/src/Bubble/types.ts +5 -5
  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 +34 -65
  9. package/src/GiftedChat/types.ts +8 -53
  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 +104 -64
  16. package/src/MessageContainer/styles.ts +3 -2
  17. package/src/MessageContainer/types.ts +36 -14
  18. package/src/MessageImage.tsx +18 -6
  19. package/src/MessageText.tsx +88 -128
  20. package/src/MessageVideo.tsx +19 -7
  21. package/src/QuickReplies.tsx +17 -10
  22. package/src/Send.tsx +7 -1
  23. package/src/SystemMessage.tsx +12 -2
  24. package/src/Time.tsx +9 -2
  25. package/src/TypingIndicator/index.tsx +2 -1
  26. package/src/TypingIndicator/types.ts +3 -0
  27. package/src/__tests__/Actions.test.tsx +3 -4
  28. package/src/__tests__/Avatar.test.tsx +5 -6
  29. package/src/__tests__/Bubble.test.tsx +14 -19
  30. package/src/__tests__/Composer.test.tsx +3 -4
  31. package/src/__tests__/Day.test.tsx +5 -8
  32. package/src/__tests__/DayAnimated.test.tsx +52 -0
  33. package/src/__tests__/GiftedAvatar.test.tsx +3 -8
  34. package/src/__tests__/GiftedChat.test.tsx +37 -21
  35. package/src/__tests__/InputToolbar.test.tsx +3 -4
  36. package/src/__tests__/LoadEarlier.test.tsx +3 -4
  37. package/src/__tests__/Message.test.tsx +51 -58
  38. package/src/__tests__/MessageContainer.test.tsx +39 -5
  39. package/src/__tests__/MessageImage.test.tsx +12 -15
  40. package/src/__tests__/MessageText.test.tsx +7 -4
  41. package/src/__tests__/Send.test.tsx +7 -8
  42. package/src/__tests__/SystemMessage.test.tsx +12 -15
  43. package/src/__tests__/Time.test.tsx +5 -8
  44. package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +48 -50
  45. package/src/__tests__/__snapshots__/Composer.test.tsx.snap +1 -2
  46. package/src/__tests__/__snapshots__/Constant.test.tsx.snap +0 -1
  47. package/src/__tests__/__snapshots__/DayAnimated.test.tsx.snap +5 -0
  48. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +25 -0
  49. package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +2 -2
  50. package/src/__tests__/__snapshots__/Message.test.tsx.snap +146 -150
  51. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +12 -10
  52. package/src/__tests__/__snapshots__/MessageText.test.tsx.snap +12 -8
  53. package/src/__tests__/__snapshots__/Send.test.tsx.snap +2 -0
  54. package/src/reanimatedCompat.ts +27 -0
  55. package/src/types.ts +4 -0
  56. package/src/utils.ts +77 -1
  57. package/lib/Actions.d.ts +0 -14
  58. package/lib/Actions.js +0 -57
  59. package/lib/Actions.js.map +0 -1
  60. package/lib/Avatar.d.ts +0 -18
  61. package/lib/Avatar.js +0 -93
  62. package/lib/Avatar.js.map +0 -1
  63. package/lib/Bubble/index.d.ts +0 -6
  64. package/lib/Bubble/index.js +0 -257
  65. package/lib/Bubble/index.js.map +0 -1
  66. package/lib/Bubble/styles.d.ts +0 -69
  67. package/lib/Bubble/styles.js +0 -72
  68. package/lib/Bubble/styles.js.map +0 -1
  69. package/lib/Bubble/types.d.ts +0 -47
  70. package/lib/Bubble/types.js +0 -2
  71. package/lib/Bubble/types.js.map +0 -1
  72. package/lib/Color.d.ts +0 -18
  73. package/lib/Color.js +0 -18
  74. package/lib/Color.js.map +0 -1
  75. package/lib/Composer.d.ts +0 -20
  76. package/lib/Composer.js +0 -60
  77. package/lib/Composer.js.map +0 -1
  78. package/lib/Constant.d.ts +0 -10
  79. package/lib/Constant.js +0 -17
  80. package/lib/Constant.js.map +0 -1
  81. package/lib/Day/index.d.ts +0 -4
  82. package/lib/Day/index.js +0 -39
  83. package/lib/Day/index.js.map +0 -1
  84. package/lib/Day/styles.d.ts +0 -20
  85. package/lib/Day/styles.js +0 -22
  86. package/lib/Day/styles.js.map +0 -1
  87. package/lib/Day/types.d.ts +0 -9
  88. package/lib/Day/types.js +0 -2
  89. package/lib/Day/types.js.map +0 -1
  90. package/lib/GiftedAvatar.d.ts +0 -11
  91. package/lib/GiftedAvatar.js +0 -104
  92. package/lib/GiftedAvatar.js.map +0 -1
  93. package/lib/GiftedChat/index.d.ts +0 -26
  94. package/lib/GiftedChat/index.js +0 -302
  95. package/lib/GiftedChat/index.js.map +0 -1
  96. package/lib/GiftedChat/styles.d.ts +0 -6
  97. package/lib/GiftedChat/styles.js +0 -7
  98. package/lib/GiftedChat/styles.js.map +0 -1
  99. package/lib/GiftedChat/types.d.ts +0 -117
  100. package/lib/GiftedChat/types.js +0 -2
  101. package/lib/GiftedChat/types.js.map +0 -1
  102. package/lib/GiftedChatContext.d.ts +0 -9
  103. package/lib/GiftedChatContext.js +0 -9
  104. package/lib/GiftedChatContext.js.map +0 -1
  105. package/lib/InputToolbar.d.ts +0 -23
  106. package/lib/InputToolbar.js +0 -56
  107. package/lib/InputToolbar.js.map +0 -1
  108. package/lib/LoadEarlier.d.ts +0 -14
  109. package/lib/LoadEarlier.js +0 -45
  110. package/lib/LoadEarlier.js.map +0 -1
  111. package/lib/Message/index.d.ts +0 -6
  112. package/lib/Message/index.js +0 -80
  113. package/lib/Message/index.js.map +0 -1
  114. package/lib/Message/styles.d.ts +0 -21
  115. package/lib/Message/styles.js +0 -22
  116. package/lib/Message/styles.js.map +0 -1
  117. package/lib/Message/types.d.ts +0 -22
  118. package/lib/Message/types.js +0 -2
  119. package/lib/Message/types.js.map +0 -1
  120. package/lib/MessageAudio.d.ts +0 -2
  121. package/lib/MessageAudio.js +0 -14
  122. package/lib/MessageAudio.js.map +0 -1
  123. package/lib/MessageContainer/components/DayAnimated/index.d.ts +0 -5
  124. package/lib/MessageContainer/components/DayAnimated/index.js +0 -85
  125. package/lib/MessageContainer/components/DayAnimated/index.js.map +0 -1
  126. package/lib/MessageContainer/components/DayAnimated/styles.d.ts +0 -11
  127. package/lib/MessageContainer/components/DayAnimated/styles.js +0 -12
  128. package/lib/MessageContainer/components/DayAnimated/styles.js.map +0 -1
  129. package/lib/MessageContainer/components/DayAnimated/types.d.ts +0 -17
  130. package/lib/MessageContainer/components/DayAnimated/types.js +0 -2
  131. package/lib/MessageContainer/components/DayAnimated/types.js.map +0 -1
  132. package/lib/MessageContainer/components/Item/index.d.ts +0 -23
  133. package/lib/MessageContainer/components/Item/index.js +0 -88
  134. package/lib/MessageContainer/components/Item/index.js.map +0 -1
  135. package/lib/MessageContainer/components/Item/types.d.ts +0 -17
  136. package/lib/MessageContainer/components/Item/types.js +0 -2
  137. package/lib/MessageContainer/components/Item/types.js.map +0 -1
  138. package/lib/MessageContainer/index.d.ts +0 -6
  139. package/lib/MessageContainer/index.js +0 -224
  140. package/lib/MessageContainer/index.js.map +0 -1
  141. package/lib/MessageContainer/styles.d.ts +0 -34
  142. package/lib/MessageContainer/styles.js +0 -31
  143. package/lib/MessageContainer/styles.js.map +0 -1
  144. package/lib/MessageContainer/types.d.ts +0 -54
  145. package/lib/MessageContainer/types.js +0 -2
  146. package/lib/MessageContainer/types.js.map +0 -1
  147. package/lib/MessageImage.d.ts +0 -13
  148. package/lib/MessageImage.js +0 -30
  149. package/lib/MessageImage.js.map +0 -1
  150. package/lib/MessageText.d.ts +0 -15
  151. package/lib/MessageText.js +0 -108
  152. package/lib/MessageText.js.map +0 -1
  153. package/lib/MessageVideo.d.ts +0 -2
  154. package/lib/MessageVideo.js +0 -14
  155. package/lib/MessageVideo.js.map +0 -1
  156. package/lib/QuickReplies.d.ts +0 -15
  157. package/lib/QuickReplies.js +0 -101
  158. package/lib/QuickReplies.js.map +0 -1
  159. package/lib/Send.d.ts +0 -15
  160. package/lib/Send.js +0 -34
  161. package/lib/Send.js.map +0 -1
  162. package/lib/SystemMessage.d.ts +0 -10
  163. package/lib/SystemMessage.js +0 -26
  164. package/lib/SystemMessage.js.map +0 -1
  165. package/lib/Time.d.ts +0 -11
  166. package/lib/Time.js +0 -56
  167. package/lib/Time.js.map +0 -1
  168. package/lib/TypingIndicator/index.d.ts +0 -5
  169. package/lib/TypingIndicator/index.js +0 -94
  170. package/lib/TypingIndicator/index.js.map +0 -1
  171. package/lib/TypingIndicator/styles.d.ts +0 -20
  172. package/lib/TypingIndicator/styles.js +0 -22
  173. package/lib/TypingIndicator/styles.js.map +0 -1
  174. package/lib/TypingIndicator/types.d.ts +0 -3
  175. package/lib/TypingIndicator/types.js +0 -2
  176. package/lib/TypingIndicator/types.js.map +0 -1
  177. package/lib/hooks/useUpdateLayoutEffect.d.ts +0 -8
  178. package/lib/hooks/useUpdateLayoutEffect.js +0 -17
  179. package/lib/hooks/useUpdateLayoutEffect.js.map +0 -1
  180. package/lib/index.d.ts +0 -4
  181. package/lib/index.js +0 -5
  182. package/lib/index.js.map +0 -1
  183. package/lib/logging.d.ts +0 -2
  184. package/lib/logging.js +0 -5
  185. package/lib/logging.js.map +0 -1
  186. package/lib/styles.d.ts +0 -10
  187. package/lib/styles.js +0 -11
  188. package/lib/styles.js.map +0 -1
  189. package/lib/types.d.ts +0 -67
  190. package/lib/types.js +0 -2
  191. package/lib/types.js.map +0 -1
  192. package/lib/utils.d.ts +0 -3
  193. package/lib/utils.js +0 -17
  194. package/lib/utils.js.map +0 -1
  195. package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +0 -101
@@ -1,164 +1,124 @@
1
- import React from 'react'
1
+ import React, { useMemo, useCallback } from 'react'
2
2
  import {
3
3
  Linking,
4
4
  StyleSheet,
5
- View,
6
- TextProps,
7
5
  StyleProp,
8
6
  ViewStyle,
9
7
  TextStyle,
8
+ View,
10
9
  } from 'react-native'
11
10
 
12
- import ParsedText from 'react-native-parsed-text'
11
+ import Autolink, { AutolinkProps } from 'react-native-autolink'
12
+ import { Match } from 'autolinker/dist/es2015'
13
13
  import { LeftRightStyle, IMessage } from './types'
14
- import { useChatContext } from './GiftedChatContext'
15
14
  import { error } from './logging'
16
15
 
17
- const WWW_URL_PATTERN = /^www\./i
18
-
19
- const { textStyle } = StyleSheet.create({
20
- textStyle: {
21
- fontSize: 16,
22
- lineHeight: 20,
23
- marginTop: 5,
24
- marginBottom: 5,
25
- marginLeft: 10,
26
- marginRight: 10,
27
- },
28
- })
29
-
30
- const styles = {
31
- left: StyleSheet.create({
32
- container: {},
33
- text: {
34
- color: 'black',
35
- ...textStyle,
36
- },
37
- link: {
38
- color: 'black',
39
- textDecorationLine: 'underline',
40
- },
41
- }),
42
- right: StyleSheet.create({
43
- container: {},
44
- text: {
45
- color: 'white',
46
- ...textStyle,
47
- },
48
- link: {
49
- color: 'white',
50
- textDecorationLine: 'underline',
51
- },
52
- }),
16
+ export interface MessageOption {
17
+ title: string
18
+ action: (phone: string) => void
53
19
  }
54
20
 
55
- const DEFAULT_OPTION_TITLES = ['Call', 'Text', 'Cancel']
56
-
57
- export interface MessageTextProps<TMessage extends IMessage> {
21
+ export type MessageTextProps<TMessage extends IMessage> = {
58
22
  position?: 'left' | 'right'
59
- optionTitles?: string[]
60
23
  currentMessage: TMessage
61
24
  containerStyle?: LeftRightStyle<ViewStyle>
62
25
  textStyle?: LeftRightStyle<TextStyle>
63
26
  linkStyle?: LeftRightStyle<TextStyle>
64
- textProps?: TextProps
65
27
  customTextStyle?: StyleProp<TextStyle>
66
- parsePatterns?: (linkStyle: TextStyle) => []
67
- }
28
+ onPress?: (
29
+ message: TMessage,
30
+ url: string,
31
+ match: Match
32
+ ) => void
33
+ } & Omit<AutolinkProps, 'text' | 'onPress'>
68
34
 
69
- export function MessageText<TMessage extends IMessage = IMessage> ({
70
- currentMessage = {} as TMessage,
71
- optionTitles = DEFAULT_OPTION_TITLES,
35
+ export const MessageText: React.FC<MessageTextProps<IMessage>> = ({
36
+ currentMessage = {} as IMessage,
72
37
  position = 'left',
73
38
  containerStyle,
74
39
  textStyle,
75
40
  linkStyle: linkStyleProp,
76
41
  customTextStyle,
77
- parsePatterns,
78
- textProps,
79
- }: MessageTextProps<TMessage>) {
80
- const { actionSheet } = useChatContext()
42
+ onPress: onPressProp,
43
+ ...rest
44
+ }) => {
45
+ const onUrlPress = useCallback((url: string) => {
46
+ if (/^www\./i.test(url))
47
+ url = `https://${url}`
81
48
 
82
- // TODO: React.memo
83
- // const shouldComponentUpdate = (nextProps: MessageTextProps<TMessage>) => {
84
- // return (
85
- // !!currentMessage &&
86
- // !!nextProps.currentMessage &&
87
- // currentMessage.text !== nextProps.currentMessage.text
88
- // )
89
- // }
49
+ Linking.openURL(url).catch(e => {
50
+ error(e, 'No handler for URL:', url)
51
+ })
52
+ }, [])
90
53
 
91
- const onUrlPress = (url: string) => {
92
- // When someone sends a message that includes a website address beginning with "www." (omitting the scheme),
93
- // react-native-parsed-text recognizes it as a valid url, but Linking fails to open due to the missing scheme.
94
- if (WWW_URL_PATTERN.test(url))
95
- onUrlPress(`https://${url}`)
96
- else
97
- Linking.openURL(url).catch(e => {
98
- error(e, 'No handler for URL:', url)
99
- })
100
- }
54
+ const onPhonePress = useCallback((phone: string) => {
55
+ Linking.openURL(`tel:${phone}`).catch(e => {
56
+ error(e, 'No handler for telephone')
57
+ })
58
+ }, [])
101
59
 
102
- const onPhonePress = (phone: string) => {
103
- const options =
104
- optionTitles && optionTitles.length > 0
105
- ? optionTitles.slice(0, 3)
106
- : DEFAULT_OPTION_TITLES
107
- const cancelButtonIndex = options.length - 1
108
- actionSheet().showActionSheetWithOptions(
109
- {
110
- options,
111
- cancelButtonIndex,
112
- },
113
- (buttonIndex?: number) => {
114
- switch (buttonIndex) {
115
- case 0:
116
- Linking.openURL(`tel:${phone}`).catch(e => {
117
- error(e, 'No handler for telephone')
118
- })
119
- break
120
- case 1:
121
- Linking.openURL(`sms:${phone}`).catch(e => {
122
- error(e, 'No handler for text')
123
- })
124
- break
125
- }
126
- }
127
- )
128
- }
129
-
130
- const onEmailPress = (email: string) =>
60
+ const onEmailPress = useCallback((email: string) =>
131
61
  Linking.openURL(`mailto:${email}`).catch(e =>
132
62
  error(e, 'No handler for mailto')
133
- )
63
+ ), [])
134
64
 
135
- const linkStyle = [
136
- styles[position].link,
65
+ const linkStyle = useMemo(() => StyleSheet.flatten([
66
+ styles.link,
137
67
  linkStyleProp?.[position],
138
- ]
68
+ ]), [position, linkStyleProp])
69
+
70
+ const handlePress = useCallback((url: string, match: Match) => {
71
+ const type = match.getType()
72
+
73
+ if (onPressProp)
74
+ onPressProp(currentMessage, url, match)
75
+ else if (type === 'url')
76
+ onUrlPress(url)
77
+ else if (type === 'phone')
78
+ onPhonePress(url)
79
+ else if (type === 'email')
80
+ onEmailPress(url)
81
+ }, [onUrlPress, onPhonePress, onEmailPress, onPressProp, currentMessage])
82
+
83
+ const style = useMemo(() => [
84
+ styles[`text_${position}`],
85
+ textStyle?.[position],
86
+ customTextStyle,
87
+ ], [position, textStyle, customTextStyle])
88
+
139
89
  return (
140
- <View
141
- style={[
142
- styles[position].container,
143
- containerStyle?.[position],
144
- ]}
145
- >
146
- <ParsedText
147
- style={[
148
- styles[position].text,
149
- textStyle?.[position],
150
- customTextStyle,
151
- ]}
152
- parse={[
153
- ...(parsePatterns ? parsePatterns(linkStyle as unknown as TextStyle) : []),
154
- { type: 'url', style: linkStyle, onPress: onUrlPress },
155
- { type: 'phone', style: linkStyle, onPress: onPhonePress },
156
- { type: 'email', style: linkStyle, onPress: onEmailPress },
157
- ]}
158
- childrenProps={{ ...textProps }}
159
- >
160
- {currentMessage!.text}
161
- </ParsedText>
90
+ <View style={[styles.container, containerStyle?.[position]]}>
91
+ <Autolink
92
+ style={style}
93
+ {...rest}
94
+ text={currentMessage!.text}
95
+ email
96
+ link
97
+ linkStyle={linkStyle}
98
+ onPress={handlePress}
99
+ />
162
100
  </View>
163
101
  )
164
102
  }
103
+
104
+ const styles = StyleSheet.create({
105
+ container: {
106
+ marginTop: 5,
107
+ marginBottom: 5,
108
+ marginLeft: 10,
109
+ marginRight: 10,
110
+ },
111
+ text: {
112
+ fontSize: 16,
113
+ lineHeight: 20,
114
+ },
115
+ text_left: {
116
+ color: 'black',
117
+ },
118
+ text_right: {
119
+ color: 'white',
120
+ },
121
+ link: {
122
+ textDecorationLine: 'underline',
123
+ },
124
+ })
@@ -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 MessageVideo () {
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
  {'Video 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 renderMessageVideo prop.'}
13
23
  </Text>
14
24
  </View>
15
- )
25
+ ), [])
26
+
27
+ return content
16
28
  }
@@ -122,6 +122,22 @@ export function QuickReplies ({
122
122
  [replies, currentMessage, handleSend]
123
123
  )
124
124
 
125
+ const renderSendButton = useMemo(() => {
126
+ if (!replies.length)
127
+ return null
128
+
129
+ return (
130
+ <TouchableOpacity
131
+ style={[stylesCommon.centerItems, styles.quickReply, styles.sendLink]}
132
+ onPress={handleSend(replies)}
133
+ >
134
+ {renderQuickReplySend?.() || (
135
+ <Text style={styles.sendLinkText}>{sendText}</Text>
136
+ )}
137
+ </TouchableOpacity>
138
+ )
139
+ }, [replies, handleSend, renderQuickReplySend, sendText])
140
+
125
141
  if (!shouldComponentDisplay)
126
142
  return null
127
143
 
@@ -159,16 +175,7 @@ export function QuickReplies ({
159
175
  )
160
176
  }
161
177
  )}
162
- {replies.length > 0 && (
163
- <TouchableOpacity
164
- style={[stylesCommon.centerItems, styles.quickReply, styles.sendLink]}
165
- onPress={handleSend(replies)}
166
- >
167
- {renderQuickReplySend?.() || (
168
- <Text style={styles.sendLinkText}>{sendText}</Text>
169
- )}
170
- </TouchableOpacity>
171
- )}
178
+ {renderSendButton}
172
179
  </View>
173
180
  )
174
181
  }
package/src/Send.tsx CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  ViewStyle,
9
9
  TextStyle,
10
10
  TouchableOpacityProps,
11
+ useColorScheme,
11
12
  } from 'react-native'
12
13
 
13
14
  import Color from './Color'
@@ -28,6 +29,9 @@ const styles = StyleSheet.create({
28
29
  marginLeft: 10,
29
30
  marginRight: 10,
30
31
  },
32
+ text_dark: {
33
+ color: '#4da6ff',
34
+ },
31
35
  })
32
36
 
33
37
  export interface SendProps<TMessage extends IMessage> {
@@ -56,6 +60,8 @@ export const Send = <TMessage extends IMessage = IMessage>({
56
60
  sendButtonProps,
57
61
  onSend,
58
62
  }: SendProps<TMessage>) => {
63
+ const colorScheme = useColorScheme()
64
+
59
65
  const handleOnPress = useCallback(() => {
60
66
  if (text && onSend)
61
67
  onSend({ text: text.trim() } as Partial<TMessage>, true)
@@ -81,7 +87,7 @@ export const Send = <TMessage extends IMessage = IMessage>({
81
87
  {...sendButtonProps}
82
88
  >
83
89
  <View>
84
- {children || <Text style={[styles.text, textStyle]}>{label}</Text>}
90
+ {children || <Text style={[styles.text, styles[`text_${colorScheme}`], textStyle]}>{label}</Text>}
85
91
  </View>
86
92
  </TouchableOpacity>
87
93
  )
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import {
3
3
  StyleSheet,
4
4
  Text,
@@ -29,6 +29,7 @@ export interface SystemMessageProps<TMessage extends IMessage> {
29
29
  containerStyle?: StyleProp<ViewStyle>
30
30
  wrapperStyle?: StyleProp<ViewStyle>
31
31
  textStyle?: StyleProp<TextStyle>
32
+ children?: React.ReactNode
32
33
  }
33
34
 
34
35
  export function SystemMessage<TMessage extends IMessage = IMessage> ({
@@ -36,14 +37,23 @@ export function SystemMessage<TMessage extends IMessage = IMessage> ({
36
37
  containerStyle,
37
38
  wrapperStyle,
38
39
  textStyle,
40
+ children,
39
41
  }: SystemMessageProps<TMessage>) {
42
+ const textContent = useMemo(() => {
43
+ if (!currentMessage?.text)
44
+ return null
45
+
46
+ return <Text style={[styles.text, textStyle]}>{currentMessage.text}</Text>
47
+ }, [currentMessage?.text, textStyle])
48
+
40
49
  if (currentMessage == null || currentMessage.system === false)
41
50
  return null
42
51
 
43
52
  return (
44
53
  <View style={[stylesCommon.fill, stylesCommon.centerItems, styles.container, containerStyle]}>
45
54
  <View style={wrapperStyle}>
46
- <Text style={[styles.text, textStyle]}>{currentMessage.text}</Text>
55
+ {textContent}
56
+ {children}
47
57
  </View>
48
58
  </View>
49
59
  )
package/src/Time.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import { StyleSheet, Text, View, ViewStyle, TextStyle } from 'react-native'
3
3
  import dayjs from 'dayjs'
4
4
 
@@ -60,6 +60,13 @@ export function Time<TMessage extends IMessage = IMessage> ({
60
60
  }: TimeProps<TMessage>) {
61
61
  const { getLocale } = useChatContext()
62
62
 
63
+ const formattedTime = useMemo(() => {
64
+ if (currentMessage == null)
65
+ return null
66
+
67
+ return dayjs(currentMessage.createdAt).locale(getLocale()).format(timeFormat)
68
+ }, [currentMessage, getLocale, timeFormat])
69
+
63
70
  if (currentMessage == null)
64
71
  return null
65
72
 
@@ -76,7 +83,7 @@ export function Time<TMessage extends IMessage = IMessage> ({
76
83
  timeTextStyle?.[position],
77
84
  ]}
78
85
  >
79
- {dayjs(currentMessage.createdAt).locale(getLocale()).format(timeFormat)}
86
+ {formattedTime}
80
87
  </Text>
81
88
  </View>
82
89
  )
@@ -89,7 +89,7 @@ const DotsAnimation = () => {
89
89
  )
90
90
  }
91
91
 
92
- const TypingIndicator = ({ isTyping }: TypingIndicatorProps) => {
92
+ const TypingIndicator = ({ isTyping, style }: TypingIndicatorProps) => {
93
93
  const yCoords = useSharedValue(200)
94
94
  const heightScale = useSharedValue(0)
95
95
  const marginScale = useSharedValue(0)
@@ -146,6 +146,7 @@ const TypingIndicator = ({ isTyping }: TypingIndicatorProps) => {
146
146
  style={[
147
147
  styles.container,
148
148
  containerStyle,
149
+ style,
149
150
  ]}
150
151
  >
151
152
  <DotsAnimation />
@@ -1,3 +1,6 @@
1
+ import { StyleProp, ViewStyle } from 'react-native'
2
+
1
3
  export interface TypingIndicatorProps {
2
4
  isTyping?: boolean
5
+ style?: StyleProp<ViewStyle>
3
6
  }
@@ -1,10 +1,9 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { Actions } from '../GiftedChat'
6
5
 
7
6
  it('should render <Actions /> and compare with snapshot', () => {
8
- const tree = renderer.create(<Actions />).toJSON()
9
- expect(tree).toMatchSnapshot()
7
+ const { toJSON } = render(<Actions />)
8
+ expect(toJSON()).toMatchSnapshot()
10
9
  })
@@ -1,13 +1,12 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { Avatar } from '../GiftedChat'
6
5
 
7
6
  it('should render <Avatar /> and compare with snapshot', () => {
8
- const tree = renderer
9
- .create(<Avatar renderAvatar={() => 'renderAvatar'} position='left' />)
10
- .toJSON()
7
+ const { toJSON } = render(
8
+ <Avatar renderAvatar={() => 'renderAvatar'} position='left' />
9
+ )
11
10
 
12
- expect(tree).toMatchSnapshot()
11
+ expect(toJSON()).toMatchSnapshot()
13
12
  })
@@ -1,26 +1,21 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { Bubble } from '../GiftedChat'
6
5
 
7
6
  it('should render <Bubble /> and compare with snapshot', () => {
8
- let tree
7
+ const { toJSON } = render(
8
+ <Bubble
9
+ user={{ _id: 1 }}
10
+ currentMessage={{
11
+ _id: 1,
12
+ text: 'test',
13
+ createdAt: 1554744013721,
14
+ user: { _id: 1 },
15
+ }}
16
+ position='left'
17
+ />
18
+ )
9
19
 
10
- renderer.act(() => {
11
- tree = renderer.create(
12
- <Bubble
13
- user={{ _id: 1 }}
14
- currentMessage={{
15
- _id: 1,
16
- text: 'test',
17
- createdAt: 1554744013721,
18
- user: { _id: 1 },
19
- }}
20
- position='left'
21
- />
22
- )
23
- })
24
-
25
- expect(tree.toJSON()).toMatchSnapshot()
20
+ expect(toJSON()).toMatchSnapshot()
26
21
  })
@@ -1,11 +1,10 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { Composer } from '../GiftedChat'
6
5
 
7
6
  it('should render <Composer /> and compare with snapshot', () => {
8
- const tree = renderer.create(<Composer />).toJSON()
7
+ const { toJSON } = render(<Composer />)
9
8
 
10
- expect(tree).toMatchSnapshot()
9
+ expect(toJSON()).toMatchSnapshot()
11
10
  })
@@ -1,23 +1,20 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { Day } from '../GiftedChat'
6
5
  import { DEFAULT_TEST_MESSAGE } from './data'
7
6
 
8
7
  describe('Day', () => {
9
8
  it('should not render <Day /> and compare with snapshot', () => {
10
- const component = renderer.create(<Day />)
11
- const tree = component.toJSON()
9
+ const { toJSON } = render(<Day />)
12
10
 
13
- expect(tree).toMatchSnapshot()
11
+ expect(toJSON()).toMatchSnapshot()
14
12
  })
15
13
 
16
14
  it('should render <Day /> and compare with snapshot', () => {
17
- const component = renderer.create(
15
+ const { toJSON } = render(
18
16
  <Day currentMessage={DEFAULT_TEST_MESSAGE} />
19
17
  )
20
- const tree = component.toJSON()
21
- expect(tree).toMatchSnapshot()
18
+ expect(toJSON()).toMatchSnapshot()
22
19
  })
23
20
  })
@@ -0,0 +1,52 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react-native'
3
+ import { View, Text } from 'react-native'
4
+ import DayAnimated from '../MessageContainer/components/DayAnimated'
5
+ import { DayProps } from '../Day'
6
+
7
+ const mockDaysPositions = { value: {} }
8
+ const mockScrolledY = { value: 0 }
9
+ const mockListHeight = { value: 800 }
10
+
11
+ const mockMessage = {
12
+ _id: 1,
13
+ text: 'Hello',
14
+ createdAt: new Date('2023-01-01'),
15
+ user: { _id: 1, name: 'User 1' },
16
+ }
17
+
18
+ describe('DayAnimated', () => {
19
+ it('should render DayAnimated with default Day component', () => {
20
+ const { toJSON } = render(
21
+ <DayAnimated
22
+ scrolledY={mockScrolledY}
23
+ daysPositions={mockDaysPositions}
24
+ listHeight={mockListHeight}
25
+ messages={[mockMessage]}
26
+ isLoadingEarlier={false}
27
+ />
28
+ )
29
+ expect(toJSON()).toMatchSnapshot()
30
+ })
31
+
32
+ it('should use custom renderDay when provided', () => {
33
+ const customRenderDay = jest.fn((props: DayProps) => (
34
+ <View testID='custom-day'>
35
+ <Text>Custom Day: {props.createdAt}</Text>
36
+ </View>
37
+ ))
38
+
39
+ const { toJSON } = render(
40
+ <DayAnimated
41
+ scrolledY={mockScrolledY}
42
+ daysPositions={mockDaysPositions}
43
+ listHeight={mockListHeight}
44
+ messages={[mockMessage]}
45
+ isLoadingEarlier={false}
46
+ renderDay={customRenderDay}
47
+ />
48
+ )
49
+
50
+ expect(toJSON()).toMatchSnapshot()
51
+ })
52
+ })
@@ -1,15 +1,10 @@
1
- import 'react-native'
2
1
  import React from 'react'
3
- import renderer from 'react-test-renderer'
2
+ import { render } from '@testing-library/react-native'
4
3
 
5
4
  import { GiftedAvatar } from '../GiftedChat'
6
5
 
7
6
  it('should render <GiftedAvatar /> and compare with snapshot', () => {
8
- let tree
7
+ const { toJSON } = render(<GiftedAvatar />)
9
8
 
10
- renderer.act(() => {
11
- tree = renderer.create(<GiftedAvatar />)
12
- })
13
-
14
- expect(tree.toJSON()).toMatchSnapshot()
9
+ expect(toJSON()).toMatchSnapshot()
15
10
  })