react-native-gifted-chat 3.0.0-alpha.0 → 3.0.0

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 (33) hide show
  1. package/CHANGELOG.md +295 -0
  2. package/README.md +71 -95
  3. package/package.json +2 -2
  4. package/src/Actions.tsx +27 -18
  5. package/src/Composer.tsx +21 -84
  6. package/src/Constant.ts +0 -9
  7. package/src/GiftedChat/index.tsx +52 -163
  8. package/src/GiftedChat/types.ts +11 -12
  9. package/src/InputToolbar.tsx +6 -11
  10. package/src/MessageImage.tsx +135 -65
  11. package/src/{MessageContainer → MessagesContainer}/components/Item/index.tsx +21 -17
  12. package/src/{MessageContainer → MessagesContainer}/components/Item/types.ts +3 -2
  13. package/src/{MessageContainer → MessagesContainer}/index.tsx +18 -14
  14. package/src/{MessageContainer → MessagesContainer}/styles.ts +12 -5
  15. package/src/{MessageContainer → MessagesContainer}/types.ts +4 -2
  16. package/src/Send.tsx +40 -22
  17. package/src/__tests__/DayAnimated.test.tsx +1 -1
  18. package/src/__tests__/GiftedChat.test.tsx +0 -28
  19. package/src/__tests__/{MessageContainer.test.tsx → MessagesContainer.test.tsx} +7 -7
  20. package/src/__tests__/__snapshots__/Actions.test.tsx.snap +31 -23
  21. package/src/__tests__/__snapshots__/Composer.test.tsx.snap +29 -30
  22. package/src/__tests__/__snapshots__/Constant.test.tsx.snap +0 -2
  23. package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +31 -54
  24. package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +102 -31
  25. package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +252 -1
  26. package/src/__tests__/__snapshots__/Send.test.tsx.snap +189 -49
  27. package/src/index.ts +1 -1
  28. package/src/styles.ts +5 -0
  29. package/src/types.ts +1 -1
  30. package/CHANGELOG_2.8.1_to_2.8.2-alpha.5.md +0 -374
  31. /package/src/{MessageContainer → MessagesContainer}/components/DayAnimated/index.tsx +0 -0
  32. /package/src/{MessageContainer → MessagesContainer}/components/DayAnimated/styles.ts +0 -0
  33. /package/src/{MessageContainer → MessagesContainer}/components/DayAnimated/types.ts +0 -0
@@ -6,6 +6,7 @@ import { Color } from './Color'
6
6
  import { Composer, ComposerProps } from './Composer'
7
7
  import { IMessage } from './Models'
8
8
  import { Send, SendProps } from './Send'
9
+ import { getColorSchemeStyle } from './styles'
9
10
  import { renderComponentOrElement } from './utils'
10
11
 
11
12
  export interface InputToolbarProps<TMessage extends IMessage> {
@@ -13,7 +14,6 @@ export interface InputToolbarProps<TMessage extends IMessage> {
13
14
  actionSheetOptionTintColor?: string
14
15
  containerStyle?: StyleProp<ViewStyle>
15
16
  primaryStyle?: StyleProp<ViewStyle>
16
- accessoryStyle?: StyleProp<ViewStyle>
17
17
  renderAccessory?: (props: InputToolbarProps<TMessage>) => React.ReactNode
18
18
  renderActions?: (props: ActionsProps) => React.ReactNode
19
19
  renderSend?: (props: SendProps<TMessage>) => React.ReactNode
@@ -88,16 +88,14 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
88
88
  if (!renderAccessory)
89
89
  return null
90
90
 
91
- return (
92
- <View style={[styles.accessory, props.accessoryStyle]}>
93
- {renderComponentOrElement(renderAccessory, props)}
94
- </View>
95
- )
91
+ return renderComponentOrElement(renderAccessory, props)
96
92
  }, [renderAccessory, props])
97
93
 
