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/InputToolbar.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useMemo } from 'react'
|
|
2
|
-
import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native'
|
|
2
|
+
import { StyleSheet, View, StyleProp, ViewStyle, useColorScheme } from 'react-native'
|
|
3
3
|
|
|
4
|
-
import { Composer, ComposerProps } from './Composer'
|
|
5
|
-
import { Send, SendProps } from './Send'
|
|
6
4
|
import { Actions, ActionsProps } from './Actions'
|
|
7
5
|
import Color from './Color'
|
|
6
|
+
import { Composer, ComposerProps } from './Composer'
|
|
7
|
+
import { Send, SendProps } from './Send'
|
|
8
8
|
import { IMessage } from './types'
|
|
9
9
|
|
|
10
10
|
export interface InputToolbarProps<TMessage extends IMessage> {
|
|
@@ -38,6 +38,8 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
|
|
|
38
38
|
containerStyle,
|
|
39
39
|
} = props
|
|
40
40
|
|
|
41
|
+
const colorScheme = useColorScheme()
|
|
42
|
+
|
|
41
43
|
const actionsFragment = useMemo(() => {
|
|
42
44
|
const props = {
|
|
43
45
|
onPressActionButton,
|
|
@@ -69,18 +71,29 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
|
|
|
69
71
|
)
|
|
70
72
|
}, [renderComposer, props])
|
|
71
73
|
|
|
74
|
+
const sendFragment = useMemo(() => {
|
|
75
|
+
return renderSend?.(props) || <Send {...props} />
|
|
76
|
+
}, [renderSend, props])
|
|
77
|
+
|
|
78
|
+
const accessoryFragment = useMemo(() => {
|
|
79
|
+
if (!renderAccessory)
|
|
80
|
+
return null
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<View style={[styles.accessory, props.accessoryStyle]}>
|
|
84
|
+
{renderAccessory(props)}
|
|
85
|
+
</View>
|
|
86
|
+
)
|
|
87
|
+
}, [renderAccessory, props])
|
|
88
|
+
|
|
72
89
|
return (
|
|
73
|
-
<View style={[styles.container, containerStyle]}>
|
|
90
|
+
<View style={[styles.container, styles[`container_${colorScheme}`], containerStyle]}>
|
|
74
91
|
<View style={[styles.primary, props.primaryStyle]}>
|
|
75
92
|
{actionsFragment}
|
|
76
93
|
{composerFragment}
|
|
77
|
-
{
|
|
94
|
+
{sendFragment}
|
|
78
95
|
</View>
|
|
79
|
-
{
|
|
80
|
-
<View style={[styles.accessory, props.accessoryStyle]}>
|
|
81
|
-
{renderAccessory(props)}
|
|
82
|
-
</View>
|
|
83
|
-
)}
|
|
96
|
+
{accessoryFragment}
|
|
84
97
|
</View>
|
|
85
98
|
)
|
|
86
99
|
}
|
|
@@ -91,6 +104,10 @@ const styles = StyleSheet.create({
|
|
|
91
104
|
borderTopColor: Color.defaultColor,
|
|
92
105
|
backgroundColor: Color.white,
|
|
93
106
|
},
|
|
107
|
+
container_dark: {
|
|
108
|
+
backgroundColor: '#1a1a1a',
|
|
109
|
+
borderTopColor: '#444',
|
|
110
|
+
},
|
|
94
111
|
primary: {
|
|
95
112
|
flexDirection: 'row',
|
|
96
113
|
alignItems: 'flex-end',
|
package/src/LoadEarlier.tsx
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
ActivityIndicator,
|
|
4
4
|
Platform,
|
|
5
5
|
StyleSheet,
|
|
6
6
|
Text,
|
|
7
|
-
TouchableOpacity,
|
|
8
7
|
View,
|
|
9
8
|
StyleProp,
|
|
10
9
|
ViewStyle,
|
|
11
10
|
TextStyle,
|
|
12
11
|
} from 'react-native'
|
|
13
12
|
import Color from './Color'
|
|
13
|
+
import { TouchableOpacity } from './components/TouchableOpacity'
|
|
14
14
|
import stylesCommon from './styles'
|
|
15
15
|
|
|
16
16
|
const styles = StyleSheet.create({
|
|
@@ -52,7 +52,7 @@ export interface LoadEarlierProps {
|
|
|
52
52
|
onLoadEarlier?(): void
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export
|
|
55
|
+
export const LoadEarlier: React.FC<LoadEarlierProps> = ({
|
|
56
56
|
isLoadingEarlier = false,
|
|
57
57
|
onLoadEarlier = () => {},
|
|
58
58
|
label = 'Load earlier messages',
|
|
@@ -62,7 +62,24 @@ export function LoadEarlier ({
|
|
|
62
62
|
activityIndicatorColor = 'white',
|
|
63
63
|
activityIndicatorSize = 'small',
|
|
64
64
|
activityIndicatorStyle,
|
|
65
|
-
}
|
|
65
|
+
}) => {
|
|
66
|
+
const loadingContent = useMemo(() => (
|
|
67
|
+
<View>
|
|
68
|
+
<Text style={[styles.text, textStyle, { opacity: 0 }]}>
|
|
69
|
+
{label}
|
|
70
|
+
</Text>
|
|
71
|
+
<ActivityIndicator
|
|
72
|
+
color={activityIndicatorColor!}
|
|
73
|
+
size={activityIndicatorSize!}
|
|
74
|
+
style={[styles.activityIndicator, activityIndicatorStyle]}
|
|
75
|
+
/>
|
|
76
|
+
</View>
|
|
77
|
+
), [label, textStyle, activityIndicatorColor, activityIndicatorSize, activityIndicatorStyle])
|
|
78
|
+
|
|
79
|
+
const labelContent = useMemo(() => (
|
|
80
|
+
<Text style={[styles.text, textStyle]}>{label}</Text>
|
|
81
|
+
), [label, textStyle])
|
|
82
|
+
|
|
66
83
|
return (
|
|
67
84
|
<TouchableOpacity
|
|
68
85
|
style={[styles.container, containerStyle]}
|
|
@@ -71,22 +88,7 @@ export function LoadEarlier ({
|
|
|
71
88
|
accessibilityRole='button'
|
|
72
89
|
>
|
|
73
90
|
<View style={[stylesCommon.centerItems, styles.wrapper, wrapperStyle]}>
|
|
74
|
-
{isLoadingEarlier
|
|
75
|
-
? (
|
|
76
|
-
<View>
|
|
77
|
-
<Text style={[styles.text, textStyle, { opacity: 0 }]}>
|
|
78
|
-
{label}
|
|
79
|
-
</Text>
|
|
80
|
-
<ActivityIndicator
|
|
81
|
-
color={activityIndicatorColor!}
|
|
82
|
-
size={activityIndicatorSize!}
|
|
83
|
-
style={[styles.activityIndicator, activityIndicatorStyle]}
|
|
84
|
-
/>
|
|
85
|
-
</View>
|
|
86
|
-
)
|
|
87
|
-
: (
|
|
88
|
-
<Text style={[styles.text, textStyle]}>{label}</Text>
|
|
89
|
-
)}
|
|
91
|
+
{isLoadingEarlier ? loadingContent : labelContent}
|
|
90
92
|
</View>
|
|
91
93
|
</TouchableOpacity>
|
|
92
94
|
)
|
package/src/Message/index.tsx
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import React, { memo, useCallback } from 'react'
|
|
2
2
|
import { View } from 'react-native'
|
|
3
|
-
import isEqual from 'lodash.isequal'
|
|
4
3
|
|
|
5
4
|
import { Avatar } from '../Avatar'
|
|
6
5
|
import Bubble from '../Bubble'
|
|
7
6
|
import { SystemMessage } from '../SystemMessage'
|
|
8
7
|
|
|
9
|
-
import { isSameUser } from '../utils'
|
|
10
8
|
import { IMessage } from '../types'
|
|
11
|
-
import {
|
|
9
|
+
import { isSameUser } from '../utils'
|
|
12
10
|
import styles from './styles'
|
|
11
|
+
import { MessageProps } from './types'
|
|
13
12
|
|
|
14
13
|
export * from './types'
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
const Message: React.FC<MessageProps<IMessage>> = (props: MessageProps<IMessage>) => {
|
|
17
16
|
const {
|
|
18
17
|
currentMessage,
|
|
19
18
|
renderBubble: renderBubbleProp,
|
|
@@ -113,17 +112,4 @@ let Message: React.FC<MessageProps<IMessage>> = (props: MessageProps<IMessage>)
|
|
|
113
112
|
)
|
|
114
113
|
}
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
const shouldUpdate =
|
|
118
|
-
props.shouldUpdateMessage?.(props, nextProps) ||
|
|
119
|
-
!isEqual(props.currentMessage!, nextProps.currentMessage!) ||
|
|
120
|
-
!isEqual(props.previousMessage, nextProps.previousMessage) ||
|
|
121
|
-
!isEqual(props.nextMessage, nextProps.nextMessage)
|
|
122
|
-
|
|
123
|
-
if (shouldUpdate)
|
|
124
|
-
return false
|
|
125
|
-
|
|
126
|
-
return true
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
export default Message
|
|
115
|
+
export default memo(Message)
|
package/src/Message/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ViewStyle, LayoutChangeEvent } from 'react-native'
|
|
2
2
|
import { AvatarProps } from '../Avatar'
|
|
3
|
-
import {
|
|
3
|
+
import { BubbleProps } from '../Bubble'
|
|
4
4
|
import { DayProps } from '../Day'
|
|
5
|
+
import { SystemMessageProps } from '../SystemMessage'
|
|
5
6
|
import { IMessage, User, LeftRightStyle } from '../types'
|
|
6
|
-
import { BubbleProps } from '../Bubble'
|
|
7
7
|
|
|
8
8
|
export interface MessageProps<TMessage extends IMessage> {
|
|
9
9
|
showUserAvatar?: boolean
|
package/src/MessageAudio.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 MessageAudio () {
|
|
6
|
-
|
|
7
|
-
<View style={
|
|
8
|
-
<Text style={
|
|
16
|
+
const content = useMemo(() => (
|
|
17
|
+
<View style={styles.container}>
|
|
18
|
+
<Text style={styles.text}>
|
|
9
19
|
{'Audio is not implemented by GiftedChat.'}
|
|
10
20
|
</Text>
|
|
11
|
-
<Text style={
|
|
21
|
+
<Text style={styles.text}>
|
|
12
22
|
{'\nYou need to provide your own implementation by using renderMessageAudio prop.'}
|
|
13
23
|
</Text>
|
|
14
24
|
</View>
|
|
15
|
-
)
|
|
25
|
+
), [])
|
|
26
|
+
|
|
27
|
+
return content
|
|
16
28
|
}
|
|
@@ -2,12 +2,12 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
2
2
|
import { LayoutChangeEvent } from 'react-native'
|
|
3
3
|
import Animated, { interpolate, useAnimatedStyle, useDerivedValue, useSharedValue, useAnimatedReaction, withTiming, runOnJS } from 'react-native-reanimated'
|
|
4
4
|
import { Day } from '../../../Day'
|
|
5
|
+
import stylesCommon from '../../../styles'
|
|
5
6
|
import { isSameDay } from '../../../utils'
|
|
6
7
|
import { useAbsoluteScrolledPositionToBottomOfDay, useRelativeScrolledPositionToBottomOfDay } from '../Item'
|
|
7
|
-
import { DayAnimatedProps } from './types'
|
|
8
8
|
|
|
9
|
-
import stylesCommon from '../../../styles'
|
|
10
9
|
import styles from './styles'
|
|
10
|
+
import { DayAnimatedProps } from './types'
|
|
11
11
|
|
|
12
12
|
export * from './types'
|
|
13
13
|
|
|
@@ -114,6 +114,19 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
|
|
|
114
114
|
isLoadingEarlierAnim.value = isLoadingEarlier
|
|
115
115
|
}, [isLoadingEarlierAnim, isLoadingEarlier])
|
|
116
116
|
|
|
117
|
+
const dayContent = useMemo(() => {
|
|
118
|
+
if (!createdAt)
|
|
119
|
+
return null
|
|
120
|
+
|
|
121
|
+
return renderDay
|
|
122
|
+
? renderDay({ ...rest, createdAt })
|
|
123
|
+
: <Day
|
|
124
|
+
{...rest}
|
|
125
|
+
containerStyle={[styles.dayAnimatedDayContainerStyle, rest.containerStyle]}
|
|
126
|
+
createdAt={createdAt}
|
|
127
|
+
/>
|
|
128
|
+
}, [createdAt, renderDay, rest])
|
|
129
|
+
|
|
117
130
|
if (!createdAt)
|
|
118
131
|
return null
|
|
119
132
|
|
|
@@ -126,15 +139,7 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
|
|
|
126
139
|
style={contentStyle}
|
|
127
140
|
pointerEvents='none'
|
|
128
141
|
>
|
|
129
|
-
{
|
|
130
|
-
renderDay
|
|
131
|
-
? renderDay({ ...rest, createdAt })
|
|
132
|
-
: <Day
|
|
133
|
-
{...rest}
|
|
134
|
-
containerStyle={[styles.dayAnimatedDayContainerStyle, rest.containerStyle]}
|
|
135
|
-
createdAt={createdAt}
|
|
136
|
-
/>
|
|
137
|
-
}
|
|
142
|
+
{dayContent}
|
|
138
143
|
</Animated.View>
|
|
139
144
|
</Animated.View>
|
|
140
145
|
)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { forwardRef, useCallback, useMemo } from 'react'
|
|
2
2
|
import { LayoutChangeEvent, View } from 'react-native'
|
|
3
|
-
import { IMessage } from '../../../types'
|
|
4
|
-
import Message, { MessageProps } from '../../../Message'
|
|
5
3
|
import Animated, { interpolate, useAnimatedStyle, useDerivedValue, useSharedValue } from 'react-native-reanimated'
|
|
6
|
-
import { DaysPositions } from '../../types'
|
|
7
4
|
import { Day } from '../../../Day'
|
|
5
|
+
import Message, { MessageProps } from '../../../Message'
|
|
6
|
+
import { IMessage } from '../../../types'
|
|
8
7
|
import { isSameDay } from '../../../utils'
|
|
8
|
+
import { DaysPositions } from '../../types'
|
|
9
9
|
import { ItemProps } from './types'
|
|
10
10
|
|
|
11
11
|
export * from './types'
|
|
@@ -33,7 +33,13 @@ export const useRelativeScrolledPositionToBottomOfDay = (
|
|
|
33
33
|
const absoluteScrolledPositionToBottomOfDay = useAbsoluteScrolledPositionToBottomOfDay(listHeight, scrolledY, containerHeight, dayBottomMargin, dayTopOffset)
|
|
34
34
|
|
|
35
35
|
// sorted array of days positions by y
|
|
36
|
-
const daysPositionsArray = useDerivedValue(() =>
|
|
36
|
+
const daysPositionsArray = useDerivedValue(() => {
|
|
37
|
+
return Object.values(daysPositions.value).sort((a, b) => {
|
|
38
|
+
'worklet'
|
|
39
|
+
|
|
40
|
+
return a.y - b.y
|
|
41
|
+
})
|
|
42
|
+
})
|
|
37
43
|
|
|
38
44
|
// find current day position by scrolled position
|
|
39
45
|
const currentDayPosition = useDerivedValue(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MessageContainerProps, DaysPositions } from '../../types'
|
|
2
1
|
import { IMessage } from '../../../types'
|
|
2
|
+
import { MessageContainerProps, DaysPositions } from '../../types'
|
|
3
3
|
|
|
4
4
|
export interface ItemProps<TMessage extends IMessage> extends MessageContainerProps<TMessage> {
|
|
5
5
|
currentMessage: TMessage
|
|
@@ -6,28 +6,28 @@ import {
|
|
|
6
6
|
Platform,
|
|
7
7
|
LayoutChangeEvent,
|
|
8
8
|
ListRenderItemInfo,
|
|
9
|
-
FlatList,
|
|
10
9
|
CellRendererProps,
|
|
11
10
|
} from 'react-native'
|
|
11
|
+
import { FlatList } from 'react-native-gesture-handler'
|
|
12
12
|
import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
|
|
13
|
-
import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes'
|
|
14
|
-
import DayAnimated from './components/DayAnimated'
|
|
15
|
-
import Item from './components/Item'
|
|
16
|
-
|
|
17
13
|
import { LoadEarlier } from '../LoadEarlier'
|
|
14
|
+
import { warning } from '../logging'
|
|
15
|
+
import { ReanimatedScrollEvent } from '../reanimatedCompat'
|
|
16
|
+
|
|
17
|
+
import stylesCommon from '../styles'
|
|
18
18
|
import { IMessage } from '../types'
|
|
19
19
|
import TypingIndicator from '../TypingIndicator'
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
20
|
+
import { isSameDay, useCallbackThrottled } from '../utils'
|
|
21
|
+
import DayAnimated from './components/DayAnimated'
|
|
22
22
|
|
|
23
|
-
import
|
|
24
|
-
import
|
|
23
|
+
import Item from './components/Item'
|
|
24
|
+
import { ItemProps } from './components/Item/types'
|
|
25
25
|
import styles from './styles'
|
|
26
|
-
import {
|
|
26
|
+
import { MessageContainerProps, DaysPositions } from './types'
|
|
27
27
|
|
|
28
28
|
export * from './types'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList) as React.ComponentType<any>
|
|
32
32
|
|
|
33
33
|
function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageContainerProps<TMessage>) {
|
|
@@ -39,9 +39,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
39
39
|
onLoadEarlier,
|
|
40
40
|
inverted = true,
|
|
41
41
|
loadEarlier = false,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
extraData = null,
|
|
42
|
+
listProps,
|
|
43
|
+
extraData,
|
|
45
44
|
isScrollToBottomEnabled = false,
|
|
46
45
|
scrollToBottomOffset = 200,
|
|
47
46
|
alignTop = false,
|
|
@@ -73,8 +72,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
73
72
|
if (renderTypingIndicatorProp)
|
|
74
73
|
return renderTypingIndicatorProp()
|
|
75
74
|
|
|
76
|
-
return <TypingIndicator isTyping={isTyping} />
|
|
77
|
-
}, [isTyping, renderTypingIndicatorProp])
|
|
75
|
+
return <TypingIndicator isTyping={isTyping} style={props.typingIndicatorStyle} />
|
|
76
|
+
}, [isTyping, renderTypingIndicatorProp, props.typingIndicatorStyle])
|
|
78
77
|
|
|
79
78
|
const ListFooterComponent = useMemo(() => {
|
|
80
79
|
if (renderFooterProp)
|
|
@@ -151,6 +150,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
151
150
|
changeScrollToBottomVisibility(false)
|
|
152
151
|
}, [handleOnScrollProp, inverted, scrollToBottomOffset, changeScrollToBottomVisibility, isScrollingDown, lastScrolledY])
|
|
153
152
|
|
|
153
|
+
const restProps = useMemo(() => {
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
155
|
+
const { messages: _, ...rest } = props
|
|
156
|
+
return rest
|
|
157
|
+
}, [props])
|
|
158
|
+
|
|
154
159
|
const renderItem = useCallback(({ item, index }: ListRenderItemInfo<unknown>): React.ReactElement | null => {
|
|
155
160
|
const messageItem = item as TMessage
|
|
156
161
|
|
|
@@ -167,8 +172,6 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
167
172
|
messageItem.user = { _id: 0 }
|
|
168
173
|
}
|
|
169
174
|
|
|
170
|
-
const { messages, ...restProps } = props
|
|
171
|
-
|
|
172
175
|
if (messages && user) {
|
|
173
176
|
const previousMessage =
|
|
174
177
|
(inverted ? messages[index + 1] : messages[index - 1]) || {}
|
|
@@ -192,22 +195,29 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
return null
|
|
195
|
-
}, [
|
|
198
|
+
}, [messages, restProps, inverted, scrolledY, daysPositions, listHeight, user])
|
|
199
|
+
|
|
200
|
+
const emptyContent = useMemo(() => {
|
|
201
|
+
if (!renderChatEmptyProp)
|
|
202
|
+
return null
|
|
203
|
+
|
|
204
|
+
return renderChatEmptyProp()
|
|
205
|
+
}, [renderChatEmptyProp])
|
|
196
206
|
|
|
197
207
|
const renderChatEmpty = useCallback(() => {
|
|
198
208
|
if (renderChatEmptyProp)
|
|
199
209
|
return inverted
|
|
200
210
|
? (
|
|
201
|
-
|
|
211
|
+
emptyContent
|
|
202
212
|
)
|
|
203
213
|
: (
|
|
204
214
|
<View style={[stylesCommon.fill, styles.emptyChatContainer]}>
|
|
205
|
-
{
|
|
215
|
+
{emptyContent}
|
|
206
216
|
</View>
|
|
207
217
|
)
|
|
208
218
|
|
|
209
219
|
return <View style={stylesCommon.fill} />
|
|
210
|
-
}, [inverted, renderChatEmptyProp])
|
|
220
|
+
}, [inverted, renderChatEmptyProp, emptyContent])
|
|
211
221
|
|
|
212
222
|
const ListHeaderComponent = useMemo(() => {
|
|
213
223
|
const content = renderLoadEarlier()
|
|
@@ -227,6 +237,25 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
227
237
|
return <Text>{'V'}</Text>
|
|
228
238
|
}, [scrollToBottomComponentProp])
|
|
229
239
|
|
|
240
|
+
const handleScrollToBottomPress = useCallback(() => {
|
|
241
|
+
doScrollToBottom()
|
|
242
|
+
}, [doScrollToBottom])
|
|
243
|
+
|
|
244
|
+
const scrollToBottomContent = useMemo(() => {
|
|
245
|
+
return (
|
|
246
|
+
<Animated.View
|
|
247
|
+
style={[
|
|
248
|
+
stylesCommon.centerItems,
|
|
249
|
+
styles.scrollToBottomContent,
|
|
250
|
+
scrollToBottomStyle,
|
|
251
|
+
scrollToBottomStyleAnim,
|
|
252
|
+
]}
|
|
253
|
+
>
|
|
254
|
+
{renderScrollBottomComponent()}
|
|
255
|
+
</Animated.View>
|
|
256
|
+
)
|
|
257
|
+
}, [scrollToBottomStyle, scrollToBottomStyleAnim, renderScrollBottomComponent])
|
|
258
|
+
|
|
230
259
|
const ScrollToBottomWrapper = useCallback(() => {
|
|
231
260
|
if (!isScrollToBottomEnabled)
|
|
232
261
|
return null
|
|
@@ -237,21 +266,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
237
266
|
return (
|
|
238
267
|
<Pressable
|
|
239
268
|
style={styles.scrollToBottom}
|
|
240
|
-
onPress={
|
|
269
|
+
onPress={handleScrollToBottomPress}
|
|
241
270
|
>
|
|
242
|
-
|
|
243
|
-
style={[
|
|
244
|
-
stylesCommon.centerItems,
|
|
245
|
-
styles.scrollToBottomContent,
|
|
246
|
-
scrollToBottomStyle,
|
|
247
|
-
scrollToBottomStyleAnim,
|
|
248
|
-
]}
|
|
249
|
-
>
|
|
250
|
-
{renderScrollBottomComponent()}
|
|
251
|
-
</Animated.View>
|
|
271
|
+
{scrollToBottomContent}
|
|
252
272
|
</Pressable>
|
|
253
273
|
)
|
|
254
|
-
}, [
|
|
274
|
+
}, [isScrollToBottomEnabled, isScrollToBottomVisible, handleScrollToBottomPress, scrollToBottomContent])
|
|
255
275
|
|
|
256
276
|
const onLayoutList = useCallback((event: LayoutChangeEvent) => {
|
|
257
277
|
listHeight.value = event.nativeEvent.layout.height
|
|
@@ -265,8 +285,8 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
265
285
|
doScrollToBottom(false)
|
|
266
286
|
}, 500)
|
|
267
287
|
|
|
268
|
-
|
|
269
|
-
}, [inverted, messages, doScrollToBottom, listHeight,
|
|
288
|
+
listProps?.onLayout?.(event)
|
|
289
|
+
}, [inverted, messages, doScrollToBottom, listHeight, listProps, isScrollToBottomEnabled])
|
|
270
290
|
|
|
271
291
|
const onEndReached = useCallback(() => {
|
|
272
292
|
if (
|
|
@@ -378,7 +398,6 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
378
398
|
inverted={inverted}
|
|
379
399
|
automaticallyAdjustContentInsets={false}
|
|
380
400
|
style={stylesCommon.fill}
|
|
381
|
-
{...invertibleScrollViewProps}
|
|
382
401
|
ListEmptyComponent={renderChatEmpty}
|
|
383
402
|
ListFooterComponent={
|
|
384
403
|
inverted ? ListHeaderComponent : ListFooterComponent
|
|
@@ -390,7 +409,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
|
|
|
390
409
|
scrollEventThrottle={1}
|
|
391
410
|
onEndReached={onEndReached}
|
|
392
411
|
onEndReachedThreshold={0.1}
|
|
393
|
-
{...
|
|
412
|
+
{...listProps}
|
|
394
413
|
onLayout={onLayoutList}
|
|
395
414
|
CellRendererComponent={renderCell}
|
|
396
415
|
/>
|
|
@@ -3,44 +3,69 @@ 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
9
|
import { LoadEarlierProps } from '../LoadEarlier'
|
|
10
10
|
import { MessageProps } from '../Message'
|
|
11
|
+
import { ReanimatedScrollEvent } from '../reanimatedCompat'
|
|
11
12
|
import { User, IMessage, Reply, DayProps } from '../types'
|
|
12
|
-
import {
|
|
13
|
+
import { TypingIndicatorProps } from '../TypingIndicator/types'
|
|
13
14
|
|
|
14
|
-
export type
|
|
15
|
+
export type ListProps<TMessage extends IMessage = IMessage> = Partial<FlatListProps<TMessage>>
|
|
15
16
|
|
|
16
17
|
export type AnimatedList<TMessage> = FlatList<TMessage>
|
|
17
18
|
|
|
18
|
-
export interface MessageContainerProps<TMessage extends IMessage = IMessage>
|
|
19
|
+
export interface MessageContainerProps<TMessage extends IMessage = IMessage>
|
|
20
|
+
extends Omit<TypingIndicatorProps, 'style'> {
|
|
21
|
+
/** Ref for the FlatList message container */
|
|
19
22
|
forwardRef?: RefObject<AnimatedList<TMessage>>
|
|
23
|
+
/** Messages to display */
|
|
20
24
|
messages?: TMessage[]
|
|
21
|
-
|
|
25
|
+
/** User sending the messages: { _id, name, avatar } */
|
|
22
26
|
user?: User
|
|
23
|
-
|
|
27
|
+
/** Additional props for FlatList */
|
|
28
|
+
listProps?: ListProps<TMessage>
|
|
29
|
+
/** Reverses display order of messages; default is true */
|
|
24
30
|
inverted?: boolean
|
|
31
|
+
/** Enables the "Load earlier messages" button */
|
|
25
32
|
loadEarlier?: boolean
|
|
33
|
+
/** Controls whether or not the message bubbles appear at the top of the chat */
|
|
26
34
|
alignTop?: boolean
|
|
35
|
+
/** Enables the isScrollToBottomEnabled Component */
|
|
27
36
|
isScrollToBottomEnabled?: boolean
|
|
37
|
+
/** Scroll to bottom wrapper style */
|
|
28
38
|
scrollToBottomStyle?: StyleProp<ViewStyle>
|
|
29
|
-
|
|
39
|
+
/** This can be used to pass unknown data which needs to be re-rendered */
|
|
30
40
|
extraData?: object
|
|
41
|
+
/** Distance from bottom before showing scroll to bottom button */
|
|
31
42
|
scrollToBottomOffset?: number
|
|
43
|
+
/** Custom component to render when messages are empty */
|
|
32
44
|
renderChatEmpty?(): React.ReactNode
|
|
45
|
+
/** Custom footer component on the ListView, e.g. 'User is typing...' */
|
|
33
46
|
renderFooter?(props: MessageContainerProps<TMessage>): React.ReactNode
|
|
47
|
+
/** Custom message container */
|
|
34
48
|
renderMessage?(props: MessageProps<TMessage>): React.ReactElement
|
|
49
|
+
/** Custom day above a message */
|
|
35
50
|
renderDay?(props: DayProps): React.ReactNode
|
|
51
|
+
/** Custom "Load earlier messages" button */
|
|
36
52
|
renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode
|
|
53
|
+
/** Custom typing indicator */
|
|
37
54
|
renderTypingIndicator?(): React.ReactNode
|
|
55
|
+
/** Scroll to bottom custom component */
|
|
38
56
|
scrollToBottomComponent?(): React.ReactNode
|
|
57
|
+
/** Callback when loading earlier messages */
|
|
39
58
|
onLoadEarlier?(): void
|
|
59
|
+
/** Callback when quick reply is sent */
|
|
40
60
|
onQuickReply?(replies: Reply[]): void
|
|
61
|
+
/** Infinite scroll up when reach the top of messages container, automatically call onLoadEarlier function if exist */
|
|
41
62
|
infiniteScroll?: boolean
|
|
63
|
+
/** Display an ActivityIndicator when loading earlier messages */
|
|
42
64
|
isLoadingEarlier?: boolean
|
|
65
|
+
/** Custom scroll event handler */
|
|
43
66
|
handleOnScroll?(event: ReanimatedScrollEvent): void
|
|
67
|
+
/** Style for TypingIndicator component */
|
|
68
|
+
typingIndicatorStyle?: StyleProp<ViewStyle>
|
|
44
69
|
}
|
|
45
70
|
|
|
46
71
|
export interface State {
|