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
package/src/GiftedChat/index.tsx
CHANGED
|
@@ -7,17 +7,27 @@ import React, {
|
|
|
7
7
|
useCallback,
|
|
8
8
|
RefObject,
|
|
9
9
|
} from 'react'
|
|
10
|
+
import {
|
|
11
|
+
TextInput,
|
|
12
|
+
View,
|
|
13
|
+
LayoutChangeEvent,
|
|
14
|
+
} from 'react-native'
|
|
10
15
|
import {
|
|
11
16
|
ActionSheetProvider,
|
|
12
17
|
ActionSheetProviderRef,
|
|
13
18
|
} from '@expo/react-native-action-sheet'
|
|
14
19
|
import dayjs from 'dayjs'
|
|
15
20
|
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
22
|
+
import { KeyboardProvider, useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'
|
|
23
|
+
import Animated, {
|
|
24
|
+
useAnimatedStyle,
|
|
25
|
+
useAnimatedReaction,
|
|
26
|
+
useSharedValue,
|
|
27
|
+
withTiming,
|
|
28
|
+
runOnJS,
|
|
29
|
+
} from 'react-native-reanimated'
|
|
30
|
+
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
|
21
31
|
import { Actions } from '../Actions'
|
|
22
32
|
import { Avatar } from '../Avatar'
|
|
23
33
|
import Bubble from '../Bubble'
|
|
@@ -27,30 +37,22 @@ import { Day } from '../Day'
|
|
|
27
37
|
import { GiftedAvatar } from '../GiftedAvatar'
|
|
28
38
|
import { GiftedChatContext } from '../GiftedChatContext'
|
|
29
39
|
import { InputToolbar } from '../InputToolbar'
|
|
30
|
-
import {
|
|
40
|
+
import { LoadEarlierMessages } from '../LoadEarlierMessages'
|
|
31
41
|
import Message from '../Message'
|
|
32
42
|
import MessageContainer, { AnimatedList } from '../MessageContainer'
|
|
33
43
|
import { MessageImage } from '../MessageImage'
|
|
34
44
|
import { MessageText } from '../MessageText'
|
|
35
|
-
import {
|
|
36
|
-
IMessage,
|
|
37
|
-
} from '../types'
|
|
38
45
|
import { Send } from '../Send'
|
|
46
|
+
import stylesCommon from '../styles'
|
|
39
47
|
import { SystemMessage } from '../SystemMessage'
|
|
40
48
|
import { Time } from '../Time'
|
|
41
|
-
import * as utils from '../utils'
|
|
42
|
-
import Animated, {
|
|
43
|
-
useAnimatedStyle,
|
|
44
|
-
useAnimatedReaction,
|
|
45
|
-
useSharedValue,
|
|
46
|
-
withTiming,
|
|
47
|
-
runOnJS,
|
|
48
|
-
} from 'react-native-reanimated'
|
|
49
|
-
import { KeyboardProvider, useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'
|
|
50
|
-
import { GiftedChatProps } from './types'
|
|
51
49
|
|
|
52
|
-
import
|
|
50
|
+
import {
|
|
51
|
+
IMessage,
|
|
52
|
+
} from '../types'
|
|
53
|
+
import * as utils from '../utils'
|
|
53
54
|
import styles from './styles'
|
|
55
|
+
import { GiftedChatProps } from './types'
|
|
54
56
|
|
|
55
57
|
dayjs.extend(localizedFormat)
|
|
56
58
|
|
|
@@ -75,14 +77,13 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
75
77
|
textInputProps,
|
|
76
78
|
renderChatFooter,
|
|
77
79
|
renderInputToolbar,
|
|
78
|
-
|
|
80
|
+
keyboardBottomOffset = 0,
|
|
79
81
|
focusOnInputWhenOpeningKeyboard = true,
|
|
80
82
|
onInputTextChanged,
|
|
81
83
|
inverted = true,
|
|
82
84
|
minComposerHeight = MIN_COMPOSER_HEIGHT,
|
|
83
85
|
maxComposerHeight = MAX_COMPOSER_HEIGHT,
|
|
84
86
|
isKeyboardInternallyHandled = true,
|
|
85
|
-
disableKeyboardController = false,
|
|
86
87
|
} = props
|
|
87
88
|
|
|
88
89
|
const actionSheetRef = useRef<ActionSheetProviderRef>(null)
|
|
@@ -108,23 +109,24 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
108
109
|
// Always call the hook, but conditionally use its data
|
|
109
110
|
const keyboardControllerData = useReanimatedKeyboardAnimation()
|
|
110
111
|
|
|
111
|
-
// Create a mock keyboard object when
|
|
112
|
+
// Create a mock keyboard object when keyboard is not internally handled
|
|
112
113
|
const keyboard = useMemo(() => {
|
|
113
|
-
if (
|
|
114
|
+
if (!isKeyboardInternallyHandled)
|
|
114
115
|
return { height: { value: 0 } }
|
|
116
|
+
|
|
115
117
|
return keyboardControllerData
|
|
116
|
-
}, [
|
|
118
|
+
}, [isKeyboardInternallyHandled, keyboardControllerData])
|
|
117
119
|
|
|
118
120
|
const trackingKeyboardMovement = useSharedValue(false)
|
|
119
|
-
const
|
|
121
|
+
const keyboardBottomOffsetAnim = useSharedValue(0)
|
|
120
122
|
|
|
121
123
|
const contentStyleAnim = useAnimatedStyle(
|
|
122
124
|
() => ({
|
|
123
125
|
transform: [
|
|
124
|
-
{ translateY: keyboard.height.value
|
|
126
|
+
{ translateY: keyboard.height.value + keyboardBottomOffsetAnim.value },
|
|
125
127
|
],
|
|
126
128
|
}),
|
|
127
|
-
[keyboard,
|
|
129
|
+
[keyboard, keyboardBottomOffsetAnim]
|
|
128
130
|
)
|
|
129
131
|
|
|
130
132
|
const getTextFromProp = useCallback(
|
|
@@ -278,6 +280,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
278
280
|
|
|
279
281
|
const onInitialLayoutViewLayout = useCallback(
|
|
280
282
|
(e: LayoutChangeEvent) => {
|
|
283
|
+
console.log('onInitialLayoutViewLayout', e.nativeEvent.layout.height)
|
|
281
284
|
if (isInitialized)
|
|
282
285
|
return
|
|
283
286
|
|
|
@@ -349,23 +352,23 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
349
352
|
setText(props.text)
|
|
350
353
|
}, [props.text])
|
|
351
354
|
|
|
352
|
-
// Only set up keyboard animation when keyboard
|
|
355
|
+
// Only set up keyboard animation when keyboard is internally handled
|
|
353
356
|
useAnimatedReaction(
|
|
354
|
-
() =>
|
|
357
|
+
() => isKeyboardInternallyHandled ? keyboard.height.value : 0,
|
|
355
358
|
(value, prevValue) => {
|
|
356
|
-
// Skip keyboard handling when
|
|
357
|
-
if (
|
|
359
|
+
// Skip keyboard handling when not internally handled
|
|
360
|
+
if (!isKeyboardInternallyHandled)
|
|
358
361
|
return
|
|
359
362
|
|
|
360
363
|
if (prevValue !== null && value !== prevValue) {
|
|
361
|
-
const isKeyboardMovingUp = value
|
|
364
|
+
const isKeyboardMovingUp = value < prevValue
|
|
362
365
|
if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
|
|
363
366
|
trackingKeyboardMovement.value = isKeyboardMovingUp
|
|
364
|
-
|
|
365
|
-
isKeyboardMovingUp ?
|
|
367
|
+
keyboardBottomOffsetAnim.value = withTiming(
|
|
368
|
+
isKeyboardMovingUp ? keyboardBottomOffset : 0,
|
|
366
369
|
{
|
|
367
|
-
// If `
|
|
368
|
-
duration:
|
|
370
|
+
// If `keyboardBottomOffset` exists, we change the duration to a smaller value to fix the delay in the keyboard animation speed
|
|
371
|
+
duration: keyboardBottomOffset ? 150 : 400,
|
|
369
372
|
}
|
|
370
373
|
)
|
|
371
374
|
|
|
@@ -383,8 +386,8 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
383
386
|
focusOnInputWhenOpeningKeyboard,
|
|
384
387
|
handleTextInputFocusWhenKeyboardHide,
|
|
385
388
|
handleTextInputFocusWhenKeyboardShow,
|
|
386
|
-
|
|
387
|
-
|
|
389
|
+
keyboardBottomOffset,
|
|
390
|
+
isKeyboardInternallyHandled,
|
|
388
391
|
]
|
|
389
392
|
)
|
|
390
393
|
|
|
@@ -398,7 +401,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
398
401
|
>
|
|
399
402
|
{isInitialized
|
|
400
403
|
? (
|
|
401
|
-
<Animated.View style={[stylesCommon.fill,
|
|
404
|
+
<Animated.View style={[stylesCommon.fill, isKeyboardInternallyHandled && contentStyleAnim]}>
|
|
402
405
|
{renderMessages}
|
|
403
406
|
{inputToolbarFragment}
|
|
404
407
|
</Animated.View>
|
|
@@ -413,14 +416,18 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
413
416
|
}
|
|
414
417
|
|
|
415
418
|
function GiftedChatWrapper<TMessage extends IMessage = IMessage> (props: GiftedChatProps<TMessage>) {
|
|
416
|
-
// Don't use KeyboardProvider when keyboard
|
|
417
|
-
if (props.
|
|
419
|
+
// Don't use KeyboardProvider when keyboard is not internally handled
|
|
420
|
+
if (!props.isKeyboardInternallyHandled)
|
|
418
421
|
return <GiftedChat<TMessage> {...props} />
|
|
419
422
|
|
|
420
423
|
return (
|
|
421
|
-
<
|
|
422
|
-
<
|
|
423
|
-
|
|
424
|
+
<GestureHandlerRootView style={styles.fill}>
|
|
425
|
+
<SafeAreaProvider>
|
|
426
|
+
<KeyboardProvider>
|
|
427
|
+
<GiftedChat<TMessage> {...props} />
|
|
428
|
+
</KeyboardProvider>
|
|
429
|
+
</SafeAreaProvider>
|
|
430
|
+
</GestureHandlerRootView>
|
|
424
431
|
)
|
|
425
432
|
}
|
|
426
433
|
|
|
@@ -463,7 +470,7 @@ export {
|
|
|
463
470
|
Composer,
|
|
464
471
|
Day,
|
|
465
472
|
InputToolbar,
|
|
466
|
-
|
|
473
|
+
LoadEarlierMessages,
|
|
467
474
|
Message,
|
|
468
475
|
MessageContainer,
|
|
469
476
|
Send,
|
package/src/GiftedChat/styles.ts
CHANGED
package/src/GiftedChat/types.ts
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import React, { RefObject } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
ActionSheetOptions,
|
|
4
|
-
} from '@expo/react-native-action-sheet'
|
|
5
2
|
import {
|
|
6
3
|
TextInput,
|
|
7
4
|
StyleProp,
|
|
8
5
|
TextStyle,
|
|
9
6
|
ViewStyle,
|
|
10
7
|
} from 'react-native'
|
|
11
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ActionSheetOptions,
|
|
10
|
+
} from '@expo/react-native-action-sheet'
|
|
12
11
|
import { ActionsProps } from '../Actions'
|
|
13
12
|
import { AvatarProps } from '../Avatar'
|
|
13
|
+
import { BubbleProps } from '../Bubble'
|
|
14
14
|
import { ComposerProps } from '../Composer'
|
|
15
15
|
import { InputToolbarProps } from '../InputToolbar'
|
|
16
16
|
import { MessageProps } from '../Message'
|
|
17
|
+
import { AnimatedList, MessageContainerProps } from '../MessageContainer'
|
|
17
18
|
import { MessageImageProps } from '../MessageImage'
|
|
18
19
|
import { MessageTextProps } from '../MessageText'
|
|
20
|
+
import { QuickRepliesProps } from '../QuickReplies'
|
|
21
|
+
import { SendProps } from '../Send'
|
|
22
|
+
import { SystemMessageProps } from '../SystemMessage'
|
|
23
|
+
import { TimeProps } from '../Time'
|
|
19
24
|
import {
|
|
20
25
|
IMessage,
|
|
21
26
|
LeftRightStyle,
|
|
@@ -23,12 +28,6 @@ import {
|
|
|
23
28
|
MessageVideoProps,
|
|
24
29
|
User,
|
|
25
30
|
} from '../types'
|
|
26
|
-
import { QuickRepliesProps } from '../QuickReplies'
|
|
27
|
-
import { SendProps } from '../Send'
|
|
28
|
-
import { SystemMessageProps } from '../SystemMessage'
|
|
29
|
-
import { TimeProps } from '../Time'
|
|
30
|
-
import { AnimatedList, MessageContainerProps } from '../MessageContainer'
|
|
31
|
-
import { BubbleProps } from '../Bubble'
|
|
32
31
|
|
|
33
32
|
export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessageContainerProps<TMessage>> {
|
|
34
33
|
/* Message container ref */
|
|
@@ -54,8 +53,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
54
53
|
dateFormatCalendar?: object
|
|
55
54
|
/* Determine whether to handle keyboard awareness inside the plugin. If you have your own keyboard handling outside the plugin set this to false; default is `true` */
|
|
56
55
|
isKeyboardInternallyHandled?: boolean
|
|
57
|
-
/* Completely disable react-native-keyboard-controller. Useful when using react-native-navigation or other conflicting keyboard libraries; default is `false` */
|
|
58
|
-
disableKeyboardController?: boolean
|
|
59
56
|
/* Whether to render an avatar for the current user; default is false, only show avatars for other users */
|
|
60
57
|
showUserAvatar?: boolean
|
|
61
58
|
/* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
|
|
@@ -64,10 +61,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
64
61
|
renderAvatarOnTop?: boolean
|
|
65
62
|
/* Extra props to be passed to the <Image> component created by the default renderMessageImage */
|
|
66
63
|
imageProps?: MessageImageProps<TMessage>
|
|
67
|
-
/* Extra props to be passed to the MessageImage's Lightbox */
|
|
68
|
-
lightboxProps?: LightboxProps
|
|
69
64
|
/* Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar); default is 0 */
|
|
70
|
-
|
|
65
|
+
keyboardBottomOffset?: number
|
|
71
66
|
/* Focus on <TextInput> automatically when opening the keyboard; default is true */
|
|
72
67
|
focusOnInputWhenOpeningKeyboard?: boolean
|
|
73
68
|
/* Minimum height of the input toolbar; default is 44 */
|
|
@@ -82,8 +77,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
82
77
|
minComposerHeight?: number
|
|
83
78
|
/* composer min Height */
|
|
84
79
|
maxComposerHeight?: number
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
actions?: Array<{ title: string, action: () => void }>
|
|
81
|
+
actionSheetOptionTintColor?: string
|
|
87
82
|
quickReplyStyle?: StyleProp<ViewStyle>
|
|
88
83
|
quickReplyTextStyle?: StyleProp<TextStyle>
|
|
89
84
|
quickReplyContainerStyle?: StyleProp<ViewStyle>
|
|
@@ -148,7 +143,9 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
148
143
|
onPressActionButton?(): void
|
|
149
144
|
/* Callback when the input text changes */
|
|
150
145
|
onInputTextChanged?(text: string): void
|
|
151
|
-
/*
|
|
146
|
+
/* Extra props to be passed to the MessageText component */
|
|
147
|
+
messageTextProps?: Partial<MessageTextProps<TMessage>>
|
|
148
|
+
/* Custom parse patterns for react-native-autolink used to linking message content (like URLs and phone numbers) */
|
|
152
149
|
matchers?: MessageTextProps<TMessage>['matchers']
|
|
153
150
|
renderQuickReplies?(
|
|
154
151
|
quickReplies: QuickRepliesProps<TMessage>,
|
package/src/InputToolbar.tsx
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import React, { useMemo } from 'react'
|
|
2
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> {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
actions?: Array<{ title: string, action: () => void }>
|
|
12
|
+
actionSheetOptionTintColor?: string
|
|
13
13
|
containerStyle?: StyleProp<ViewStyle>
|
|
14
14
|
primaryStyle?: StyleProp<ViewStyle>
|
|
15
15
|
accessoryStyle?: StyleProp<ViewStyle>
|
|
@@ -31,8 +31,8 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
|
|
|
31
31
|
renderComposer,
|
|
32
32
|
renderSend,
|
|
33
33
|
renderAccessory,
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
actions,
|
|
35
|
+
actionSheetOptionTintColor,
|
|
36
36
|
icon,
|
|
37
37
|
wrapperStyle,
|
|
38
38
|
containerStyle,
|
|
@@ -43,8 +43,8 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
|
|
|
43
43
|
const actionsFragment = useMemo(() => {
|
|
44
44
|
const props = {
|
|
45
45
|
onPressActionButton,
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
actions,
|
|
47
|
+
actionSheetOptionTintColor,
|
|
48
48
|
icon,
|
|
49
49
|
wrapperStyle,
|
|
50
50
|
containerStyle,
|
|
@@ -56,8 +56,8 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
|
|
|
56
56
|
}, [
|
|
57
57
|
renderActions,
|
|
58
58
|
onPressActionButton,
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
actions,
|
|
60
|
+
actionSheetOptionTintColor,
|
|
61
61
|
icon,
|
|
62
62
|
wrapperStyle,
|
|
63
63
|
containerStyle,
|
package/src/LoadEarlier.tsx
CHANGED
|
@@ -4,13 +4,13 @@ import {
|
|
|
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({
|
|
@@ -40,7 +40,7 @@ const styles = StyleSheet.create({
|
|
|
40
40
|
},
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
export interface
|
|
43
|
+
export interface LoadEarlierMessagesProps {
|
|
44
44
|
isLoadingEarlier?: boolean
|
|
45
45
|
label?: string
|
|
46
46
|
containerStyle?: StyleProp<ViewStyle>
|
|
@@ -49,12 +49,12 @@ export interface LoadEarlierProps {
|
|
|
49
49
|
activityIndicatorStyle?: StyleProp<ViewStyle>
|
|
50
50
|
activityIndicatorColor?: string
|
|
51
51
|
activityIndicatorSize?: number | 'small' | 'large'
|
|
52
|
-
|
|
52
|
+
onPress: () => void
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export
|
|
55
|
+
export const LoadEarlierMessages: React.FC<LoadEarlierMessagesProps> = ({
|
|
56
56
|
isLoadingEarlier = false,
|
|
57
|
-
|
|
57
|
+
onPress,
|
|
58
58
|
label = 'Load earlier messages',
|
|
59
59
|
containerStyle,
|
|
60
60
|
wrapperStyle,
|
|
@@ -62,7 +62,7 @@ export function LoadEarlier ({
|
|
|
62
62
|
activityIndicatorColor = 'white',
|
|
63
63
|
activityIndicatorSize = 'small',
|
|
64
64
|
activityIndicatorStyle,
|
|
65
|
-
}
|
|
65
|
+
}) => {
|
|
66
66
|
const loadingContent = useMemo(() => (
|
|
67
67
|
<View>
|
|
68
68
|
<Text style={[styles.text, textStyle, { opacity: 0 }]}>
|
|
@@ -83,7 +83,7 @@ export function LoadEarlier ({
|
|
|
83
83
|
return (
|
|
84
84
|
<TouchableOpacity
|
|
85
85
|
style={[styles.container, containerStyle]}
|
|
86
|
-
onPress={
|
|
86
|
+
onPress={onPress}
|
|
87
87
|
disabled={isLoadingEarlier}
|
|
88
88
|
accessibilityRole='button'
|
|
89
89
|
>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
ActivityIndicator,
|
|
4
|
+
Platform,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
Text,
|
|
7
|
+
View,
|
|
8
|
+
StyleProp,
|
|
9
|
+
ViewStyle,
|
|
10
|
+
TextStyle,
|
|
11
|
+
} from 'react-native'
|
|
12
|
+
import Color from './Color'
|
|
13
|
+
import { TouchableOpacity } from './components/TouchableOpacity'
|
|
14
|
+
import stylesCommon from './styles'
|
|
15
|
+
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
container: {
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
marginTop: 5,
|
|
20
|
+
marginBottom: 10,
|
|
21
|
+
},
|
|
22
|
+
wrapper: {
|
|
23
|
+
backgroundColor: Color.defaultColor,
|
|
24
|
+
borderRadius: 15,
|
|
25
|
+
height: 30,
|
|
26
|
+
paddingLeft: 10,
|
|
27
|
+
paddingRight: 10,
|
|
28
|
+
},
|
|
29
|
+
text: {
|
|
30
|
+
backgroundColor: Color.backgroundTransparent,
|
|
31
|
+
color: Color.white,
|
|
32
|
+
fontSize: 12,
|
|
33
|
+
},
|
|
34
|
+
activityIndicator: {
|
|
35
|
+
marginTop: Platform.select({
|
|
36
|
+
ios: -14,
|
|
37
|
+
android: -16,
|
|
38
|
+
default: -15,
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export interface LoadEarlierMessagesProps {
|
|
44
|
+
isAvailable?: boolean
|
|
45
|
+
isLoading?: boolean
|
|
46
|
+
isInfiniteScrollEnabled?: boolean
|
|
47
|
+
label?: string
|
|
48
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
49
|
+
wrapperStyle?: StyleProp<ViewStyle>
|
|
50
|
+
textStyle?: StyleProp<TextStyle>
|
|
51
|
+
activityIndicatorStyle?: StyleProp<ViewStyle>
|
|
52
|
+
activityIndicatorColor?: string
|
|
53
|
+
activityIndicatorSize?: number | 'small' | 'large'
|
|
54
|
+
onPress: () => void
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const LoadEarlierMessages: React.FC<LoadEarlierMessagesProps> = ({
|
|
58
|
+
isLoading = false,
|
|
59
|
+
onPress,
|
|
60
|
+
label = 'Load earlier messages',
|
|
61
|
+
containerStyle,
|
|
62
|
+
wrapperStyle,
|
|
63
|
+
textStyle,
|
|
64
|
+
activityIndicatorColor = 'white',
|
|
65
|
+
activityIndicatorSize = 'small',
|
|
66
|
+
activityIndicatorStyle,
|
|
67
|
+
}) => {
|
|
68
|
+
const loadingContent = useMemo(() => (
|
|
69
|
+
<View>
|
|
70
|
+
<Text style={[styles.text, textStyle, { opacity: 0 }]}>
|
|
71
|
+
{label}
|
|
72
|
+
</Text>
|
|
73
|
+
<ActivityIndicator
|
|
74
|
+
color={activityIndicatorColor!}
|
|
75
|
+
size={activityIndicatorSize!}
|
|
76
|
+
style={[styles.activityIndicator, activityIndicatorStyle]}
|
|
77
|
+
/>
|
|
78
|
+
</View>
|
|
79
|
+
), [label, textStyle, activityIndicatorColor, activityIndicatorSize, activityIndicatorStyle])
|
|
80
|
+
|
|
81
|
+
const labelContent = useMemo(() => (
|
|
82
|
+
<Text style={[styles.text, textStyle]}>{label}</Text>
|
|
83
|
+
), [label, textStyle])
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<TouchableOpacity
|
|
87
|
+
style={[styles.container, containerStyle]}
|
|
88
|
+
onPress={onPress}
|
|
89
|
+
disabled={isLoading}
|
|
90
|
+
accessibilityRole='button'
|
|
91
|
+
>
|
|
92
|
+
<View style={[stylesCommon.centerItems, styles.wrapper, wrapperStyle]}>
|
|
93
|
+
{isLoading ? loadingContent : labelContent}
|
|
94
|
+
</View>
|
|
95
|
+
</TouchableOpacity>
|
|
96
|
+
)
|
|
97
|
+
}
|
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
|
@@ -2,22 +2,22 @@ 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
|
|
|
14
|
-
const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages,
|
|
14
|
+
const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages, isLoading, ...rest }: DayAnimatedProps) => {
|
|
15
15
|
const opacity = useSharedValue(0)
|
|
16
16
|
const fadeOutOpacityTimeoutId = useSharedValue<ReturnType<typeof setTimeout> | undefined>(undefined)
|
|
17
17
|
const containerHeight = useSharedValue(0)
|
|
18
18
|
|
|
19
19
|
const isScrolledOnMount = useSharedValue(false)
|
|
20
|
-
const
|
|
20
|
+
const isLoadingAnim = useSharedValue(isLoading)
|
|
21
21
|
|
|
22
22
|
const daysPositionsArray = useDerivedValue(() => Object.values(daysPositions.value).sort((a, b) => a.y - b.y))
|
|
23
23
|
|
|
@@ -57,11 +57,11 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
|
|
|
57
57
|
const style = useAnimatedStyle(() => ({
|
|
58
58
|
top: interpolate(
|
|
59
59
|
relativeScrolledPositionToBottomOfDay.value,
|
|
60
|
-
[-dayTopOffset, -0.0001, 0,
|
|
61
|
-
[dayTopOffset, dayTopOffset, -containerHeight.value,
|
|
60
|
+
[-dayTopOffset, -0.0001, 0, isLoadingAnim.value ? 0 : containerHeight.value + dayTopOffset],
|
|
61
|
+
[dayTopOffset, dayTopOffset, -containerHeight.value, isLoadingAnim.value ? -containerHeight.value : dayTopOffset],
|
|
62
62
|
'clamp'
|
|
63
63
|
),
|
|
64
|
-
}), [relativeScrolledPositionToBottomOfDay, containerHeight, dayTopOffset,
|
|
64
|
+
}), [relativeScrolledPositionToBottomOfDay, containerHeight, dayTopOffset, isLoadingAnim])
|
|
65
65
|
|
|
66
66
|
const contentStyle = useAnimatedStyle(() => ({
|
|
67
67
|
opacity: opacity.value,
|
|
@@ -111,8 +111,8 @@ const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages
|
|
|
111
111
|
)
|
|
112
112
|
|
|
113
113
|
useEffect(() => {
|
|
114
|
-
|
|
115
|
-
}, [
|
|
114
|
+
isLoadingAnim.value = isLoading
|
|
115
|
+
}, [isLoadingAnim, isLoading])
|
|
116
116
|
|
|
117
117
|
const dayContent = useMemo(() => {
|
|
118
118
|
if (!createdAt)
|
|
@@ -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'
|
|
@@ -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
|