98
94
  return (
99
- <View style={[styles.container, colorScheme === 'dark' && styles.container_dark, containerStyle]}>
100
- <View style={[styles.primary, props.primaryStyle]}>
95
+ <View
96
+ style={[getColorSchemeStyle(styles, 'container', colorScheme), containerStyle]}
97
+ >
98
+ <View style={[getColorSchemeStyle(styles, 'primary', colorScheme), props.primaryStyle]}>
101
99
  {actionsFragment}
102
100
  {composerFragment}
103
101
  {sendFragment}
@@ -121,7 +119,4 @@ const styles = StyleSheet.create({
121
119
  flexDirection: 'row',
122
120
  alignItems: 'flex-end',
123
121
  },
124
- accessory: {
125
- height: 44,
126
- },
127
122
  })
@@ -8,46 +8,101 @@ import {
8
8
  StyleProp,
9
9
  ImageStyle,
10
10
  ImageURISource,
11
- Modal,
12
11
  TouchableOpacity,
13
12
  LayoutChangeEvent,
14
13
  useWindowDimensions,
14
+ StatusBar,
15
15
  } from 'react-native'
16
16
  import { BaseButton, GestureHandlerRootView, Text } from 'react-native-gesture-handler'
17
- import { useSafeAreaInsets } from 'react-native-safe-area-context'
17
+ import { OverKeyboardView } from 'react-native-keyboard-controller'
18
+ import Animated, {
19
+ useAnimatedStyle,
20
+ useSharedValue,
21
+ withTiming,
22
+ Easing,
23
+ runOnJS,
24
+ } from 'react-native-reanimated'
25
+ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
18
26
  import Zoom from 'react-native-zoom-reanimated'
19
27
  import { IMessage } from './Models'
20
28
  import commonStyles from './styles'
21
29
 
