react-native-gifted-chat 2.4.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +34 -14
  2. package/lib/Actions.d.ts +5 -6
  3. package/lib/Actions.js +16 -13
  4. package/lib/Actions.js.map +1 -1
  5. package/lib/Avatar.d.ts +9 -25
  6. package/lib/Avatar.js +12 -18
  7. package/lib/Avatar.js.flow +1 -1
  8. package/lib/Avatar.js.map +1 -1
  9. package/lib/Bubble.d.ts +29 -30
  10. package/lib/Bubble.js +99 -92
  11. package/lib/Bubble.js.flow +2 -2
  12. package/lib/Bubble.js.map +1 -1
  13. package/lib/Composer.d.ts +1 -1
  14. package/lib/Composer.js +30 -32
  15. package/lib/Composer.js.map +1 -1
  16. package/lib/Constant.js +1 -0
  17. package/lib/Constant.js.map +1 -1
  18. package/lib/Day.d.ts +3 -15
  19. package/lib/Day.js +2 -14
  20. package/lib/Day.js.flow +1 -1
  21. package/lib/Day.js.map +1 -1
  22. package/lib/GiftedAvatar.d.ts +7 -7
  23. package/lib/GiftedAvatar.js +30 -29
  24. package/lib/GiftedAvatar.js.map +1 -1
  25. package/lib/GiftedChat.d.ts +15 -89
  26. package/lib/GiftedChat.js +204 -350
  27. package/lib/GiftedChat.js.flow +1 -3
  28. package/lib/GiftedChat.js.map +1 -1
  29. package/lib/GiftedChatContext.d.ts +2 -1
  30. package/lib/GiftedChatContext.js.map +1 -1
  31. package/lib/InputToolbar.d.ts +7 -5
  32. package/lib/InputToolbar.js +41 -34
  33. package/lib/InputToolbar.js.map +1 -1
  34. package/lib/LoadEarlier.d.ts +4 -4
  35. package/lib/LoadEarlier.js +8 -6
  36. package/lib/LoadEarlier.js.map +1 -1
  37. package/lib/Message.d.ts +8 -9
  38. package/lib/Message.js +47 -40
  39. package/lib/Message.js.flow +1 -1
  40. package/lib/Message.js.map +1 -1
  41. package/lib/MessageAudio.d.ts +2 -1
  42. package/lib/MessageAudio.js +4 -4
  43. package/lib/MessageAudio.js.flow +1 -1
  44. package/lib/MessageAudio.js.map +1 -1
  45. package/lib/MessageContainer.d.ts +17 -17
  46. package/lib/MessageContainer.js +33 -51
  47. package/lib/MessageContainer.js.map +1 -1
  48. package/lib/MessageImage.d.ts +5 -4
  49. package/lib/MessageImage.js +4 -5
  50. package/lib/MessageImage.js.flow +1 -1
  51. package/lib/MessageImage.js.map +1 -1
  52. package/lib/MessageText.d.ts +11 -10
  53. package/lib/MessageText.js +5 -10
  54. package/lib/MessageText.js.flow +1 -1
  55. package/lib/MessageText.js.map +1 -1
  56. package/lib/MessageVideo.d.ts +2 -1
  57. package/lib/MessageVideo.js +4 -4
  58. package/lib/MessageVideo.js.flow +1 -1
  59. package/lib/MessageVideo.js.map +1 -1
  60. package/lib/Models.d.ts +7 -7
  61. package/lib/QuickReplies.d.ts +3 -3
  62. package/lib/QuickReplies.js +8 -14
  63. package/lib/QuickReplies.js.flow +1 -1
  64. package/lib/QuickReplies.js.map +1 -1
  65. package/lib/Send.d.ts +4 -4
  66. package/lib/Send.js +6 -9
  67. package/lib/Send.js.map +1 -1
  68. package/lib/SystemMessage.d.ts +6 -5
  69. package/lib/SystemMessage.js +1 -2
  70. package/lib/SystemMessage.js.flow +1 -1
  71. package/lib/SystemMessage.js.map +1 -1
  72. package/lib/Time.d.ts +7 -6
  73. package/lib/Time.js +1 -3
  74. package/lib/Time.js.flow +1 -1
  75. package/lib/Time.js.map +1 -1
  76. package/lib/TypingIndicator.d.ts +2 -1
  77. package/lib/TypingIndicator.js +5 -5
  78. package/lib/TypingIndicator.js.map +1 -1
  79. package/lib/hooks/useUpdateLayoutEffect.js +2 -4
  80. package/lib/hooks/useUpdateLayoutEffect.js.map +1 -1
  81. package/lib/index.d.ts +1 -0
  82. package/lib/index.js +1 -0
  83. package/lib/index.js.map +1 -1
  84. package/lib/logging.d.ts +2 -2
  85. package/lib/logging.js.map +1 -1
  86. package/lib/types.js.flow +1 -1
  87. package/lib/utils.d.ts +1 -1
  88. package/lib/utils.js +2 -4
  89. package/lib/utils.js.map +1 -1
  90. package/package.json +86 -59
  91. package/src/Actions.tsx +114 -0
  92. package/src/Avatar.tsx +178 -0
  93. package/src/Bubble.tsx +596 -0
  94. package/src/Color.ts +17 -0
  95. package/src/Composer.tsx +147 -0
  96. package/src/Constant.ts +18 -0
  97. package/src/Day.tsx +71 -0
  98. package/src/GiftedAvatar.tsx +205 -0
  99. package/src/GiftedChat.tsx +670 -0
  100. package/src/GiftedChatContext.ts +23 -0
  101. package/src/InputToolbar.tsx +113 -0
  102. package/src/LoadEarlier.tsx +108 -0
  103. package/src/Message.tsx +229 -0
  104. package/src/MessageAudio.tsx +19 -0
  105. package/src/MessageContainer.tsx +362 -0
  106. package/src/MessageImage.tsx +78 -0
  107. package/src/MessageText.tsx +187 -0
  108. package/src/MessageVideo.tsx +19 -0
  109. package/src/Models.ts +84 -0
  110. package/src/QuickReplies.tsx +186 -0
  111. package/src/Send.tsx +102 -0
  112. package/src/SystemMessage.tsx +61 -0
  113. package/src/Time.tsx +97 -0
  114. package/src/TypingIndicator.tsx +108 -0
  115. package/src/__tests__/Actions.test.tsx +10 -0
  116. package/src/__tests__/Avatar.test.tsx +13 -0
  117. package/src/__tests__/Bubble.test.tsx +23 -0
  118. package/src/__tests__/Color.test.tsx +5 -0
  119. package/src/__tests__/Composer.test.tsx +11 -0
  120. package/src/__tests__/Constant.test.tsx +5 -0
  121. package/src/__tests__/Day.test.tsx +23 -0
  122. package/src/__tests__/GiftedAvatar.test.tsx +11 -0
  123. package/src/__tests__/GiftedChat.test.tsx +36 -0
  124. package/src/__tests__/InputToolbar.test.tsx +11 -0
  125. package/src/__tests__/LoadEarlier.test.tsx +11 -0
  126. package/src/__tests__/Message.test.tsx +77 -0
  127. package/src/__tests__/MessageContainer.test.tsx +11 -0
  128. package/src/__tests__/MessageImage.test.tsx +27 -0
  129. package/src/__tests__/MessageText.test.tsx +11 -0
  130. package/src/__tests__/Send.test.tsx +22 -0
  131. package/src/__tests__/SystemMessage.test.tsx +27 -0
  132. package/src/__tests__/Time.test.tsx +29 -0
  133. package/src/__tests__/__snapshots__/Actions.test.tsx.snap +76 -0
  134. package/src/__tests__/__snapshots__/Avatar.test.tsx.snap +17 -0
  135. package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +145 -0
  136. package/src/__tests__/__snapshots__/Color.test.tsx.snap +21 -0
  137. package/src/__tests__/__snapshots__/Composer.test.tsx.snap +35 -0
  138. package/src/__tests__/__snapshots__/Constant.test.tsx.snap +16 -0
  139. package/src/__tests__/__snapshots__/Day.test.tsx.snap +37 -0
  140. package/src/__tests__/__snapshots__/GiftedAvatar.test.tsx.snap +22 -0
  141. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +15 -0
  142. package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +60 -0
  143. package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +74 -0
  144. package/src/__tests__/__snapshots__/Message.test.tsx.snap +628 -0
  145. package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +127 -0
  146. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +38 -0
  147. package/src/__tests__/__snapshots__/MessageText.test.tsx.snap +30 -0
  148. package/src/__tests__/__snapshots__/Send.test.tsx.snap +129 -0
  149. package/src/__tests__/__snapshots__/SystemMessage.test.tsx.snap +38 -0
  150. package/src/__tests__/__snapshots__/Time.test.tsx.snap +33 -0
  151. package/src/__tests__/data.ts +8 -0
  152. package/src/__tests__/utils.test.ts +31 -0
  153. package/src/hooks/useUpdateLayoutEffect.ts +21 -0
  154. package/src/index.ts +4 -0
  155. package/src/logging.ts +8 -0
  156. package/src/utils.ts +39 -0
  157. package/.eslintignore +0 -2
  158. package/.eslintrc.js +0 -21
  159. package/jest.config.js +0 -15
