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.
Files changed (43) hide show
  1. package/README.md +68 -27
  2. package/package.json +10 -11
  3. package/src/Actions.tsx +14 -16
  4. package/src/Avatar.tsx +1 -1
  5. package/src/Bubble/index.tsx +13 -10
  6. package/src/Bubble/types.ts +5 -4
  7. package/src/Composer.tsx +1 -1
  8. package/src/Day/index.tsx +3 -3
  9. package/src/GiftedAvatar.tsx +2 -2
  10. package/src/GiftedChat/index.tsx +53 -46
  11. package/src/GiftedChat/styles.ts +3 -0
  12. package/src/GiftedChat/types.ts +15 -18
  13. package/src/InputToolbar.tsx +10 -10
  14. package/src/LoadEarlier.tsx +7 -7
  15. package/src/LoadEarlierMessages.tsx +97 -0
  16. package/src/Message/index.tsx +4 -18
  17. package/src/Message/types.ts +2 -2
  18. package/src/MessageAudio.tsx +1 -1
  19. package/src/MessageContainer/components/DayAnimated/index.tsx +9 -9
  20. package/src/MessageContainer/components/DayAnimated/types.ts +1 -1
  21. package/src/MessageContainer/components/Item/index.tsx +3 -3
  22. package/src/MessageContainer/components/Item/types.ts +1 -1
  23. package/src/MessageContainer/index.tsx +22 -27
  24. package/src/MessageContainer/types.ts +6 -12
  25. package/src/MessageImage.tsx +119 -17
  26. package/src/MessageText.tsx +10 -45
  27. package/src/MessageVideo.tsx +1 -1
  28. package/src/QuickReplies.tsx +2 -2
  29. package/src/Send.tsx +3 -4
  30. package/src/SystemMessage.tsx +1 -1
  31. package/src/Time.tsx +1 -1
  32. package/src/TypingIndicator/index.tsx +2 -2
  33. package/src/__tests__/DayAnimated.test.tsx +4 -4
  34. package/src/__tests__/GiftedChat.test.tsx +3 -3
  35. package/src/__tests__/LoadEarlier.test.tsx +3 -3
  36. package/src/__tests__/__snapshots__/Actions.test.tsx.snap +39 -7
  37. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +20 -22
  38. package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +38 -7
  39. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +34 -15
  40. package/src/__tests__/__snapshots__/Send.test.tsx.snap +70 -10
  41. package/src/components/TouchableOpacity.tsx +45 -0
  42. package/src/types.ts +1 -3
  43. package/src/utils.ts +2 -2
@@ -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
- TextInput,
18
- View,
19
- LayoutChangeEvent,
20
- } from 'react-native'
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 { LoadEarlier } from '../LoadEarlier'
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 stylesCommon from '../styles'
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
- bottomOffset = 0,
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 disabled
112
+ // Create a mock keyboard object when keyboard is not internally handled
112
113
  const keyboard = useMemo(() => {
113
- if (disableKeyboardController)
114
+ if (!isKeyboardInternallyHandled)
114
115
  return { height: { value: 0 } }
116
+
115
117
  return keyboardControllerData
116
- }, [disableKeyboardController, keyboardControllerData])
118
+ }, [isKeyboardInternallyHandled, keyboardControllerData])
117
119
 
118
120
  const trackingKeyboardMovement = useSharedValue(false)
119
- const keyboardOffsetBottom = useSharedValue(0)
121
+ const keyboardBottomOffsetAnim = useSharedValue(0)
120
122
 