22
- const styles = StyleSheet.create({
23
- image: {
24
- width: 150,
25
- height: 100,
26
- borderRadius: 13,
27
- margin: 3,
28
- resizeMode: 'cover',
29
- },
30
- modalContent: {
31
- backgroundColor: '#000',
32
- },
33
- modalImageContainer: {
34
- width: '100%',
35
- height: '100%',
36
- },
30
+ interface ModalContentProps {
31
+ isVisible: boolean
32
+ imageSource: ImageURISource
33
+ modalImageDimensions: { width: number, height: number } | undefined
34
+ imageProps?: Partial<ImageProps>
35
+ onClose: () => void
36
+ }
37
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',
49
- },
50
- })
38
+ function ModalContent({ isVisible, imageSource, modalImageDimensions, imageProps, onClose }: ModalContentProps) {
39
+ const insets = useSafeAreaInsets()
40
+
41
+ // Animation values
42
+ const modalOpacity = useSharedValue(0)
43
+ const modalScale = useSharedValue(0.9)
44
+ const modalBorderRadius = useSharedValue(40)
45
+
46
+ const handleModalClose = useCallback(() => {
47
+ modalOpacity.value = withTiming(0, { duration: 200, easing: Easing.in(Easing.ease) })
48
+ modalScale.value = withTiming(0.9, { duration: 200, easing: Easing.in(Easing.ease) }, () => {
49
+ runOnJS(onClose)()
50
+ })
51
+ modalBorderRadius.value = withTiming(40, { duration: 200, easing: Easing.in(Easing.ease) })
52
+ }, [onClose, modalOpacity, modalScale, modalBorderRadius])
53
+
54
+ // Animate on visibility change
55
+ useEffect(() => {
56
+ if (isVisible) {
57
+ modalOpacity.value = withTiming(1, { duration: 300, easing: Easing.out(Easing.ease) })
58
+ modalScale.value = withTiming(1, { duration: 300, easing: Easing.out(Easing.ease) })
59
+ modalBorderRadius.value = withTiming(0, { duration: 300, easing: Easing.out(Easing.ease) })
60
+ }
61
+ }, [isVisible, modalOpacity, modalScale, modalBorderRadius])
62
+
63
+ const modalAnimatedStyle = useAnimatedStyle(() => ({
64
+ opacity: modalOpacity.value,
65
+ transform: [{ scale: modalScale.value }],
66
+ }), [modalOpacity, modalScale])
67
+
68
+ const modalBorderRadiusStyle = useAnimatedStyle(() => ({
69
+ borderRadius: modalBorderRadius.value,
70
+ }), [modalBorderRadius])
71
+
72
+ return (
73
+ <>
74
+ <StatusBar animated barStyle='dark-content' />
75
+ <Animated.View style={[styles.modalOverlay, modalAnimatedStyle, modalBorderRadiusStyle]}>
76
+ <GestureHandlerRootView style={commonStyles.fill}>
77
+ <Animated.View style={[commonStyles.fill, styles.modalContent, modalBorderRadiusStyle, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
78
+
79
+ {/* close button */}
80
+ <View style={styles.closeButtonContainer}>
81
+ <BaseButton onPress={handleModalClose}>
82
+ <View style={styles.closeButtonContent}>
83
+ <Text style={styles.closeButtonIcon}>
84
+ {'X'}
85
+ </Text>
86
+ </View>
87
+ </BaseButton>
88
+ </View>
89
+
90
+ <View style={[commonStyles.fill, commonStyles.centerItems]}>
91
+ <Zoom>
92
+ <Image
93
+ style={modalImageDimensions}
94
+ source={imageSource}
95
+ resizeMode='contain'
96
+ {...imageProps}
97
+ />
98
+ </Zoom>
99
+ </View>
100
+ </Animated.View>
101
+ </GestureHandlerRootView>
102
+ </Animated.View>
103
+ </>
104
+ )
105
+ }
51
106
 
52
107
  export interface MessageImageProps<TMessage extends IMessage> {
53
108
  currentMessage: TMessage
@@ -68,8 +123,6 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
68
123
  const [imageDimensions, setImageDimensions] = useState<{ width: number, height: number }>()
69
124
  const windowDimensions = useWindowDimensions()
70
125
 
71
- const insets = useSafeAreaInsets()
72
-
73
126
  const imageSource = useMemo(() => ({
74
127
  ...imageSourceProps,
75
128
  uri: currentMessage?.image,
@@ -140,42 +193,59 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
140
193
  style={computedImageStyle}
141
194
  source={imageSource}
142
195
  onLayout={handleImageLayout}
196
+ resizeMode='cover'
143
197
  />
144
198
  </TouchableOpacity>
145
199
 
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>
200
+ <OverKeyboardView visible={isModalVisible}>
201
+ <SafeAreaProvider>
202
+ <ModalContent
203
+ isVisible={isModalVisible}
204
+ imageSource={imageSource}
205
+ modalImageDimensions={modalImageDimensions}
206
+ imageProps={imageProps}
207
+ onClose={handleModalClose}
208
+ />
209
+ </SafeAreaProvider>
210
+ </OverKeyboardView>
179
211
  </View>
180
212
  )
181
213
  }
214
+
215
+ const styles = StyleSheet.create({
216
+ image: {
217
+ width: 150,
218
+ height: 100,
219
+ borderRadius: 13,
220
+ margin: 3,
221
+ },
222
+ modalOverlay: {
223
+ position: 'absolute',
224
+ top: 0,
225
+ left: 0,
226
+ right: 0,
227
+ bottom: 0,
228
+ zIndex: 1000,
229
+ },
230
+ modalContent: {
231
+ backgroundColor: '#000',
232
+ overflow: 'hidden',
233
+ },
234
+ modalImageContainer: {
235
+ width: '100%',
236
+ height: '100%',
237
+ },
238
+
239
+ closeButtonContainer: {
240
+ flexDirection: 'row',
241
+ justifyContent: 'flex-end',
242
+ },
243
+ closeButtonContent: {
244
+ padding: 20,
245
+ },
246
+ closeButtonIcon: {
247
+ fontSize: 20,
248
+ lineHeight: 20,
249
+ color: 'white',
250
+ },
251
+ })
@@ -103,6 +103,7 @@ export const Item = <TMessage extends IMessage>(props: ItemProps<TMessage>) => {
103
103
  scrolledY,
104
104
  daysPositions,
105
105
  listHeight,
106
+ isDayAnimationEnabled,
106
107
  ...rest
107
108
  } = props
108
109
 
@@ -121,23 +122,26 @@ export const Item = <TMessage extends IMessage>(props: ItemProps<TMessage>) => {
121
122
  }, [dayContainerHeight])
122
123
 
123
124
  const style = useAnimatedStyle(() => ({
124
- opacity: interpolate(
125
- relativeScrolledPositionToBottomOfDay.value,
126
- [
127
- -dayTopOffset,
128
- -0.0001,
129
- 0,
130
- dayContainerHeight.value + dayTopOffset,
131
- ],
132
- [
133
- 0,
134
- 0,
135
- 1,
136
- 1,
137
- ],
138
- 'clamp'
139
- ),
140
- }), [relativeScrolledPositionToBottomOfDay, dayContainerHeight, dayTopOffset])
125
+ opacity:
126
+ isDayAnimationEnabled
127
+ ? interpolate(
128
+ relativeScrolledPositionToBottomOfDay.value,
129
+ [
130
+ -dayTopOffset,
131
+ -0.0001,
132
+ 0,
133
+ dayContainerHeight.value + dayTopOffset,
134
+ ],
135
+ [
136
+ 0,
137
+ 0,
138
+ 1,
139
+ 1,
140
+ ],
141
+ 'clamp'
142
+ )
143
+ : 1,
144
+ }), [relativeScrolledPositionToBottomOfDay, dayContainerHeight, dayTopOffset, isDayAnimationEnabled])
141
145
 
