react-native-gifted-chat 2.8.2-alpha.1 → 2.8.2-alpha.3
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 +68 -27
- package/package.json +10 -11
- package/src/Actions.tsx +14 -16
- package/src/Avatar.tsx +1 -1
- package/src/Bubble/index.tsx +13 -10
- package/src/Bubble/types.ts +5 -4
- package/src/Composer.tsx +1 -1
- package/src/Day/index.tsx +3 -3
- package/src/GiftedAvatar.tsx +2 -2
- package/src/GiftedChat/index.tsx +53 -46
- package/src/GiftedChat/styles.ts +3 -0
- package/src/GiftedChat/types.ts +15 -18
- package/src/InputToolbar.tsx +10 -10
- package/src/LoadEarlier.tsx +7 -7
- package/src/LoadEarlierMessages.tsx +97 -0
- package/src/Message/index.tsx +4 -18
- package/src/Message/types.ts +2 -2
- package/src/MessageAudio.tsx +1 -1
- package/src/MessageContainer/components/DayAnimated/index.tsx +9 -9
- package/src/MessageContainer/components/DayAnimated/types.ts +1 -1
- package/src/MessageContainer/components/Item/index.tsx +3 -3
- package/src/MessageContainer/components/Item/types.ts +1 -1
- package/src/MessageContainer/index.tsx +22 -27
- package/src/MessageContainer/types.ts +6 -12
- package/src/MessageImage.tsx +119 -17
- package/src/MessageText.tsx +10 -45
- package/src/MessageVideo.tsx +1 -1
- package/src/QuickReplies.tsx +2 -2
- package/src/Send.tsx +3 -4
- package/src/SystemMessage.tsx +1 -1
- package/src/Time.tsx +1 -1
- package/src/TypingIndicator/index.tsx +2 -2
- package/src/__tests__/DayAnimated.test.tsx +4 -4
- package/src/__tests__/GiftedChat.test.tsx +3 -3
- package/src/__tests__/LoadEarlier.test.tsx +3 -3
- package/src/__tests__/__snapshots__/Actions.test.tsx.snap +39 -7
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +20 -22
- package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +38 -7
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +34 -15
- package/src/__tests__/__snapshots__/Send.test.tsx.snap +70 -10
- package/src/components/TouchableOpacity.tsx +45 -0
- package/src/types.ts +1 -3
- package/src/utils.ts +2 -2
|
@@ -3,31 +3,30 @@ import {
|
|
|
3
3
|
View,
|
|
4
4
|
Pressable,
|
|
5
5
|
Text,
|
|
6
|
-
Platform,
|
|
7
6
|
LayoutChangeEvent,
|
|
8
7
|
ListRenderItemInfo,
|
|
9
|
-
FlatList,
|
|
10
8
|
CellRendererProps,
|
|
11
9
|
} from 'react-native'
|
|
10
|
+
import { FlatList } from 'react-native-gesture-handler'
|
|
12
11
|
import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
|
|
12
|
+
import { LoadEarlierMessages } from '../LoadEarlierMessages'
|
|
13
|
+
import { warning } from '../logging'
|
|
13
14
|
import { ReanimatedScrollEvent } from '../reanimatedCompat'
|
|
14
|
-
import DayAnimated from './components/DayAnimated'
|
|
15
|
-
import Item from './components/Item'
|
|
16
15
|
|
|
17
|
-
import
|
|
16
|
+
import stylesCommon from '../styles'
|
|
18
17
|
import { IMessage } from '../types'
|
|
19
18
|
import TypingIndicator from '../TypingIndicator'
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
19
|
+
import { isSameDay, useCallbackThrottled } from '../utils'
|
|
20
|
+
import DayAnimated from './components/DayAnimated'
|
|
22
21
|
|
|
23
|
-
import
|
|
24
|
-
import
|
|
22
|
+
import Item from './components/Item'
|
|
23
|
+
import { ItemProps } from './components/Item/types'
|
|
25
24
|
import styles from './styles'
|
|
26
|
-
import {
|
|
25
|
+
import { MessageContainerProps, DaysPositions } from './types'
|
|
27
26
|
|
|
28
27
|
export * from './types'
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
|
|
31
30
|
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList) as React.ComponentType<any>
|
|
32
31
|
|
|
33
32
|
function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageContainerProps<TMessage>) {
|
|
@@ -36,17 +35,14 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
36
35
|
user,
|
|
37
36
|
isTyping = false,
|
|
38
37
|
renderChatEmpty: renderChatEmptyProp,
|
|
39
|
-
onLoadEarlier,
|
|
40
38
|
inverted = true,
|
|
41
|
-
loadEarlier = false,
|
|
42
39
|
listProps,
|
|
43
40
|
extraData,
|
|
44
41
|
isScrollToBottomEnabled = false,
|
|
45
42
|
scrollToBottomOffset = 200,
|
|
46
43
|
alignTop = false,
|
|
47
44
|
scrollToBottomStyle,
|
|
48
|
-
|
|
49
|
-
isLoadingEarlier = false,
|
|
45
|
+
loadEarlierMessagesProps,
|
|
50
46
|
renderTypingIndicator: renderTypingIndicatorProp,
|
|
51
47
|
renderFooter: renderFooterProp,
|
|
52
48
|
renderLoadEarlier: renderLoadEarlierProp,
|
|
@@ -83,15 +79,15 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
83
79
|
}, [renderFooterProp, renderTypingIndicator, props])
|
|
84
80
|
|
|
85
81
|
const renderLoadEarlier = useCallback(() => {
|
|
86
|
-
if (
|
|
82
|
+
if (loadEarlierMessagesProps?.onPress && loadEarlierMessagesProps?.isAvailable) {
|
|
87
83
|
if (renderLoadEarlierProp)
|
|
88
|
-
return renderLoadEarlierProp(
|
|
84
|
+
return renderLoadEarlierProp(loadEarlierMessagesProps)
|
|
89
85
|
|
|
90
|
-
return <
|
|
86
|
+
return <LoadEarlierMessages {...loadEarlierMessagesProps} />
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
return null
|
|
94
|
-
}, [
|
|
90
|
+
}, [loadEarlierMessagesProps, renderLoadEarlierProp])
|
|
95
91
|
|
|
96
92
|
const changeScrollToBottomVisibility: (isVisible: boolean) => void = useCallbackThrottled((isVisible: boolean) => {
|
|
97
93
|
if (isScrollingDown.value && isVisible)
|
|
@@ -290,14 +286,13 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
290
286
|
|
|
291
287
|
const onEndReached = useCallback(() => {
|
|
292
288
|
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
!
|
|
297
|
-
Platform.OS !== 'web'
|
|
289
|
+
loadEarlierMessagesProps?.isInfiniteScrollEnabled &&
|
|
290
|
+
loadEarlierMessagesProps?.onPress &&
|
|
291
|
+
loadEarlierMessagesProps?.isAvailable &&
|
|
292
|
+
!loadEarlierMessagesProps?.isLoading
|
|
298
293
|
)
|
|
299
|
-
|
|
300
|
-
}, [
|
|
294
|
+
loadEarlierMessagesProps.onPress()
|
|
295
|
+
}, [loadEarlierMessagesProps])
|
|
301
296
|
|
|
302
297
|
const keyExtractor = useCallback((item: unknown) => (item as TMessage)._id.toString(), [])
|
|
303
298
|
|
|
@@ -420,7 +415,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
420
415
|
listHeight={listHeight}
|
|
421
416
|
renderDay={renderDayProp}
|
|
422
417
|
messages={messages}
|
|
423
|
-
|
|
418
|
+
isLoading={loadEarlierMessagesProps?.isLoading ?? false}
|
|
424
419
|
/>
|
|
425
420
|
</View>
|
|
426
421
|
)
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
FlatListProps,
|
|
4
4
|
StyleProp,
|
|
5
5
|
ViewStyle,
|
|
6
|
-
FlatList,
|
|
7
6
|
} from 'react-native'
|
|
7
|
+
import { FlatList } from 'react-native-gesture-handler'
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { LoadEarlierMessagesProps } from '../LoadEarlierMessages'
|
|
10
10
|
import { MessageProps } from '../Message'
|
|
11
|
-
import { User, IMessage, Reply, DayProps } from '../types'
|
|
12
11
|
import { ReanimatedScrollEvent } from '../reanimatedCompat'
|
|
12
|
+
import { User, IMessage, Reply, DayProps } from '../types'
|
|
13
13
|
import { TypingIndicatorProps } from '../TypingIndicator/types'
|
|
14
14
|
|
|
15
15
|
export type ListProps<TMessage extends IMessage = IMessage> = Partial<FlatListProps<TMessage>>
|
|
@@ -28,8 +28,6 @@ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
|
|
|
28
28
|
listProps?: ListProps<TMessage>
|
|
29
29
|
/** Reverses display order of messages; default is true */
|
|
30
30
|
inverted?: boolean
|
|
31
|
-
/** Enables the "Load earlier messages" button */
|
|
32
|
-
loadEarlier?: boolean
|
|
33
31
|
/** Controls whether or not the message bubbles appear at the top of the chat */
|
|
34
32
|
alignTop?: boolean
|
|
35
33
|
/** Enables the isScrollToBottomEnabled Component */
|
|
@@ -49,19 +47,15 @@ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
|
|
|
49
47
|
/** Custom day above a message */
|
|
50
48
|
renderDay?(props: DayProps): React.ReactNode
|
|
51
49
|
/** Custom "Load earlier messages" button */
|
|
52
|
-
renderLoadEarlier?(props:
|
|
50
|
+
renderLoadEarlier?(props: LoadEarlierMessagesProps): React.ReactNode
|
|
53
51
|
/** Custom typing indicator */
|
|
54
52
|
renderTypingIndicator?(): React.ReactNode
|
|
55
53
|
/** Scroll to bottom custom component */
|
|
56
54
|
scrollToBottomComponent?(): React.ReactNode
|
|
57
|
-
/** Callback when loading earlier messages */
|
|
58
|
-
onLoadEarlier?(): void
|
|
59
55
|
/** Callback when quick reply is sent */
|
|
60
56
|
onQuickReply?(replies: Reply[]): void
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
/** Display an ActivityIndicator when loading earlier messages */
|
|
64
|
-
isLoadingEarlier?: boolean
|
|
57
|
+
/** Props to pass to the LoadEarlierMessages component. The LoadEarlierMessages button is only visible when isAvailable is true. Includes isAvailable (controls button visibility), isInfiniteScrollEnabled (infinite scroll up when reach the top of messages container, automatically call onPress function if it exists - not yet supported for web), onPress (callback when button is pressed), isLoading (display loading indicator), label (override default "Load earlier messages" text), and styling props (containerStyle, wrapperStyle, textStyle, activityIndicatorStyle, activityIndicatorColor, activityIndicatorSize). */
|
|
58
|
+
loadEarlierMessagesProps?: LoadEarlierMessagesProps
|
|
65
59
|
/** Custom scroll event handler */
|
|
66
60
|
handleOnScroll?(event: ReanimatedScrollEvent): void
|
|
67
61
|
/** Style for TypingIndicator component */
|
package/src/MessageImage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo } 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,47 +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
|
+
|
|
47
73
|
const imageSource = useMemo(() => ({
|
|
48
74
|
...imageSourceProps,
|
|
49
75
|
uri: currentMessage?.image,
|
|
50
76
|
}), [imageSourceProps, currentMessage?.image])
|
|
51
77
|
|
|
78
|
+
const isImageSourceChanged = useRef(true)
|
|
79
|
+
|
|
52
80
|
const computedImageStyle = useMemo(() => [
|
|
53
81
|
styles.image,
|
|
54
82
|
imageStyle,
|
|
55
83
|
], [imageStyle])
|
|
56
84
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
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])
|
|
60
131
|
|
|
61
132
|
if (currentMessage == null)
|
|
62
133
|
return null
|
|
63
134
|
|
|
64
135
|
return (
|
|
65
136
|
<View style={containerStyle}>
|
|
66
|
-
{
|
|
67
|
-
<Lightbox
|
|
68
|
-
activeProps={activePropsStyle}
|
|
69
|
-
{...lightboxProps}
|
|
70
|
-
>
|
|
137
|
+
<TouchableOpacity onPress={handleImagePress}>
|
|
71
138
|
<Image
|
|
72
139
|
{...imageProps}
|
|
73
140
|
style={computedImageStyle}
|
|
74
141
|
source={imageSource}
|
|
142
|
+
onLayout={handleImageLayout}
|
|
75
143
|
/>
|
|
76
|
-
</
|
|
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>
|
|
77
179
|
</View>
|
|
78
180
|
)
|
|
79
181
|
}
|
package/src/MessageText.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, { useMemo, useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
|
-
Linking,
|
|
4
3
|
StyleSheet,
|
|
5
4
|
StyleProp,
|
|
6
5
|
ViewStyle,
|
|
@@ -8,15 +7,9 @@ import {
|
|
|
8
7
|
View,
|
|
9
8
|
} from 'react-native'
|
|
10
9
|
|
|
11
|
-
import Autolink, { AutolinkProps } from 'react-native-autolink'
|
|
12
10
|
import { Match } from 'autolinker/dist/es2015'
|
|
11
|
+
import Autolink, { AutolinkProps } from 'react-native-autolink'
|
|
13
12
|
import { LeftRightStyle, IMessage } from './types'
|
|
14
|
-
import { error } from './logging'
|
|
15
|
-
|
|
16
|
-
export interface MessageOption {
|
|
17
|
-
title: string
|
|
18
|
-
action: (phone: string) => void
|
|
19
|
-
}
|
|
20
13
|
|
|
21
14
|
export type MessageTextProps<TMessage extends IMessage> = {
|
|
22
15
|
position?: 'left' | 'right'
|
|
@@ -42,60 +35,32 @@ export const MessageText: React.FC<MessageTextProps<IMessage>> = ({
|
|
|
42
35
|
onPress: onPressProp,
|
|
43
36
|
...rest
|
|
44
37
|
}) => {
|
|
45
|
-
const onUrlPress = useCallback((url: string) => {
|
|
46
|
-
if (/^www\./i.test(url))
|
|
47
|
-
url = `https://${url}`
|
|
48
|
-
|
|
49
|
-
Linking.openURL(url).catch(e => {
|
|
50
|
-
error(e, 'No handler for URL:', url)
|
|
51
|
-
})
|
|
52
|
-
}, [])
|
|
53
|
-
|
|
54
|
-
const onPhonePress = useCallback((phone: string) => {
|
|
55
|
-
Linking.openURL(`tel:${phone}`).catch(e => {
|
|
56
|
-
error(e, 'No handler for telephone')
|
|
57
|
-
})
|
|
58
|
-
}, [])
|
|
59
|
-
|
|
60
|
-
const onEmailPress = useCallback((email: string) =>
|
|
61
|
-
Linking.openURL(`mailto:${email}`).catch(e =>
|
|
62
|
-
error(e, 'No handler for mailto')
|
|
63
|
-
), [])
|
|
64
|
-
|
|
65
38
|
const linkStyle = useMemo(() => StyleSheet.flatten([
|
|
66
39
|
styles.link,
|
|
67
40
|
linkStyleProp?.[position],
|
|
68
41
|
]), [position, linkStyleProp])
|
|
69
42
|
|
|
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
43
|
const style = useMemo(() => [
|
|
84
44
|
styles[`text_${position}`],
|
|
85
45
|
textStyle?.[position],
|
|
86
46
|
customTextStyle,
|
|
87
47
|
], [position, textStyle, customTextStyle])
|
|
88
48
|
|
|
49
|
+
const handlePress = useCallback((url: string, match: Match) => {
|
|
50
|
+
onPressProp?.(currentMessage, url, match)
|
|
51
|
+
}, [onPressProp, currentMessage])
|
|
52
|
+
|
|
89
53
|
return (
|
|
90
54
|
<View style={[styles.container, containerStyle?.[position]]}>
|
|
91
55
|
<Autolink
|
|
92
|
-
style={style}
|
|
93
|
-
{...rest}
|
|
94
|
-
text={currentMessage!.text}
|
|
95
56
|
email
|
|
57
|
+
phone
|
|
96
58
|
link
|
|
59
|
+
{...rest}
|
|
60
|
+
onPress={onPressProp ? handlePress : undefined}
|
|
97
61
|
linkStyle={linkStyle}
|
|
98
|
-
|
|
62
|
+
style={style}
|
|
63
|
+
text={currentMessage!.text}
|
|
99
64
|
/>
|
|
100
65
|
</View>
|
|
101
66
|
)
|
package/src/MessageVideo.tsx
CHANGED
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: {
|
package/src/Send.tsx
CHANGED
|
@@ -2,18 +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
|
-
TouchableOpacityProps,
|
|
11
9
|
useColorScheme,
|
|
12
10
|
} from 'react-native'
|
|
13
|
-
|
|
14
11
|
import Color from './Color'
|
|
15
|
-
|
|
12
|
+
|
|
13
|
+
import { TouchableOpacity, TouchableOpacityProps } from './components/TouchableOpacity'
|
|
16
14
|
import { TEST_ID } from './Constant'
|
|
15
|
+
import { IMessage } from './types'
|
|
17
16
|
|
|
18
17
|
const styles = StyleSheet.create({
|
|
19
18
|
container: {
|
package/src/SystemMessage.tsx
CHANGED
package/src/Time.tsx
CHANGED
|
@@ -4,8 +4,8 @@ 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: {
|
|
@@ -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
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { render } from '@testing-library/react-native'
|
|
3
2
|
import { View, Text } from 'react-native'
|
|
4
|
-
import
|
|
3
|
+
import { render } from '@testing-library/react-native'
|
|
5
4
|
import { DayProps } from '../Day'
|
|
5
|
+
import DayAnimated from '../MessageContainer/components/DayAnimated'
|
|
6
6
|
|
|
7
7
|
const mockDaysPositions = { value: {} }
|
|
8
8
|
const mockScrolledY = { value: 0 }
|
|
@@ -23,7 +23,7 @@ describe('DayAnimated', () => {
|
|
|
23
23
|
daysPositions={mockDaysPositions}
|
|
24
24
|
listHeight={mockListHeight}
|
|
25
25
|
messages={[mockMessage]}
|
|
26
|
-
|
|
26
|
+
isLoading={false}
|
|
27
27
|
/>
|
|
28
28
|
)
|
|
29
29
|
expect(toJSON()).toMatchSnapshot()
|
|
@@ -42,7 +42,7 @@ describe('DayAnimated', () => {
|
|
|
42
42
|
daysPositions={mockDaysPositions}
|
|
43
43
|
listHeight={mockListHeight}
|
|
44
44
|
messages={[mockMessage]}
|
|
45
|
-
|
|
45
|
+
isLoading={false}
|
|
46
46
|
renderDay={customRenderDay}
|
|
47
47
|
/>
|
|
48
48
|
)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { render } from '@testing-library/react-native'
|
|
3
3
|
|
|
4
|
-
import { GiftedChat } from '../GiftedChat'
|
|
5
4
|
import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'
|
|
5
|
+
import { GiftedChat } from '../GiftedChat'
|
|
6
6
|
|
|
7
7
|
const messages = [
|
|
8
8
|
{
|
|
@@ -36,7 +36,7 @@ it('should render <GiftedChat/> and compare with snapshot', () => {
|
|
|
36
36
|
expect(toJSON()).toMatchSnapshot()
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
it('should render <GiftedChat/> with
|
|
39
|
+
it('should render <GiftedChat/> with isKeyboardInternallyHandled=false', () => {
|
|
40
40
|
(useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
|
|
41
41
|
height: {
|
|
42
42
|
value: 0,
|
|
@@ -50,7 +50,7 @@ it('should render <GiftedChat/> with disableKeyboardController=true', () => {
|
|
|
50
50
|
user={{
|
|
51
51
|
_id: 1,
|
|
52
52
|
}}
|
|
53
|
-
|
|
53
|
+
isKeyboardInternallyHandled={false}
|
|
54
54
|
/>
|
|
55
55
|
)
|
|
56
56
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { render } from '@testing-library/react-native'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { LoadEarlierMessages } from '../GiftedChat'
|
|
5
5
|
|
|
6
|
-
it('should render <
|
|
7
|
-
const { toJSON } = render(<
|
|
6
|
+
it('should render <LoadEarlierMessages /> and compare with snapshot', () => {
|
|
7
|
+
const { toJSON } = render(<LoadEarlierMessages />)
|
|
8
8
|
|
|
9
9
|
expect(toJSON()).toMatchSnapshot()
|
|
10
10
|
})
|
|
@@ -22,7 +22,34 @@ exports[`should render <Actions /> and compare with snapshot 1`] = `
|
|
|
22
22
|
accessible={true}
|
|
23
23
|
collapsable={false}
|
|
24
24
|
focusable={true}
|
|
25
|
+
jestAnimatedProps={
|
|
26
|
+
{
|
|
27
|
+
"value": {},
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
jestAnimatedStyle={
|
|
31
|
+
{
|
|
32
|
+
"value": {
|
|
33
|
+
"opacity": 1,
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
jestInlineStyle={
|
|
38
|
+
[
|
|
39
|
+
[
|
|
40
|
+
{
|
|
41
|
+
"height": 26,
|
|
42
|
+
"marginBottom": 10,
|
|
43
|
+
"marginLeft": 10,
|
|
44
|
+
"width": 26,
|
|
45
|
+
},
|
|
46
|
+
undefined,
|
|
47
|
+
],
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
onBlur={[Function]}
|
|
25
51
|
onClick={[Function]}
|
|
52
|
+
onFocus={[Function]}
|
|
26
53
|
onResponderGrant={[Function]}
|
|
27
54
|
onResponderMove={[Function]}
|
|
28
55
|
onResponderRelease={[Function]}
|
|
@@ -30,13 +57,18 @@ exports[`should render <Actions /> and compare with snapshot 1`] = `
|
|
|
30
57
|
onResponderTerminationRequest={[Function]}
|
|
31
58
|
onStartShouldSetResponder={[Function]}
|
|
32
59
|
style={
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
[
|
|
61
|
+
{
|
|
62
|
+
"height": 26,
|
|
63
|
+
"marginBottom": 10,
|
|
64
|
+
"marginLeft": 10,
|
|
65
|
+
"width": 26,
|
|
66
|
+
},
|
|
67
|
+
undefined,
|
|
68
|
+
{
|
|
69
|
+
"opacity": 1,
|
|
70
|
+
},
|
|
71
|
+
]
|
|
40
72
|
}
|
|
41
73
|
>
|
|
42
74
|
<View
|