121
123
  const contentStyleAnim = useAnimatedStyle(
122
124
  () => ({
123
125
  transform: [
124
- { translateY: keyboard.height.value - keyboardOffsetBottom.value },
126
+ { translateY: keyboard.height.value + keyboardBottomOffsetAnim.value },
125
127
  ],
126
128
  }),
127
- [keyboard, keyboardOffsetBottom]
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 controller is enabled
355
+ // Only set up keyboard animation when keyboard is internally handled
353
356
  useAnimatedReaction(
354
- () => disableKeyboardController ? 0 : -keyboard.height.value,
357
+ () => isKeyboardInternallyHandled ? keyboard.height.value : 0,
355
358
  (value, prevValue) => {
356
- // Skip keyboard handling when disabled
357
- if (disableKeyboardController)
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 > prevValue
364
+ const isKeyboardMovingUp = value < prevValue
362
365
  if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
363
366
  trackingKeyboardMovement.value = isKeyboardMovingUp
364
- keyboardOffsetBottom.value = withTiming(
365
- isKeyboardMovingUp ? bottomOffset : 0,
367
+ keyboardBottomOffsetAnim.value = withTiming(
368
+ isKeyboardMovingUp ? keyboardBottomOffset : 0,
366
369
  {
367
- // If `bottomOffset` exists, we change the duration to a smaller value to fix the delay in the keyboard animation speed
368
- duration: bottomOffset ? 150 : 400,
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
- bottomOffset,
387
- disableKeyboardController,
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, (isKeyboardInternallyHandled && !disableKeyboardController) && contentStyleAnim]}>
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 controller is disabled
417
- if (props.disableKeyboardController)
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
- <KeyboardProvider>
422
- <GiftedChat<TMessage> {...props} />
423
- </KeyboardProvider>
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
- LoadEarlier,
473
+ LoadEarlierMessages,
467
474
  Message,
468
475
  MessageContainer,
469
476
  Send,
@@ -1,6 +1,9 @@
1
1
  import { StyleSheet } from 'react-native'
2
2
 
3
3
  export default StyleSheet.create({
4
+ fill: {
5
+ flex: 1,
6
+ },
4
7
  contentContainer: {
5
8
  overflow: 'hidden',
6
9
  },
@@ -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 { LightboxProps } from 'react-native-lightbox-v2'
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
- bottomOffset?: number
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
- options?: { [key: string]: () => void }
86
- optionTintColor?: string
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
- /* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */
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>,
@@ -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
- options?: { [key: string]: () => void }
12
- optionTintColor?: string
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
- options,
35
- optionTintColor,
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
- options,
47
- optionTintColor,
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
- options,
60
- optionTintColor,
59
+ actions,
60
+ actionSheetOptionTintColor,
61
61
  icon,
62
62
  wrapperStyle,
63
63
  containerStyle,
@@ -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 LoadEarlierProps {
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
- onLoadEarlier?(): void
52
+ onPress: () => void
53
53
  }
54
54
 
55
- export function LoadEarlier ({
55
+ export const LoadEarlierMessages: React.FC<LoadEarlierMessagesProps> = ({
56
56
  isLoadingEarlier = false,
57
- onLoadEarlier = () => {},
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
- }: LoadEarlierProps): React.ReactElement {
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={onLoadEarlier}
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
+ }
@@ -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 { MessageProps } from './types'
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
- let Message: React.FC<MessageProps<IMessage>> = (props: MessageProps<IMessage>) => {
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
- Message = memo(Message, (props, nextProps) => {
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)
@@ -1,9 +1,9 @@
1
1
  import { ViewStyle, LayoutChangeEvent } from 'react-native'
2
2
  import { AvatarProps } from '../Avatar'
3
- import { SystemMessageProps } from '../SystemMessage'
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
@@ -1,6 +1,6 @@
1
1
  import React, { useMemo } from 'react'
2
- import Color from './Color'
3
2
  import { View, Text, StyleSheet } from 'react-native'
3
+ import Color from './Color'
4
4
 
5
5
  const styles = StyleSheet.create({
6
6
  container: {
@@ -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, isLoadingEarlier, ...rest }: DayAnimatedProps) => {
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 isLoadingEarlierAnim = useSharedValue(isLoadingEarlier)
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, isLoadingEarlierAnim.value ? 0 : containerHeight.value + dayTopOffset],
61
- [dayTopOffset, dayTopOffset, -containerHeight.value, isLoadingEarlierAnim.value ? -containerHeight.value : dayTopOffset],
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, isLoadingEarlierAnim])
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
- isLoadingEarlierAnim.value = isLoadingEarlier
115
- }, [isLoadingEarlierAnim, isLoadingEarlier])
114
+ isLoadingAnim.value = isLoading
115
+ }, [isLoadingAnim, isLoading])
116
116
 
117
117
  const dayContent = useMemo(() => {
118
118
  if (!createdAt)
@@ -8,5 +8,5 @@ export interface DayAnimatedProps extends Omit<DayProps, 'createdAt'> {
8
8
  listHeight: { value: number }
9
9
  renderDay?: (props: DayProps) => React.ReactNode
10
10
  messages: IMessage[]
11
- isLoadingEarlier: boolean
11
+ isLoading: boolean
12
12
  }
@@ -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