142
146
  return (
143
147
  // do not remove key. it helps to get correct position of the day container
@@ -1,7 +1,7 @@
1
1
  import { IMessage } from '../../../Models'
2
- import { MessageContainerProps, DaysPositions } from '../../types'
2
+ import { MessagesContainerProps, DaysPositions } from '../../types'
3
3
 
4
- export interface ItemProps<TMessage extends IMessage> extends MessageContainerProps<TMessage> {
4
+ export interface ItemProps<TMessage extends IMessage> extends MessagesContainerProps<TMessage> {
5
5
  currentMessage: TMessage
6
6
  previousMessage?: TMessage
7
7
  nextMessage?: TMessage
@@ -9,4 +9,5 @@ export interface ItemProps<TMessage extends IMessage> extends MessageContainerPr
9
9
  scrolledY: { value: number }
10
10
  daysPositions: { value: DaysPositions }
11
11
  listHeight: { value: number }
12
+ isDayAnimationEnabled?: boolean
12
13
  }
@@ -1,13 +1,12 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react'
2
2
  import {
3
3
  View,
4
- Pressable,
5
4
  Text,
6
5
  LayoutChangeEvent,
7
6
  ListRenderItemInfo,
8
7
  CellRendererProps,
9
8
  } from 'react-native'
10
- import { FlatList } from 'react-native-gesture-handler'
9
+ import { FlatList, Pressable } from 'react-native-gesture-handler'
11
10
  import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
12
11
  import { LoadEarlierMessages } from '../LoadEarlierMessages'
13
12
  import { warning } from '../logging'
@@ -21,14 +20,13 @@ import { DayAnimated } from './components/DayAnimated'
21
20
  import { Item } from './components/Item'
22
21
  import { ItemProps } from './components/Item/types'
23
22
  import styles from './styles'
24
- import { MessageContainerProps, DaysPositions } from './types'
23
+ import { MessagesContainerProps, DaysPositions } from './types'
25
24
 
26
25
  export * from './types'
27
26
 
28
-
29
27
  const AnimatedFlatList = Animated.createAnimatedComponent(FlatList) as React.ComponentType<any>
30
28
 
31
- export const MessageContainer = <TMessage extends IMessage>(props: MessageContainerProps<TMessage>) => {
29
+ export const MessagesContainer = <TMessage extends IMessage>(props: MessagesContainerProps<TMessage>) => {
32
30
  const {
33
31
  messages = [],
34
32
  user,
@@ -47,6 +45,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
47
45
  forwardRef,
48
46
  scrollToBottomComponent: scrollToBottomComponentProp,
49
47
  renderDay: renderDayProp,
48
+ isDayAnimationEnabled = true,
50
49
  } = props
51
50
 
52
51
  const listPropsOnScrollProp = listProps?.onScroll
@@ -182,6 +181,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
182
181
  scrolledY,
183
182
  daysPositions,
184
183
  listHeight,
184
+ isDayAnimationEnabled,
185
185
  }
186
186
 
187
187
  return (
@@ -190,7 +190,7 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
190
190
  }
191
191
 
192
192
  return null
193
- }, [messages, restProps, isInverted, scrolledY, daysPositions, listHeight, user])
193
+ }, [messages, restProps, isInverted, scrolledY, daysPositions, listHeight, isDayAnimationEnabled, user])
194
194
 