@@ -0,0 +1,147 @@
1
+ import PropTypes from 'prop-types'
2
+ import React, { useCallback, useRef } from 'react'
3
+ import {
4
+ Platform,
5
+ StyleSheet,
6
+ TextInput,
7
+ TextInputProps,
8
+ NativeSyntheticEvent,
9
+ TextInputContentSizeChangeEventData,
10
+ } from 'react-native'
11
+ import { MIN_COMPOSER_HEIGHT, DEFAULT_PLACEHOLDER } from './Constant'
12
+ import Color from './Color'
13
+ import { StylePropType } from './utils'
14
+ import { useCallbackOne } from 'use-memo-one'
15
+
16
+ export interface ComposerProps {
17
+ composerHeight?: number
18
+ text?: string
19
+ placeholder?: string
20
+ placeholderTextColor?: string
21
+ textInputProps?: Partial<TextInputProps>
22
+ textInputStyle?: TextInputProps['style']
23
+ textInputAutoFocus?: boolean
24
+ keyboardAppearance?: TextInputProps['keyboardAppearance']
25
+ multiline?: boolean
26
+ disableComposer?: boolean
27
+ onTextChanged?(text: string): void
28
+ onInputSizeChanged?(layout: { width: number, height: number }): void
29
+ }
30
+
31
+ export function Composer ({
32
+ composerHeight = MIN_COMPOSER_HEIGHT,
33
+ disableComposer = false,
34
+ keyboardAppearance = 'default',
35
+ multiline = true,
36
+ onInputSizeChanged,
37
+ onTextChanged,
38
+ placeholder = DEFAULT_PLACEHOLDER,
39
+ placeholderTextColor = Color.defaultColor,
40
+ text = '',
41
+ textInputAutoFocus = false,
42
+ textInputProps,
43
+ textInputStyle,
44
+ }: ComposerProps): React.ReactElement {
45
+ const dimensionsRef = useRef<{ width: number, height: number }>()
46
+
47
+ const determineInputSizeChange = useCallbackOne(
48
+ (dimensions: { width: number, height: number }) => {
49
+ // Support earlier versions of React Native on Android.
50
+ if (!dimensions)
51
+ return
52
+
53
+ if (
54
+ !dimensionsRef.current ||
55
+ (dimensionsRef.current &&
56
+ (dimensionsRef.current.width !== dimensions.width ||
57
+ dimensionsRef.current.height !== dimensions.height))
58
+ ) {
59
+ dimensionsRef.current = dimensions
60
+ onInputSizeChanged?.(dimensions)
61
+ }
62
+ },
63
+ [onInputSizeChanged]
64
+ )
65
+
66
+ const handleContentSizeChange = useCallback(
67
+ ({
68
+ nativeEvent: { contentSize },
69
+ }: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) =>
70
+ determineInputSizeChange(contentSize),
71
+ [determineInputSizeChange]
72
+ )
73
+
74
+ return (
75
+ <TextInput
76
+ testID={placeholder}
77
+ accessible
78
+ accessibilityLabel={placeholder}
79
+ placeholder={placeholder}
80
+ placeholderTextColor={placeholderTextColor}
81
+ multiline={multiline}
82
+ editable={!disableComposer}
83
+ onContentSizeChange={handleContentSizeChange}
84
+ onChangeText={onTextChanged}
85
+ style={[
86
+ styles.textInput,
87
+ textInputStyle,
88
+ {
89
+ height: composerHeight,
90
+ ...Platform.select({
91
+ web: {
92
+ outlineWidth: 0,
93
+ outlineColor: 'transparent',
94
+ outlineOffset: 0,
95
+ },
96
+ }),
97
+ },
98
+ ]}
99
+ autoFocus={textInputAutoFocus}
100
+ value={text}
101
+ enablesReturnKeyAutomatically
102
+ underlineColorAndroid='transparent'
103
+ keyboardAppearance={keyboardAppearance}
104
+ {...textInputProps}
105
+ />
106
+ )
107
+ }
108
+
109
+ Composer.propTypes = {
110
+ composerHeight: PropTypes.number,
111
+ text: PropTypes.string,
112
+ placeholder: PropTypes.string,
113
+ placeholderTextColor: PropTypes.string,
114
+ textInputProps: PropTypes.object,
115
+ onTextChanged: PropTypes.func,
116
+ onInputSizeChanged: PropTypes.func,
117
+ multiline: PropTypes.bool,
118
+ disableComposer: PropTypes.bool,
119
+ textInputStyle: StylePropType,
120
+ textInputAutoFocus: PropTypes.bool,
121
+ keyboardAppearance: PropTypes.string,
122
+ }
123
+
124
+ const styles = StyleSheet.create({
125
+ textInput: {
126
+ flex: 1,
127
+ marginLeft: 10,
128
+ fontSize: 16,
129
+ lineHeight: 22,
130
+ ...Platform.select({
131
+ web: {
132
+ paddingTop: 6,
133
+ paddingLeft: 4,
134
+ },
135
+ }),
136
+ marginTop: Platform.select({
137
+ ios: 6,
138
+ android: 0,
139
+ web: 6,
140
+ }),
141
+ marginBottom: Platform.select({
142
+ ios: 5,
143
+ android: 3,
144
+ web: 4,
145
+ }),
146
+ },
147
+ })
@@ -0,0 +1,18 @@
1
+ import { Platform } from 'react-native'
2
+
3
+ export const MIN_COMPOSER_HEIGHT = Platform.select({
4
+ ios: 33,
5
+ android: 41,
6
+ web: 34,
7
+ windows: 34,
8
+ })
9
+ export const MAX_COMPOSER_HEIGHT = 200
10
+ export const DEFAULT_PLACEHOLDER = 'Type a message...'
11
+ export const DATE_FORMAT = 'll'
12
+ export const TIME_FORMAT = 'LT'
13
+
14
+ export const TEST_ID = {
15
+ WRAPPER: 'GC_WRAPPER',
16
+ LOADING_WRAPPER: 'GC_LOADING_CONTAINER',
17
+ SEND_TOUCHABLE: 'GC_SEND_TOUCHABLE',
18
+ }
package/src/Day.tsx ADDED
@@ -0,0 +1,71 @@
1
+ import * as React from 'react'
2
+ import {
3
+ StyleSheet,
4
+ Text,
5
+ View,
6
+ StyleProp,
7
+ ViewStyle,
8
+ TextStyle,
9
+ TextProps,
10
+ } from 'react-native'
11
+ import dayjs from 'dayjs'
12
+
13
+ import Color from './Color'
14
+ import { isSameDay } from './utils'
15
+ import { DATE_FORMAT } from './Constant'
16
+ import { IMessage } from './Models'
17
+
18
+ import { useChatContext } from './GiftedChatContext'
19
+
20
+ const styles = StyleSheet.create({
21
+ container: {
22
+ alignItems: 'center',
23
+ justifyContent: 'center',
24
+ marginTop: 5,
25
+ marginBottom: 10,
26
+ },
27
+ text: {
28
+ backgroundColor: Color.backgroundTransparent,
29
+ color: Color.defaultColor,
30
+ fontSize: 12,
31
+ fontWeight: '600',
32
+ },
33
+ })
34
+
35
+ export interface DayProps<TMessage extends IMessage = IMessage> {
36
+ currentMessage: TMessage
37
+ nextMessage?: TMessage
38
+ previousMessage?: TMessage
39
+ containerStyle?: StyleProp<ViewStyle>
40
+ wrapperStyle?: StyleProp<ViewStyle>
41
+ textStyle?: StyleProp<TextStyle>
42
+ textProps?: TextProps
43
+ dateFormat?: string
44
+ inverted?: boolean
45
+ }
46
+
47
+ export function Day<TMessage extends IMessage = IMessage> ({
48
+ dateFormat = DATE_FORMAT,
49
+ currentMessage,
50
+ previousMessage,
51
+ containerStyle,
52
+ wrapperStyle,
53
+ textStyle,
54
+ }: DayProps<TMessage>) {
55
+ const { getLocale } = useChatContext()
56
+
57
+ if (currentMessage == null || isSameDay(currentMessage, previousMessage))
58
+ return null
59
+
60
+ return (
61
+ <View style={[styles.container, containerStyle]}>
62
+ <View style={wrapperStyle}>
63
+ <Text style={[styles.text, textStyle]}>
64
+ {dayjs(currentMessage.createdAt)
65
+ .locale(getLocale())
66
+ .format(dateFormat)}
67
+ </Text>
68
+ </View>
69
+ </View>
70
+ )
71
+ }
@@ -0,0 +1,205 @@
1
+ import PropTypes from 'prop-types'
2
+ import React from 'react'
3
+ import {
4
+ Image,
5
+ Text,
6
+ TouchableOpacity,
7
+ View,
8
+ StyleSheet,
9
+ StyleProp,
10
+ ImageStyle,
11
+ TextStyle,
12
+ } from 'react-native'
13
+ import Color from './Color'
14
+ import { User } from './Models'
15
+ import { StylePropType } from './utils'
16
+
17
+ const {
18
+ carrot,
19
+ emerald,
20
+ peterRiver,
21
+ wisteria,
22
+ alizarin,
23
+ turquoise,
24
+ midnightBlue,
25
+ } = Color
26
+
27
+ const styles = StyleSheet.create({
28
+ avatarStyle: {
29
+ justifyContent: 'center',
30
+ alignItems: 'center',
31
+ width: 40,
32
+ height: 40,
33
+ borderRadius: 20,
34
+ },
35
+ avatarTransparent: {
36
+ backgroundColor: Color.backgroundTransparent,
37
+ },
38
+ textStyle: {
39
+ color: Color.white,
40
+ fontSize: 16,
41
+ backgroundColor: Color.backgroundTransparent,
42
+ fontWeight: '100',
43
+ },
44
+ })
45
+
46
+ export interface GiftedAvatarProps {
47
+ user?: User
48
+ avatarStyle?: StyleProp<ImageStyle>
49
+ textStyle?: StyleProp<TextStyle>
50
+ onPress?: (props: GiftedAvatarProps) => void
51
+ onLongPress?: (props: GiftedAvatarProps) => void
52
+ }
53
+
54
+ export default class GiftedAvatar extends React.Component<GiftedAvatarProps> {
55
+ static defaultProps = {
56
+ user: {
57
+ name: null,
58
+ avatar: null,
59
+ },
60
+ onPress: undefined,
61
+ onLongPress: undefined,
62
+ avatarStyle: {},
63
+ textStyle: {},
64
+ }
65
+
66
+ static propTypes = {
67
+ user: PropTypes.object,
68
+ onPress: PropTypes.func,
69
+ onLongPress: PropTypes.func,
70
+ avatarStyle: StylePropType,
71
+ textStyle: StylePropType,
72
+ }
73
+
74
+ avatarName?: string = undefined
75
+ avatarColor?: string = undefined
76
+
77
+ setAvatarColor () {
78
+ const userName = (this.props.user && this.props.user.name) || ''
79
+ const name = userName.toUpperCase().split(' ')
80
+ if (name.length === 1)
81
+ this.avatarName = `${name[0].charAt(0)}`
82
+ else if (name.length > 1)
83
+ this.avatarName = `${name[0].charAt(0)}${name[1].charAt(0)}`
84
+ else
85
+ this.avatarName = ''
86
+
87
+ let sumChars = 0
88
+ for (let i = 0; i < userName.length; i += 1)
89
+ sumChars += userName.charCodeAt(i)
90
+
91
+ // inspired by https://github.com/wbinnssmith/react-user-avatar
92
+ // colors from https://flatuicolors.com/
93
+ const colors = [
94
+ carrot,
95
+ emerald,
96
+ peterRiver,
97
+ wisteria,
98
+ alizarin,
99
+ turquoise,
100
+ midnightBlue,
101
+ ]
102
+
103
+ this.avatarColor = colors[sumChars % colors.length]
104
+ }
105
+
106
+ renderAvatar () {
107
+ const { user } = this.props
108
+ if (user)
109
+ if (typeof user.avatar === 'function')
110
+ return user.avatar([styles.avatarStyle, this.props.avatarStyle])
111
+ else if (typeof user.avatar === 'string')
112
+ return (
113
+ <Image
114
+ source={{ uri: user.avatar }}
115
+ style={[styles.avatarStyle, this.props.avatarStyle]}
116
+ />
117
+ )
118
+ else if (typeof user.avatar === 'number')
119
+ return (
120
+ <Image
121
+ source={user.avatar}
122
+ style={[styles.avatarStyle, this.props.avatarStyle]}
123
+ />
124
+ )
125
+
126
+ return null
127
+ }
128
+
129
+ renderInitials () {
130
+ return (
131
+ <Text style={[styles.textStyle, this.props.textStyle]}>
132
+ {this.avatarName}
133
+ </Text>
134
+ )
135
+ }
136
+
137
+ handleOnPress = () => {
138
+ const {
139
+ /* eslint-disable @typescript-eslint/no-unused-vars */
140
+ onPress,
141
+ /* eslint-enable @typescript-eslint/no-unused-vars */
142
+ ...rest
143
+ } = this.props
144
+
145
+ if (this.props.onPress)
146
+ this.props.onPress(rest)
147
+ }
148
+
149
+ handleOnLongPress = () => {
150
+ const {
151
+ /* eslint-disable @typescript-eslint/no-unused-vars */
152
+ onLongPress,
153
+ /* eslint-enable @typescript-eslint/no-unused-vars */
154
+ ...rest
155
+ } = this.props
156
+
157
+ if (this.props.onLongPress)
158
+ this.props.onLongPress(rest)
159
+ }
160
+
161
+ render () {
162
+ if (!this.props.user || (!this.props.user.name && !this.props.user.avatar))
163
+ // render placeholder
164
+ return (
165
+ <View
166
+ style={[
167
+ styles.avatarStyle,
168
+ styles.avatarTransparent,
169
+ this.props.avatarStyle,
170
+ ]}
171
+ accessibilityRole='image'
172
+ />
173
+ )
174
+
175
+ if (this.props.user.avatar)
176
+ return (
177
+ <TouchableOpacity
178
+ disabled={!this.props.onPress}
179
+ onPress={this.handleOnPress}
180
+ onLongPress={this.handleOnLongPress}
181
+ accessibilityRole='image'
182
+ >
183
+ {this.renderAvatar()}
184
+ </TouchableOpacity>
185
+ )
186
+
187
+ this.setAvatarColor()
188
+
189
+ return (
190
+ <TouchableOpacity
191
+ disabled={!this.props.onPress}
192
+ onPress={this.handleOnPress}
193
+ onLongPress={this.handleOnLongPress}
194
+ style={[
195
+ styles.avatarStyle,
196
+ { backgroundColor: this.avatarColor },
197
+ this.props.avatarStyle,
198
+ ]}
199
+ accessibilityRole='image'
200
+ >
201
+ {this.renderInitials()}
202
+ </TouchableOpacity>
203
+ )
204
+ }
205
+ }