react-native-gifted-chat 2.8.2-alpha.0 → 2.8.2-alpha.2
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.
- package/README.md +51 -31
- package/package.json +28 -30
- package/src/Actions.tsx +1 -1
- package/src/Avatar.tsx +1 -1
- package/src/Bubble/index.tsx +24 -20
- package/src/Bubble/types.ts +7 -6
- package/src/Composer.tsx +19 -26
- package/src/Constant.ts +0 -1
- package/src/Day/index.tsx +3 -3
- package/src/GiftedAvatar.tsx +31 -38
- package/src/GiftedChat/index.tsx +59 -106
- package/src/GiftedChat/styles.ts +3 -0
- package/src/GiftedChat/types.ts +17 -67
- package/src/InputToolbar.tsx +27 -10
- package/src/LoadEarlier.tsx +22 -20
- package/src/Message/index.tsx +4 -18
- package/src/Message/types.ts +2 -2
- package/src/MessageAudio.tsx +19 -7
- package/src/MessageContainer/components/DayAnimated/index.tsx +16 -11
- package/src/MessageContainer/components/Item/index.tsx +10 -4
- package/src/MessageContainer/components/Item/types.ts +1 -1
- package/src/MessageContainer/index.tsx +57 -38
- package/src/MessageContainer/types.ts +32 -7
- package/src/MessageImage.tsx +132 -18
- package/src/MessageText.tsx +24 -64
- package/src/MessageVideo.tsx +19 -7
- package/src/QuickReplies.tsx +19 -12
- package/src/Send.tsx +10 -5
- package/src/SystemMessage.tsx +10 -3
- package/src/Time.tsx +10 -3
- package/src/TypingIndicator/index.tsx +4 -3
- package/src/TypingIndicator/types.ts +3 -0
- package/src/__tests__/Actions.test.tsx +3 -4
- package/src/__tests__/Avatar.test.tsx +5 -6
- package/src/__tests__/Bubble.test.tsx +14 -19
- package/src/__tests__/Composer.test.tsx +3 -4
- package/src/__tests__/Day.test.tsx +5 -8
- package/src/__tests__/DayAnimated.test.tsx +12 -14
- package/src/__tests__/GiftedAvatar.test.tsx +3 -8
- package/src/__tests__/GiftedChat.test.tsx +34 -43
- package/src/__tests__/InputToolbar.test.tsx +3 -4
- package/src/__tests__/LoadEarlier.test.tsx +3 -4
- package/src/__tests__/Message.test.tsx +51 -58
- package/src/__tests__/MessageContainer.test.tsx +39 -5
- package/src/__tests__/MessageImage.test.tsx +12 -15
- package/src/__tests__/MessageText.test.tsx +7 -4
- package/src/__tests__/Send.test.tsx +7 -8
- package/src/__tests__/SystemMessage.test.tsx +12 -15
- package/src/__tests__/Time.test.tsx +5 -8
- package/src/__tests__/__snapshots__/Actions.test.tsx.snap +39 -7
- package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +48 -50
- package/src/__tests__/__snapshots__/Composer.test.tsx.snap +1 -2
- package/src/__tests__/__snapshots__/Constant.test.tsx.snap +0 -1
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +20 -22
- package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +2 -2
- package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +37 -6
- package/src/__tests__/__snapshots__/Message.test.tsx.snap +146 -150
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +32 -11
- package/src/__tests__/__snapshots__/MessageText.test.tsx.snap +12 -8
- package/src/__tests__/__snapshots__/Send.test.tsx.snap +72 -10
- package/src/components/TouchableOpacity.tsx +45 -0
- package/src/reanimatedCompat.ts +27 -0
- package/src/types.ts +4 -2
- package/src/utils.ts +2 -2
- package/lib/Actions.d.ts +0 -14
- package/lib/Actions.js +0 -57
- package/lib/Actions.js.map +0 -1
- package/lib/Avatar.d.ts +0 -18
- package/lib/Avatar.js +0 -93
- package/lib/Avatar.js.map +0 -1
- package/lib/Bubble/index.d.ts +0 -6
- package/lib/Bubble/index.js +0 -242
- package/lib/Bubble/index.js.map +0 -1
- package/lib/Bubble/styles.d.ts +0 -69
- package/lib/Bubble/styles.js +0 -72
- package/lib/Bubble/styles.js.map +0 -1
- package/lib/Bubble/types.d.ts +0 -47
- package/lib/Bubble/types.js +0 -2
- package/lib/Bubble/types.js.map +0 -1
- package/lib/Color.d.ts +0 -18
- package/lib/Color.js +0 -18
- package/lib/Color.js.map +0 -1
- package/lib/Composer.d.ts +0 -20
- package/lib/Composer.js +0 -60
- package/lib/Composer.js.map +0 -1
- package/lib/Constant.d.ts +0 -10
- package/lib/Constant.js +0 -17
- package/lib/Constant.js.map +0 -1
- package/lib/Day/index.d.ts +0 -4
- package/lib/Day/index.js +0 -39
- package/lib/Day/index.js.map +0 -1
- package/lib/Day/styles.d.ts +0 -20
- package/lib/Day/styles.js +0 -22
- package/lib/Day/styles.js.map +0 -1
- package/lib/Day/types.d.ts +0 -9
- package/lib/Day/types.js +0 -2
- package/lib/Day/types.js.map +0 -1
- package/lib/GiftedAvatar.d.ts +0 -11
- package/lib/GiftedAvatar.js +0 -104
- package/lib/GiftedAvatar.js.map +0 -1
- package/lib/GiftedChat/index.d.ts +0 -26
- package/lib/GiftedChat/index.js +0 -317
- package/lib/GiftedChat/index.js.map +0 -1
- package/lib/GiftedChat/styles.d.ts +0 -6
- package/lib/GiftedChat/styles.js +0 -7
- package/lib/GiftedChat/styles.js.map +0 -1
- package/lib/GiftedChat/types.d.ts +0 -112
- package/lib/GiftedChat/types.js +0 -2
- package/lib/GiftedChat/types.js.map +0 -1
- package/lib/GiftedChatContext.d.ts +0 -9
- package/lib/GiftedChatContext.js +0 -9
- package/lib/GiftedChatContext.js.map +0 -1
- package/lib/InputToolbar.d.ts +0 -23
- package/lib/InputToolbar.js +0 -56
- package/lib/InputToolbar.js.map +0 -1
- package/lib/LoadEarlier.d.ts +0 -14
- package/lib/LoadEarlier.js +0 -45
- package/lib/LoadEarlier.js.map +0 -1
- package/lib/Message/index.d.ts +0 -6
- package/lib/Message/index.js +0 -80
- package/lib/Message/index.js.map +0 -1
- package/lib/Message/styles.d.ts +0 -21
- package/lib/Message/styles.js +0 -22
- package/lib/Message/styles.js.map +0 -1
- package/lib/Message/types.d.ts +0 -22
- package/lib/Message/types.js +0 -2
- package/lib/Message/types.js.map +0 -1
- package/lib/MessageAudio.d.ts +0 -2
- package/lib/MessageAudio.js +0 -14
- package/lib/MessageAudio.js.map +0 -1
- package/lib/MessageContainer/components/DayAnimated/index.d.ts +0 -5
- package/lib/MessageContainer/components/DayAnimated/index.js +0 -85
- package/lib/MessageContainer/components/DayAnimated/index.js.map +0 -1
- package/lib/MessageContainer/components/DayAnimated/styles.d.ts +0 -11
- package/lib/MessageContainer/components/DayAnimated/styles.js +0 -12
- package/lib/MessageContainer/components/DayAnimated/styles.js.map +0 -1
- package/lib/MessageContainer/components/DayAnimated/types.d.ts +0 -17
- package/lib/MessageContainer/components/DayAnimated/types.js +0 -2
- package/lib/MessageContainer/components/DayAnimated/types.js.map +0 -1
- package/lib/MessageContainer/components/Item/index.d.ts +0 -23
- package/lib/MessageContainer/components/Item/index.js +0 -88
- package/lib/MessageContainer/components/Item/index.js.map +0 -1
- package/lib/MessageContainer/components/Item/types.d.ts +0 -17
- package/lib/MessageContainer/components/Item/types.js +0 -2
- package/lib/MessageContainer/components/Item/types.js.map +0 -1
- package/lib/MessageContainer/index.d.ts +0 -6
- package/lib/MessageContainer/index.js +0 -235
- package/lib/MessageContainer/index.js.map +0 -1
- package/lib/MessageContainer/styles.d.ts +0 -35
- package/lib/MessageContainer/styles.js +0 -32
- package/lib/MessageContainer/styles.js.map +0 -1
- package/lib/MessageContainer/types.d.ts +0 -51
- package/lib/MessageContainer/types.js +0 -2
- package/lib/MessageContainer/types.js.map +0 -1
- package/lib/MessageImage.d.ts +0 -13
- package/lib/MessageImage.js +0 -30
- package/lib/MessageImage.js.map +0 -1
- package/lib/MessageText.d.ts +0 -19
- package/lib/MessageText.js +0 -69
- package/lib/MessageText.js.map +0 -1
- package/lib/MessageVideo.d.ts +0 -2
- package/lib/MessageVideo.js +0 -14
- package/lib/MessageVideo.js.map +0 -1
- package/lib/QuickReplies.d.ts +0 -15
- package/lib/QuickReplies.js +0 -101
- package/lib/QuickReplies.js.map +0 -1
- package/lib/Send.d.ts +0 -15
- package/lib/Send.js +0 -34
- package/lib/Send.js.map +0 -1
- package/lib/SystemMessage.d.ts +0 -11
- package/lib/SystemMessage.js +0 -27
- package/lib/SystemMessage.js.map +0 -1
- package/lib/Time.d.ts +0 -11
- package/lib/Time.js +0 -56
- package/lib/Time.js.map +0 -1
- package/lib/TypingIndicator/index.d.ts +0 -5
- package/lib/TypingIndicator/index.js +0 -94
- package/lib/TypingIndicator/index.js.map +0 -1
- package/lib/TypingIndicator/styles.d.ts +0 -20
- package/lib/TypingIndicator/styles.js +0 -22
- package/lib/TypingIndicator/styles.js.map +0 -1
- package/lib/TypingIndicator/types.d.ts +0 -3
- package/lib/TypingIndicator/types.js +0 -2
- package/lib/TypingIndicator/types.js.map +0 -1
- package/lib/hooks/useUpdateLayoutEffect.d.ts +0 -8
- package/lib/hooks/useUpdateLayoutEffect.js +0 -17
- package/lib/hooks/useUpdateLayoutEffect.js.map +0 -1
- package/lib/index.d.ts +0 -4
- package/lib/index.js +0 -5
- package/lib/index.js.map +0 -1
- package/lib/logging.d.ts +0 -2
- package/lib/logging.js +0 -5
- package/lib/logging.js.map +0 -1
- package/lib/styles.d.ts +0 -10
- package/lib/styles.js +0 -11
- package/lib/styles.js.map +0 -1
- package/lib/types.d.ts +0 -67
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts +0 -5
- package/lib/utils.js +0 -83
- package/lib/utils.js.map +0 -1
- package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +0 -108
package/src/MessageImage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Image,
|
|
4
4
|
StyleSheet,
|
|
@@ -8,11 +8,16 @@ import {
|
|
|
8
8
|
StyleProp,
|
|
9
9
|
ImageStyle,
|
|
10
10
|
ImageURISource,
|
|
11
|
+
Modal,
|
|
12
|
+
TouchableOpacity,
|
|
13
|
+
LayoutChangeEvent,
|
|
14
|
+
useWindowDimensions,
|
|
11
15
|
} from 'react-native'
|
|
12
|
-
|
|
13
|
-
import
|
|
16
|
+
import { BaseButton, GestureHandlerRootView, Text } from 'react-native-gesture-handler'
|
|
17
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
18
|
+
import Zoom from 'react-native-zoom-reanimated'
|
|
19
|
+
import commonStyles from './styles'
|
|
14
20
|
import { IMessage } from './types'
|
|
15
|
-
import stylesCommon from './styles'
|
|
16
21
|
|
|
17
22
|
const styles = StyleSheet.create({
|
|
18
23
|
image: {
|
|
@@ -22,8 +27,25 @@ const styles = StyleSheet.create({
|
|
|
22
27
|
margin: 3,
|
|
23
28
|
resizeMode: 'cover',
|
|
24
29
|
},
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
modalContent: {
|
|
31
|
+
backgroundColor: '#000',
|
|
32
|
+
},
|
|
33
|
+
modalImageContainer: {
|
|
34
|
+
width: '100%',
|
|
35
|
+
height: '100%',
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
closeButtonContainer: {
|
|
39
|
+
flexDirection: 'row',
|
|
40
|
+
justifyContent: 'flex-end',
|
|
41
|
+
},
|
|
42
|
+
closeButtonContent: {
|
|
43
|
+
padding: 10,
|
|
44
|
+
},
|
|
45
|
+
closeButtonIcon: {
|
|
46
|
+
fontSize: 20,
|
|
47
|
+
lineHeight: 20,
|
|
48
|
+
color: 'white',
|
|
27
49
|
},
|
|
28
50
|
})
|
|
29
51
|
|
|
@@ -33,35 +55,127 @@ export interface MessageImageProps<TMessage extends IMessage> {
|
|
|
33
55
|
imageSourceProps?: Partial<ImageURISource>
|
|
34
56
|
imageStyle?: StyleProp<ImageStyle>
|
|
35
57
|
imageProps?: Partial<ImageProps>
|
|
36
|
-
lightboxProps?: LightboxProps
|
|
37
58
|
}
|
|
38
59
|
|
|
39
60
|
export function MessageImage<TMessage extends IMessage = IMessage> ({
|
|
40
61
|
containerStyle,
|
|
41
|
-
lightboxProps,
|
|
42
62
|
imageProps,
|
|
43
63
|
imageSourceProps,
|
|
44
64
|
imageStyle,
|
|
45
65
|
currentMessage,
|
|
46
66
|
}: MessageImageProps<TMessage>) {
|
|
67
|
+
const [isModalVisible, setIsModalVisible] = useState(false)
|
|
68
|
+
const [imageDimensions, setImageDimensions] = useState<{ width: number, height: number }>()
|
|
69
|
+
const windowDimensions = useWindowDimensions()
|
|
70
|
+
|
|
71
|
+
const insets = useSafeAreaInsets()
|
|
72
|
+
|
|
73
|
+
const imageSource = useMemo(() => ({
|
|
74
|
+
...imageSourceProps,
|
|
75
|
+
uri: currentMessage?.image,
|
|
76
|
+
}), [imageSourceProps, currentMessage?.image])
|
|
77
|
+
|
|
78
|
+
const isImageSourceChanged = useRef(true)
|
|
79
|
+
|
|
80
|
+
const computedImageStyle = useMemo(() => [
|
|
81
|
+
styles.image,
|
|
82
|
+
imageStyle,
|
|
83
|
+
], [imageStyle])
|
|
84
|
+
|
|
85
|
+
const handleImagePress = useCallback(() => {
|
|
86
|
+
if (!imageSource.uri)
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
setIsModalVisible(true)
|
|
90
|
+
|
|
91
|
+
if (isImageSourceChanged.current || !imageDimensions)
|
|
92
|
+
Image.getSize(imageSource.uri, (width, height) => {
|
|
93
|
+
setImageDimensions({ width, height })
|
|
94
|
+
})
|
|
95
|
+
}, [imageSource.uri, imageDimensions])
|
|
96
|
+
|
|
97
|
+
const handleModalClose = useCallback(() => {
|
|
98
|
+
setIsModalVisible(false)
|
|
99
|
+
}, [])
|
|
100
|
+
|
|
101
|
+
const handleImageLayout = useCallback((e: LayoutChangeEvent) => {
|
|
102
|
+
setImageDimensions({
|
|
103
|
+
width: e.nativeEvent.layout.width,
|
|
104
|
+
height: e.nativeEvent.layout.height,
|
|
105
|
+
})
|
|
106
|
+
}, [])
|
|
107
|
+
|
|
108
|
+
const modalImageDimensions = useMemo(() => {
|
|
109
|
+
if (!imageDimensions)
|
|
110
|
+
return undefined
|
|
111
|
+
|
|
112
|
+
const aspectRatio = imageDimensions.width / imageDimensions.height
|
|
113
|
+
|
|
114
|
+
let width = windowDimensions.width
|
|
115
|
+
let height = width / aspectRatio
|
|
116
|
+
|
|
117
|
+
if (height > windowDimensions.height) {
|
|
118
|
+
height = windowDimensions.height
|
|
119
|
+
width = height * aspectRatio
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
width,
|
|
124
|
+
height,
|
|
125
|
+
}
|
|
126
|
+
}, [imageDimensions, windowDimensions.height, windowDimensions.width])
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
isImageSourceChanged.current = true
|
|
130
|
+
}, [imageSource.uri])
|
|
131
|
+
|
|
47
132
|
if (currentMessage == null)
|
|
48
133
|
return null
|
|
49
134
|
|
|
50
135
|
return (
|
|
51
136
|
<View style={containerStyle}>
|
|
52
|
-
{
|
|
53
|
-
<Lightbox
|
|
54
|
-
activeProps={{
|
|
55
|
-
style: [stylesCommon.fill, styles.imageActive],
|
|
56
|
-
}}
|
|
57
|
-
{...lightboxProps}
|
|
58
|
-
>
|
|
137
|
+
<TouchableOpacity onPress={handleImagePress}>
|
|
59
138
|
<Image
|
|
60
139
|
{...imageProps}
|
|
61
|
-
style={
|
|
62
|
-
source={
|
|
140
|
+
style={computedImageStyle}
|
|
141
|
+
source={imageSource}
|
|
142
|
+
onLayout={handleImageLayout}
|
|
63
143
|
/>
|
|
64
|
-
</
|
|
144
|
+
</TouchableOpacity>
|
|
145
|
+
|
|
146
|
+
<Modal
|
|
147
|
+
visible={isModalVisible}
|
|
148
|
+
onRequestClose={handleModalClose}
|
|
149
|
+
animationType='slide'
|
|
150
|
+
transparent={false}
|
|
151
|
+
>
|
|
152
|
+
<GestureHandlerRootView style={commonStyles.fill}>
|
|
153
|
+
<View style={[commonStyles.fill, styles.modalContent, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
|
|
154
|
+
|
|
155
|
+
{/* close button */}
|
|
156
|
+
<View style={styles.closeButtonContainer}>
|
|
157
|
+
<BaseButton onPress={handleModalClose}>
|
|
158
|
+
<View style={styles.closeButtonContent}>
|
|
159
|
+
<Text style={styles.closeButtonIcon}>
|
|
160
|
+
{'X'}
|
|
161
|
+
</Text>
|
|
162
|
+
</View>
|
|
163
|
+
</BaseButton>
|
|
164
|
+
</View>
|
|
165
|
+
|
|
166
|
+
<View style={[commonStyles.fill, commonStyles.centerItems]}>
|
|
167
|
+
<Zoom>
|
|
168
|
+
<Image
|
|
169
|
+
style={modalImageDimensions}
|
|
170
|
+
source={imageSource}
|
|
171
|
+
resizeMode='contain'
|
|
172
|
+
{...imageProps}
|
|
173
|
+
/>
|
|
174
|
+
</Zoom>
|
|
175
|
+
</View>
|
|
176
|
+
</View>
|
|
177
|
+
</GestureHandlerRootView>
|
|
178
|
+
</Modal>
|
|
65
179
|
</View>
|
|
66
180
|
)
|
|
67
181
|
}
|
package/src/MessageText.tsx
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import React, { useMemo, useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
|
-
Linking,
|
|
4
3
|
StyleSheet,
|
|
5
4
|
StyleProp,
|
|
6
5
|
ViewStyle,
|
|
7
6
|
TextStyle,
|
|
7
|
+
View,
|
|
8
8
|
} from 'react-native'
|
|
9
9
|
|
|
10
|
-
import Autolink, { AutolinkProps } from 'react-native-autolink'
|
|
11
10
|
import { Match } from 'autolinker/dist/es2015'
|
|
11
|
+
import Autolink, { AutolinkProps } from 'react-native-autolink'
|
|
12
12
|
import { LeftRightStyle, IMessage } from './types'
|
|
13
|
-
import { error } from './logging'
|
|
14
|
-
|
|
15
|
-
export interface MessageOption {
|
|
16
|
-
title: string
|
|
17
|
-
action: (phone: string) => void
|
|
18
|
-
}
|
|
19
13
|
|
|
20
14
|
export type MessageTextProps<TMessage extends IMessage> = {
|
|
21
15
|
position?: 'left' | 'right'
|
|
@@ -41,82 +35,48 @@ export const MessageText: React.FC<MessageTextProps<IMessage>> = ({
|
|
|
41
35
|
onPress: onPressProp,
|
|
42
36
|
...rest
|
|
43
37
|
}) => {
|
|
44
|
-
// TODO: React.memo
|
|
45
|
-
// const shouldComponentUpdate = (nextProps: MessageTextProps<TMessage>) => {
|
|
46
|
-
// return (
|
|
47
|
-
// !!currentMessage &&
|
|
48
|
-
// !!nextProps.currentMessage &&
|
|
49
|
-
// currentMessage.text !== nextProps.currentMessage.text
|
|
50
|
-
// )
|
|
51
|
-
// }
|
|
52
|
-
|
|
53
|
-
const onUrlPress = useCallback((url: string) => {
|
|
54
|
-
if (/^www\./i.test(url))
|
|
55
|
-
url = `https://${url}`
|
|
56
|
-
|
|
57
|
-
Linking.openURL(url).catch(e => {
|
|
58
|
-
error(e, 'No handler for URL:', url)
|
|
59
|
-
})
|
|
60
|
-
}, [])
|
|
61
|
-
|
|
62
|
-
const onPhonePress = useCallback((phone: string) => {
|
|
63
|
-
Linking.openURL(`tel:${phone}`).catch(e => {
|
|
64
|
-
error(e, 'No handler for telephone')
|
|
65
|
-
})
|
|
66
|
-
}, [])
|
|
67
|
-
|
|
68
|
-
const onEmailPress = useCallback((email: string) =>
|
|
69
|
-
Linking.openURL(`mailto:${email}`).catch(e =>
|
|
70
|
-
error(e, 'No handler for mailto')
|
|
71
|
-
), [])
|
|
72
|
-
|
|
73
38
|
const linkStyle = useMemo(() => StyleSheet.flatten([
|
|
74
39
|
styles.link,
|
|
75
40
|
linkStyleProp?.[position],
|
|
76
41
|
]), [position, linkStyleProp])
|
|
77
42
|
|
|
78
|
-
const handlePress = useCallback((url: string, match: Match) => {
|
|
79
|
-
const type = match.getType()
|
|
80
|
-
|
|
81
|
-
if (onPressProp)
|
|
82
|
-
onPressProp(currentMessage, url, match)
|
|
83
|
-
else if (type === 'url')
|
|
84
|
-
onUrlPress(url)
|
|
85
|
-
else if (type === 'phone')
|
|
86
|
-
onPhonePress(url)
|
|
87
|
-
else if (type === 'email')
|
|
88
|
-
onEmailPress(url)
|
|
89
|
-
}, [onUrlPress, onPhonePress, onEmailPress, onPressProp, currentMessage])
|
|
90
|
-
|
|
91
43
|
const style = useMemo(() => [
|
|
92
|
-
containerStyle?.[position],
|
|
93
44
|
styles[`text_${position}`],
|
|
94
45
|
textStyle?.[position],
|
|
95
46
|
customTextStyle,
|
|
96
|
-
], [
|
|
47
|
+
], [position, textStyle, customTextStyle])
|
|
48
|
+
|
|
49
|
+
const handlePress = useCallback((url: string, match: Match) => {
|
|
50
|
+
onPressProp?.(currentMessage, url, match)
|
|
51
|
+
}, [onPressProp, currentMessage])
|
|
97
52
|
|
|
98
53
|
return (
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
54
|
+
<View style={[styles.container, containerStyle?.[position]]}>
|
|
55
|
+
<Autolink
|
|
56
|
+
email
|
|
57
|
+
phone
|
|
58
|
+
link
|
|
59
|
+
{...rest}
|
|
60
|
+
onPress={onPressProp ? handlePress : undefined}
|
|
61
|
+
linkStyle={linkStyle}
|
|
62
|
+
style={style}
|
|
63
|
+
text={currentMessage!.text}
|
|
64
|
+
/>
|
|
65
|
+
</View>
|
|
108
66
|
)
|
|
109
67
|
}
|
|
110
68
|
|
|
111
69
|
const styles = StyleSheet.create({
|
|
112
|
-
|
|
113
|
-
fontSize: 16,
|
|
114
|
-
lineHeight: 20,
|
|
70
|
+
container: {
|
|
115
71
|
marginTop: 5,
|
|
116
72
|
marginBottom: 5,
|
|
117
73
|
marginLeft: 10,
|
|
118
74
|
marginRight: 10,
|
|
119
75
|
},
|
|
76
|
+
text: {
|
|
77
|
+
fontSize: 16,
|
|
78
|
+
lineHeight: 20,
|
|
79
|
+
},
|
|
120
80
|
text_left: {
|
|
121
81
|
color: 'black',
|
|
122
82
|
},
|
package/src/MessageVideo.tsx
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native'
|
|
2
3
|
import Color from './Color'
|
|
3
|
-
|
|
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
|
-
|
|
7
|
-
<View style={
|
|
8
|
-
<Text style={
|
|
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={
|
|
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
|
}
|
package/src/QuickReplies.tsx
CHANGED
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
Text,
|
|
4
4
|
StyleSheet,
|
|
5
5
|
View,
|
|
6
|
-
TouchableOpacity,
|
|
7
6
|
StyleProp,
|
|
8
7
|
ViewStyle,
|
|
9
8
|
TextStyle,
|
|
10
9
|
} from 'react-native'
|
|
11
|
-
import { IMessage, Reply } from './types'
|
|
12
10
|
import Color from './Color'
|
|
11
|
+
import { TouchableOpacity } from './components/TouchableOpacity'
|
|
13
12
|
import { warning } from './logging'
|
|
14
13
|
import stylesCommon from './styles'
|
|
14
|
+
import { IMessage, Reply } from './types'
|
|
15
15
|
|
|
16
16
|
const styles = StyleSheet.create({
|
|
17
17
|
container: {
|
|
@@ -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
|
-
{
|
|
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
|
@@ -2,17 +2,17 @@ import React, { useMemo, useCallback } from 'react'
|
|
|
2
2
|
import {
|
|
3
3
|
StyleSheet,
|
|
4
4
|
Text,
|
|
5
|
-
TouchableOpacity,
|
|
6
5
|
View,
|
|
7
6
|
StyleProp,
|
|
8
7
|
ViewStyle,
|
|
9
8
|
TextStyle,
|
|
10
|
-
|
|
9
|
+
useColorScheme,
|
|
11
10
|
} from 'react-native'
|
|
12
|
-
|
|
13
11
|
import Color from './Color'
|
|
14
|
-
|
|
12
|
+
|
|
13
|
+
import { TouchableOpacity, TouchableOpacityProps } from './components/TouchableOpacity'
|
|
15
14
|
import { TEST_ID } from './Constant'
|
|
15
|
+
import { IMessage } from './types'
|
|
16
16
|
|
|
17
17
|
const styles = StyleSheet.create({
|
|
18
18
|
container: {
|
|
@@ -28,6 +28,9 @@ const styles = StyleSheet.create({
|
|
|
28
28
|
marginLeft: 10,
|
|
29
29
|
marginRight: 10,
|
|
30
30
|
},
|
|
31
|
+
text_dark: {
|
|
32
|
+
color: '#4da6ff',
|
|
33
|
+
},
|
|
31
34
|
})
|
|
32
35
|
|
|
33
36
|
export interface SendProps<TMessage extends IMessage> {
|
|
@@ -56,6 +59,8 @@ export const Send = <TMessage extends IMessage = IMessage>({
|
|
|
56
59
|
sendButtonProps,
|
|
57
60
|
onSend,
|
|
58
61
|
}: SendProps<TMessage>) => {
|
|
62
|
+
const colorScheme = useColorScheme()
|
|
63
|
+
|
|
59
64
|
const handleOnPress = useCallback(() => {
|
|
60
65
|
if (text && onSend)
|
|
61
66
|
onSend({ text: text.trim() } as Partial<TMessage>, true)
|
|
@@ -81,7 +86,7 @@ export const Send = <TMessage extends IMessage = IMessage>({
|
|
|
81
86
|
{...sendButtonProps}
|
|
82
87
|
>
|
|
83
88
|
<View>
|
|
84
|
-
{children || <Text style={[styles.text, textStyle]}>{label}</Text>}
|
|
89
|
+
{children || <Text style={[styles.text, styles[`text_${colorScheme}`], textStyle]}>{label}</Text>}
|
|
85
90
|
</View>
|
|
86
91
|
</TouchableOpacity>
|
|
87
92
|
)
|
package/src/SystemMessage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
StyleSheet,
|
|
4
4
|
Text,
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
TextStyle,
|
|
9
9
|
} from 'react-native'
|
|
10
10
|
import Color from './Color'
|
|
11
|
-
import { IMessage } from './types'
|
|
12
11
|
import stylesCommon from './styles'
|
|
12
|
+
import { IMessage } from './types'
|
|
13
13
|
|
|
14
14
|
const styles = StyleSheet.create({
|
|
15
15
|
container: {
|
|
@@ -39,13 +39,20 @@ export function SystemMessage<TMessage extends IMessage = IMessage> ({
|
|
|
39
39
|
textStyle,
|
|
40
40
|
children,
|
|
41
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
|
+
|
|
42
49
|
if (currentMessage == null || currentMessage.system === false)
|
|
43
50
|
return null
|
|
44
51
|
|
|
45
52
|
return (
|
|
46
53
|
<View style={[stylesCommon.fill, stylesCommon.centerItems, styles.container, containerStyle]}>
|
|
47
54
|
<View style={wrapperStyle}>
|
|
48
|
-
{
|
|
55
|
+
{textContent}
|
|
49
56
|
{children}
|
|
50
57
|
</View>
|
|
51
58
|
</View>
|
package/src/Time.tsx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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
|
|
|
5
5
|
import Color from './Color'
|
|
6
6
|
import { TIME_FORMAT } from './Constant'
|
|
7
|
-
import { LeftRightStyle, IMessage } from './types'
|
|
8
7
|
import { useChatContext } from './GiftedChatContext'
|
|
8
|
+
import { LeftRightStyle, IMessage } from './types'
|
|
9
9
|
|
|
10
10
|
const { containerStyle } = StyleSheet.create({
|
|
11
11
|
containerStyle: {
|
|
@@ -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
|
-
{
|
|
86
|
+
{formattedTime}
|
|
80
87
|
</Text>
|
|
81
88
|
</View>
|
|
82
89
|
)
|
|
@@ -9,10 +9,10 @@ import Animated, {
|
|
|
9
9
|
withSequence,
|
|
10
10
|
withTiming,
|
|
11
11
|
} from 'react-native-reanimated'
|
|
12
|
-
import { TypingIndicatorProps } from './types'
|
|
13
|
-
|
|
14
12
|
import stylesCommon from '../styles'
|
|
13
|
+
|
|
15
14
|
import styles from './styles'
|
|
15
|
+
import { TypingIndicatorProps } from './types'
|
|
16
16
|
|
|
17
17
|
export * from './types'
|
|
18
18
|
|
|
@@ -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,10 +1,9 @@
|
|
|
1
|
-
import 'react-native'
|
|
2
1
|
import React from 'react'
|
|
3
|
-
import
|
|
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
|
|
9
|
-
expect(
|
|
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
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const { toJSON } = render(
|
|
8
|
+
<Avatar renderAvatar={() => 'renderAvatar'} position='left' />
|
|
9
|
+
)
|
|
11
10
|
|
|
12
|
-
expect(
|
|
11
|
+
expect(toJSON()).toMatchSnapshot()
|
|
13
12
|
})
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
import 'react-native'
|
|
2
1
|
import React from 'react'
|
|
3
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
7
|
+
const { toJSON } = render(<Composer />)
|
|
9
8
|
|
|
10
|
-
expect(
|
|
9
|
+
expect(toJSON()).toMatchSnapshot()
|
|
11
10
|
})
|