195
195
  const emptyContent = useMemo(() => {
196
196
  if (!renderChatEmptyProp)
@@ -401,20 +401,24 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
401
401
  scrollEventThrottle={1}
402
402
  onEndReached={onEndReached}
403
403
  onEndReachedThreshold={0.1}
404
+ keyboardDismissMode='interactive'
405
+ keyboardShouldPersistTaps='handled'
404
406
  {...listProps}
405
407
  onScroll={scrollHandler}
406
408
  onLayout={onLayoutList}
407
409
  CellRendererComponent={renderCell}
408
410
  />
409
411
  <ScrollToBottomWrapper />
410
- <DayAnimated
411
- scrolledY={scrolledY}
412
- daysPositions={daysPositions}
413
- listHeight={listHeight}
414
- renderDay={renderDayProp}
415
- messages={messages}
416
- isLoading={loadEarlierMessagesProps?.isLoading ?? false}
417
- />
412
+ {isDayAnimationEnabled && (
413
+ <DayAnimated
414
+ scrolledY={scrolledY}
415
+ daysPositions={daysPositions}
416
+ listHeight={listHeight}
417
+ renderDay={renderDayProp}
418
+ messages={messages}
419
+ isLoading={loadEarlierMessagesProps?.isLoading ?? false}
420
+ />
421
+ )}
418
422
  </View>
419
423
  )
420
424
  }
@@ -1,4 +1,4 @@
1
- import { StyleSheet } from 'react-native'
1
+ import { Platform, StyleSheet } from 'react-native'
2
2
  import { Color } from '../Color'
3
3
 
4
4
  export default StyleSheet.create({
@@ -24,9 +24,16 @@ export default StyleSheet.create({
24
24
  width: 40,
25
25
  borderRadius: 20,
26
26
  backgroundColor: Color.white,
27
- shadowColor: Color.black,
28
- shadowOpacity: 0.5,
29
- shadowOffset: { width: 0, height: 0 },
30
- shadowRadius: 1,
27
+ ...Platform.select({
28
+ ios: {
29
+ shadowColor: Color.black,
30
+ shadowOpacity: 0.5,
31
+ shadowOffset: { width: 0, height: 0 },
32
+ shadowRadius: 1,
33
+ },
34
+ android: {
35
+ elevation: 5,
36
+ },
37
+ }),
31
38
  },
32
39
  })
@@ -16,7 +16,7 @@ export type ListProps<TMessage extends IMessage = IMessage> = Partial<FlatListPr
16
16
 
17
17
  export type AnimatedList<TMessage> = FlatList<TMessage>
18
18
 
19
- export interface MessageContainerProps<TMessage extends IMessage = IMessage>
19
+ export interface MessagesContainerProps<TMessage extends IMessage = IMessage>
20
20
  extends Omit<TypingIndicatorProps, 'style'> {
21
21
  /** Ref for the FlatList message container */
22
22
  forwardRef?: RefObject<AnimatedList<TMessage>>
@@ -39,7 +39,7 @@ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
39
39
  /** Custom component to render when messages are empty */
40
40
  renderChatEmpty?: () => React.ReactNode
41
41
  /** Custom footer component on the ListView, e.g. 'User is typing...' */
42
- renderFooter?: (props: MessageContainerProps<TMessage>) => React.ReactNode
42
+ renderFooter?: (props: MessagesContainerProps<TMessage>) => React.ReactNode
43
43
  /** Custom message container */
44
44
  renderMessage?: (props: MessageProps<TMessage>) => React.ReactElement
45
45
  /** Custom day above a message */
@@ -56,6 +56,8 @@ export interface MessageContainerProps<TMessage extends IMessage = IMessage>
56
56
  loadEarlierMessagesProps?: LoadEarlierMessagesProps
57
57
  /** Style for TypingIndicator component */
58
58
  typingIndicatorStyle?: StyleProp<ViewStyle>
59
+ /** Enable animated day label that appears on scroll; default is true */
60
+ isDayAnimationEnabled?: boolean
59
61
  }
60
62
 
61
63
  export interface State {
package/src/Send.tsx CHANGED
@@ -1,18 +1,19 @@
1
- import React, { useMemo, useCallback } from 'react'
1
+ import React, { useMemo, useCallback, useEffect } from 'react'
2
2
  import {
3
3
  StyleSheet,
4
4
  Text,
5
- View,
6
5
  StyleProp,
7
6
  ViewStyle,
8
7
  TextStyle,
9
8
  useColorScheme,
10
9
  } from 'react-native'
10
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated'
11
11
  import { Color } from './Color'
12
12
 
13
13
  import { TouchableOpacity, TouchableOpacityProps } from './components/TouchableOpacity'
14
14
  import { TEST_ID } from './Constant'
15
15
  import { IMessage } from './Models'
16
+ import { getColorSchemeStyle } from './styles'
16
17
 
17
18
  export interface SendProps<TMessage extends IMessage> {
18
19
  text?: string
@@ -39,6 +40,7 @@ export const Send = <TMessage extends IMessage = IMessage>({
39
40
  onSend,
40
41
  }: SendProps<TMessage>) => {
41
42
  const colorScheme = useColorScheme()
43
+ const opacity = useSharedValue(0)
42
44
 
43
45
  const handleOnPress = useCallback(() => {
44
46
  const message = { text: text?.trim() } as Partial<TMessage>
@@ -47,34 +49,51 @@ export const Send = <TMessage extends IMessage = IMessage>({
47
49
  onSend(message, true)
48
50
  }, [text, onSend])
49
51
 
50
- const showSend = useMemo(
52
+ const isVisible = useMemo(
51
53
  () => isSendButtonAlwaysVisible || !!text?.trim().length,
52
54
  [isSendButtonAlwaysVisible, text]
53
55
  )
54
56
 
55
- if (!showSend)
56
- return null
57
+ useEffect(() => {
58
+ opacity.value = withTiming(isVisible ? 1 : 0, { duration: 200 })
59
+ }, [isVisible, opacity])
60
+
61
+ const animatedStyle = useAnimatedStyle(() => ({
62
+ opacity: opacity.value,
63
+ }), [opacity])
57
64
 
58
65
  return (
59
- <TouchableOpacity
60
- testID={TEST_ID.SEND_TOUCHABLE}
61
- style={[styles.container, containerStyle]}
62
- onPress={handleOnPress}
63
- accessible
64
- accessibilityLabel='send'
65
- accessibilityRole='button'
66
- {...sendButtonProps}
67
- >
68
- <View>
69
- {children || <Text style={[styles.text, styles[`text_${colorScheme}`], textStyle]}>{label}</Text>}
70
- </View>
71
- </TouchableOpacity>
66
+ <Animated.View style={[styles.container, containerStyle, animatedStyle]} pointerEvents={isVisible ? 'auto' : 'none'}>
67
+ <TouchableOpacity
68
+ testID={TEST_ID.SEND_TOUCHABLE}
69
+ style={styles.touchable}
70
+ onPress={handleOnPress}
71
+ accessible
72
+ accessibilityLabel='send'
73
+ accessibilityRole='button'
74
+ {...sendButtonProps}
75
+ >
76
+ {
77
+ children ||
78
+ <Text
79
+ style={[
80
+ getColorSchemeStyle(styles, 'text', colorScheme),
81
+ textStyle,
82
+ ]}
83
+ >
84
+ {label}
85
+ </Text>
86
+ }
87
+ </TouchableOpacity>
88
+ </Animated.View>
72
89
  )
73
90
  }
74
91
 
75
92
  const styles = StyleSheet.create({
76
93
  container: {
77
- height: 44,
94
+ justifyContent: 'flex-end',
95
+ },
96
+ touchable: {
78
97
  justifyContent: 'flex-end',
79
98
  },
80
99
  text: {
@@ -82,9 +101,8 @@ const styles = StyleSheet.create({
82
101
  fontWeight: '600',
83
102
  fontSize: 17,
84
103
  backgroundColor: Color.backgroundTransparent,
85
- marginBottom: 12,
86
- marginLeft: 10,
87
- marginRight: 10,
104
+ paddingVertical: 10,
105
+ paddingHorizontal: 10,
88
106
  },
89
107
  text_dark: {
90
108
  color: '#4da6ff',
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import { View, Text } from 'react-native'
3
3
  import { render } from '@testing-library/react-native'
4
4
  import { DayProps } from '../Day'
5
- import { DayAnimated } from '../MessageContainer/components/DayAnimated'
5
+ import { DayAnimated } from '../MessagesContainer/components/DayAnimated'
6
6
  import { DEFAULT_TEST_MESSAGE } from './data'
7
7
 
8
8
  const mockDaysPositions = { value: {} }
@@ -1,7 +1,6 @@
1
1
  import React from 'react'
2
2
  import { render } from '@testing-library/react-native'
3
3
 
4
- import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'
5
4
  import { GiftedChat } from '..'
6
5
 
7
6
  const messages = [
@@ -17,32 +16,6 @@ const messages = [
17
16
  ]
18
17
 
19
18
  it('should render <GiftedChat/> and compare with snapshot', () => {
20
- (useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
21
- height: {
22
- value: 0,
23
- },
24
- })
25
-
26
- const { toJSON } = render(
27
- <GiftedChat
28
- messages={messages}
29
- onSend={() => {}}
30
- user={{
31
- _id: 1,
32
- }}
33
- />
34
- )
35
-
36
- expect(toJSON()).toMatchSnapshot()
37
- })
38
-
39
- it('should render <GiftedChat/> with isKeyboardInternallyHandled=false', () => {
40
- (useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
41
- height: {
42
- value: 0,
43
- },
44
- })
45
-
46
19
  const { toJSON } = render(
47
20
  <GiftedChat
48
21
  messages={messages}
@@ -50,7 +23,6 @@ it('should render <GiftedChat/> with isKeyboardInternallyHandled=false', () => {
50
23
  user={{
51
24
  _id: 1,
52
25
  }}
53
- isKeyboardInternallyHandled={false}
54
26
  />
55
27
  )
56
28