react-native-gifted-chat 3.2.3 → 3.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gifted-chat",
3
- "version": "3.2.3",
3
+ "version": "3.3.2",
4
4
  "description": "The most complete chat UI for React Native",
5
5
  "keywords": [
6
6
  "android",
@@ -29,8 +29,8 @@
29
29
  "src"
30
30
  ],
31
31
  "scripts": {
32
- "lint": "yarn eslint src",
33
- "lint:fix": "yarn eslint --cache --fix",
32
+ "lint": "yarn eslint src example",
33
+ "lint:fix": "yarn eslint --cache --fix src example",
34
34
  "prepublishOnly": "yarn lint && yarn test",
35
35
  "start": "cd example && expo start",
36
36
  "start:web": "cd example && expo start -w --dev",
@@ -52,7 +52,7 @@
52
52
  "@types/lodash.isequal": "^4.5.8",
53
53
  "dayjs": "^1.11.19",
54
54
  "lodash.isequal": "^4.5.0",
55
- "react-native-zoom-reanimated": "^1.4.10"
55
+ "react-native-zoom-reanimated": "^1.5.2"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@babel/core": "^7.28.5",
@@ -92,10 +92,11 @@
92
92
  "react": "19.1.0",
93
93
  "react-dom": "19.1.0",
94
94
  "react-native": "0.81.5",
95
- "react-native-gesture-handler": "^2.29.1",
96
- "react-native-keyboard-controller": "^1.19.6",
97
- "react-native-reanimated": "^3.19.4",
98
- "react-native-safe-area-context": "^5.6.2",
95
+ "react-native-gesture-handler": "~2.30.0",
96
+ "react-native-keyboard-controller": "1.20.6",
97
+ "react-native-reanimated": "~4.2.1",
98
+ "react-native-safe-area-context": "~5.6.2",
99
+ "react-native-worklets": "0.7.2",
99
100
  "react-test-renderer": "19.1.0",
100
101
  "typescript": "^5.9.3"
101
102
  },
@@ -5,6 +5,8 @@ import {
5
5
  } from 'react-native'
6
6
 
7
7
  import { Text } from 'react-native-gesture-handler'
8
+
9
+ import { MessageReply } from '../components/MessageReply'
8
10
  import { useChatContext } from '../GiftedChatContext'
9
11
  import { MessageAudio } from '../MessageAudio'
10
12
  import { MessageImage } from '../MessageImage'
@@ -12,10 +14,8 @@ import { MessageText } from '../MessageText'
12
14
  import { MessageVideo } from '../MessageVideo'
13
15
  import { IMessage } from '../Models'
14
16
  import { QuickReplies } from '../QuickReplies'
15
-
16
17
  import { getStyleWithPosition } from '../styles'
17
18
  import { Time } from '../Time'
18
-
19
19
  import { isSameUser, isSameDay, renderComponentOrElement } from '../utils'
20
20
  import styles from './styles'
21
21
  import { BubbleProps, RenderMessageTextProps } from './types'
@@ -319,10 +319,41 @@ export const Bubble = <TMessage extends IMessage = IMessage>(props: BubbleProps<
319
319
  return null
320
320
  }, [props])
321
321
 
322
+ const renderMessageReply = useCallback(() => {
323
+ if (!currentMessage?.replyMessage)
324
+ return null
325
+
326
+ const { messageReply } = props
327
+
328
+ const messageReplyProps = {
329
+ replyMessage: currentMessage.replyMessage,
330
+ currentMessage,
331
+ position,
332
+ onPress: messageReply?.onPress,
333
+ containerStyle: position === 'left'
334
+ ? messageReply?.containerStyleLeft ?? messageReply?.containerStyle
335
+ : messageReply?.containerStyleRight ?? messageReply?.containerStyle,
336
+ textStyle: position === 'left'
337
+ ? messageReply?.textStyleLeft ?? messageReply?.textStyle
338
+ : messageReply?.textStyleRight ?? messageReply?.textStyle,
339
+ imageStyle: messageReply?.imageStyle,
340
+ }
341
+
342
+ if (messageReply?.renderMessageReply)
343
+ return renderComponentOrElement(messageReply.renderMessageReply, messageReplyProps)
344
+
345
+ return <MessageReply {...messageReplyProps} />
346
+ }, [
347
+ props,
348
+ currentMessage,
349
+ position,
350
+ ])
351
+
322
352
  const renderBubbleContent = useCallback(() => {
323
353
  return (
324
354
  <>
325
355
  {!props.isCustomViewBottom && renderCustomView()}
356
+ {renderMessageReply()}
326
357
  {renderMessageImage()}
327
358
  {renderMessageVideo()}
328
359
  {renderMessageAudio()}
@@ -331,6 +362,7 @@ export const Bubble = <TMessage extends IMessage = IMessage>(props: BubbleProps<
331
362
  </>
332
363
  )
333
364
  }, [
365
+ renderMessageReply,
334
366
  renderCustomView,
335
367
  renderMessageImage,
336
368
  renderMessageVideo,
@@ -5,6 +5,8 @@ import {
5
5
  TextStyle,
6
6
  Pressable,
7
7
  } from 'react-native'
8
+
9
+ import { MessageReplyProps } from '../components/MessageReply'
8
10
  import { MessageImageProps } from '../MessageImage'
9
11
  import { MessageTextProps } from '../MessageText'
10
12
  import {
@@ -12,11 +14,13 @@ import {
12
14
  IMessage,
13
15
  LeftRightStyle,
14
16
  Reply,
17
+ ReplyMessage,
15
18
  Omit,
16
19
  MessageVideoProps,
17
20
  MessageAudioProps,
18
21
  } from '../Models'
19
22
  import { QuickRepliesProps } from '../QuickReplies'
23
+ import { MessageReplyStyleProps } from '../Reply'
20
24
  import { TimeProps } from '../Time'
21
25
 
22
26
 
@@ -44,6 +48,13 @@ export type RenderMessageTextProps<TMessage extends IMessage> = Omit<
44
48
  > &
45
49
  MessageTextProps<TMessage>
46
50
 
51
+ /** Props for message reply functionality in bubble */
52
+ export interface BubbleReplyProps<TMessage extends IMessage> extends MessageReplyStyleProps {
53
+ /** Custom render for message reply; rendered on top of message content */
54
+ renderMessageReply?: (props: MessageReplyProps<TMessage>) => React.ReactNode
55
+ /** Callback when message reply is pressed */
56
+ onPress?: (replyMessage: ReplyMessage) => void
57
+ }
47
58
 
48
59
  export interface BubbleProps<TMessage extends IMessage> {
49
60
  user?: User
@@ -71,13 +82,13 @@ export interface BubbleProps<TMessage extends IMessage> {
71
82
  onLongPressMessage?: (context?: unknown, message?: unknown) => void
72
83
  onQuickReply?: (replies: Reply[]) => void
73
84
  renderMessageImage?: (
74
- props: RenderMessageImageProps<TMessage>,
85
+ props: RenderMessageImageProps<TMessage>
75
86
  ) => React.ReactNode
76
87
  renderMessageVideo?: (
77
- props: RenderMessageVideoProps<TMessage>,
88
+ props: RenderMessageVideoProps<TMessage>
78
89
  ) => React.ReactNode
79
90
  renderMessageAudio?: (
80
- props: RenderMessageAudioProps<TMessage>,
91
+ props: RenderMessageAudioProps<TMessage>
81
92
  ) => React.ReactNode
82
93
  renderMessageText?: (props: RenderMessageTextProps<TMessage>) => React.ReactNode
83
94
  renderCustomView?: (bubbleProps: BubbleProps<TMessage>) => React.ReactNode
@@ -86,6 +97,8 @@ export interface BubbleProps<TMessage extends IMessage> {
86
97
  renderUsername?: (user?: TMessage['user']) => React.ReactNode
87
98
  renderQuickReplySend?: () => React.ReactNode
88
99
  renderQuickReplies?: (
89
- quickReplies: QuickRepliesProps<TMessage>,
100
+ quickReplies: QuickRepliesProps<TMessage>
90
101
  ) => React.ReactNode
102
+ /** Message reply configuration */
103
+ messageReply?: BubbleReplyProps<TMessage>
91
104
  }
package/src/Day/index.tsx CHANGED
@@ -25,7 +25,7 @@ export function Day ({
25
25
  createdAt,
26
26
  containerStyle,
27
27
  wrapperStyle,
28
- textStyle,
28
+ textProps,
29
29
  }: DayProps) {
30
30
  const { getLocale } = useChatContext()
31
31
 
@@ -54,7 +54,7 @@ export function Day ({
54
54
  return (
55
55
  <View style={[stylesCommon.centerItems, styles.container, containerStyle]}>
56
56
  <View style={[styles.wrapper, wrapperStyle]}>
57
- <Text style={[styles.text, textStyle]}>
57
+ <Text {...textProps} style={[styles.text, textProps?.style]}>
58
58
  {dateStr}
59
59
  </Text>
60
60
  </View>
package/src/Day/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  StyleProp,
3
3
  ViewStyle,
4
- TextStyle,
4
+ TextProps,
5
5
  } from 'react-native'
6
6
 
7
7
  export interface DayProps {
@@ -10,5 +10,6 @@ export interface DayProps {
10
10
  dateFormatCalendar?: object
11
11
  containerStyle?: StyleProp<ViewStyle>
12
12
  wrapperStyle?: StyleProp<ViewStyle>
13
- textStyle?: StyleProp<TextStyle>
13
+ /** Props to pass to the Text component (e.g., style, allowFontScaling, numberOfLines) */
14
+ textProps?: Partial<TextProps>
14
15
  }
@@ -20,12 +20,12 @@ import dayjs from 'dayjs'
20
20
  import localizedFormat from 'dayjs/plugin/localizedFormat'
21
21
  import { GestureHandlerRootView, TextInput } from 'react-native-gesture-handler'
22
22
  import { KeyboardAvoidingView, KeyboardProvider } from 'react-native-keyboard-controller'
23
- import { SafeAreaProvider } from 'react-native-safe-area-context'
23
+ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
24
24
  import { TEST_ID } from '../Constant'
25
25
  import { GiftedChatContext } from '../GiftedChatContext'
26
26
  import { InputToolbar } from '../InputToolbar'
27
27
  import { MessagesContainer, AnimatedList } from '../MessagesContainer'
28
- import { IMessage } from '../Models'
28
+ import { IMessage, ReplyMessage } from '../Models'
29
29
  import stylesCommon from '../styles'
30
30
  import { renderComponentOrElement } from '../utils'
31
31
  import styles from './styles'
@@ -56,13 +56,26 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
56
56
  renderChatFooter,
57
57
  renderInputToolbar,
58
58
  isInverted = true,
59
+
60
+ // Reply props
61
+ reply,
59
62
  } = props
60
63
 
64
+ // Extract reply props for internal use
65
+ const replyMessageProp = reply?.message
66
+ const onClearReply = reply?.onClear
67
+ const onSwipeToReply = reply?.swipe?.onSwipe
68
+ const renderReplyPreview = reply?.renderPreview
69
+ const replyPreviewContainerStyle = reply?.previewStyle?.containerStyle
70
+ const replyPreviewTextStyle = reply?.previewStyle?.textStyle
71
+
61
72
  const systemColorScheme = useColorScheme()
62
73
  const colorScheme = colorSchemeProp !== undefined ? colorSchemeProp : systemColorScheme
63
74
 
64
75
  const actionSheetRef = useRef<ActionSheetProviderRef>(null)
65
76
 
77
+ const insets = useSafeAreaInsets()
78
+
66
79
  const messagesContainerRef = useMemo(
67
80
  () => props.messagesContainerRef || createRef<AnimatedList<TMessage>>(),
68
81
  [props.messagesContainerRef]
@@ -75,6 +88,10 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
75
88
 
76
89
  const [isInitialized, setIsInitialized] = useState<boolean>(false)
77
90
  const [text, setText] = useState<string | undefined>(() => props.text || '')
91
+ const [internalReplyMessage, setInternalReplyMessage] = useState<ReplyMessage | null>(null)
92
+
93
+ // Use controlled or uncontrolled reply state
94
+ const replyMessage = replyMessageProp !== undefined ? replyMessageProp : internalReplyMessage
78
95
 
79
96
  const getTextFromProp = useCallback(
80
97
  (fallback: string) => {
@@ -104,6 +121,31 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
104
121
  [isInverted, messagesContainerRef]
105
122
  )
106
123
 
124
+ const handleSwipeToReply = useCallback(
125
+ (message: TMessage) => {
126
+ if (replyMessageProp === undefined)
127
+ // Uncontrolled mode: manage state internally
128
+ setInternalReplyMessage({
129
+ _id: message._id,
130
+ text: message.text,
131
+ user: message.user,
132
+ image: message.image,
133
+ audio: message.audio,
134
+ })
135
+
136
+ onSwipeToReply?.(message)
137
+ },
138
+ [replyMessageProp, onSwipeToReply]
139
+ )
140
+
141
+ const clearReply = useCallback(() => {
142
+ if (replyMessageProp === undefined)
143
+ // Uncontrolled mode: manage state internally
144
+ setInternalReplyMessage(null)
145
+
146
+ onClearReply?.()
147
+ }, [replyMessageProp, onClearReply])
148
+
107
149
  const renderMessages = useMemo(() => {
108
150
  if (!isInitialized)
109
151
  return null
@@ -118,6 +160,13 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
118
160
  messages={messages}
119
161
  forwardRef={messagesContainerRef}
120
162
  isTyping={isTyping}
163
+ reply={{
164
+ ...reply,
165
+ swipe: reply?.swipe ? {
166
+ ...reply.swipe,
167
+ onSwipe: handleSwipeToReply,
168
+ } : undefined,
169
+ }}
121
170
  />
122
171
  {renderComponentOrElement(renderChatFooter, {})}
123
172
  </View>
@@ -130,6 +179,8 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
130
179
  isInverted,
131
180
  messagesContainerRef,
132
181
  renderChatFooter,
182
+ reply,
183
+ handleSwipeToReply,
133
184
  ])
134
185
 
135
186
  const notifyInputTextReset = useCallback(() => {
@@ -159,17 +210,22 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
159
210
  user: user!,
160
211
  createdAt: new Date(),
161
212
  _id: messageIdGenerator?.(),
213
+ // Attach reply message if exists
214
+ ...(replyMessage ? { replyMessage } : {}),
162
215
  }
163
216
  })
164
217
 
165
218
  if (shouldResetInputToolbar === true)
166
219
  resetInputToolbar()
167
220
 
221
+ // Clear reply after sending
222
+ clearReply()
223
+
168
224
  onSend?.(newMessages)
169
225
 
170
226
  setTimeout(() => scrollToBottom(), 10)
171
227
  },
172
- [messageIdGenerator, onSend, user, resetInputToolbar, scrollToBottom]
228
+ [messageIdGenerator, onSend, user, resetInputToolbar, scrollToBottom, replyMessage, clearReply]
173
229
  )
174
230
 
175
231
  const _onChangeText = useCallback(
@@ -214,6 +270,12 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
214
270
  onChangeText: _onChangeText,
215
271
  ref: textInputRef,
216
272
  },
273
+ // Reply preview props
274
+ replyMessage,
275
+ onClearReply: clearReply,
276
+ renderReplyPreview,
277
+ replyPreviewContainerStyle,
278
+ replyPreviewTextStyle,
217
279
  }
218
280
 
219
281
  if (renderInputToolbar)
@@ -230,6 +292,11 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
230
292
  textInputRef,
231
293
  textInputProps,
232
294
  _onChangeText,
295
+ replyMessage,
296
+ clearReply,
297
+ renderReplyPreview,
298
+ replyPreviewContainerStyle,
299
+ replyPreviewTextStyle,
233
300
  ])
234
301
 
235
302
  const contextValues = useMemo(
@@ -254,29 +321,25 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
254
321
  return (
255
322
  <GiftedChatContext.Provider value={contextValues}>
256
323
  <ActionSheetProvider ref={actionSheetRef}>
257
- {/* @ts-expect-error */}
258
- <KeyboardAvoidingView
259
- behavior='padding'
260
- style={stylesCommon.fill}
261
- {...props.keyboardAvoidingViewProps}
324
+ <View
325
+ testID={TEST_ID.WRAPPER}
326
+ style={[stylesCommon.fill, styles.contentContainer]}
327
+ onLayout={onInitialLayoutViewLayout}
262
328
  >
263
- <View
264
- testID={TEST_ID.WRAPPER}
265
- style={[stylesCommon.fill, styles.contentContainer]}
266
- onLayout={onInitialLayoutViewLayout}
329
+ {/* @ts-expect-error */}
330
+ <KeyboardAvoidingView
331
+ behavior='translate-with-padding'
332
+ keyboardVerticalOffset={insets.top}
333
+ style={stylesCommon.fill}
334
+ {...props.keyboardAvoidingViewProps}
267
335
  >
268
- {isInitialized
269
- ? (
270
- <>
271
- {renderMessages}
272
- {inputToolbarFragment}
273
- </>
274
- )
275
- : (
276
- renderComponentOrElement(renderLoading, {})
277
- )}
278
- </View>
279
- </KeyboardAvoidingView>
336
+ <View style={[stylesCommon.fill, !isInitialized && styles.hidden]}>
337
+ {renderMessages}
338
+ {inputToolbarFragment}
339
+ </View>
340
+ {!isInitialized && renderComponentOrElement(renderLoading, {})}
341
+ </KeyboardAvoidingView>
342
+ </View>
280
343
  </ActionSheetProvider>
281
344
  </GiftedChatContext.Provider>
282
345
  )
@@ -7,4 +7,7 @@ export default StyleSheet.create({
7
7
  contentContainer: {
8
8
  overflow: 'hidden',
9
9
  },
10
+ hidden: {
11
+ opacity: 0,
12
+ },
10
13
  })
@@ -9,6 +9,7 @@ import {
9
9
  ActionSheetOptions,
10
10
  } from '@expo/react-native-action-sheet'
11
11
  import { KeyboardProvider, KeyboardAvoidingViewProps } from 'react-native-keyboard-controller'
12
+
12
13
  import { ActionsProps } from '../Actions'
13
14
  import { AvatarProps } from '../Avatar'
14
15
  import { BubbleProps } from '../Bubble'
@@ -25,11 +26,12 @@ import {
25
26
  User,
26
27
  } from '../Models'
27
28
  import { QuickRepliesProps } from '../QuickReplies'
29
+ import { ReplyProps } from '../Reply'
28
30
  import { SendProps } from '../Send'
29
31
  import { SystemMessageProps } from '../SystemMessage'
30
32
  import { TimeProps } from '../Time'
31
33
 
32
- export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessagesContainerProps<TMessage>> {
34
+ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Omit<MessagesContainerProps<TMessage>, 'messageReplyContainerStyle'>> {
33
35
  /* Messages container ref */
34
36
  messagesContainerRef?: RefObject<AnimatedList<TMessage>>
35
37
  /* text input ref */
@@ -85,7 +87,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
85
87
  actionSheet?: () => {
86
88
  showActionSheetWithOptions: (
87
89
  options: ActionSheetOptions,
88
- callback: (buttonIndex: number) => void | Promise<void>,
90
+ callback: (buttonIndex: number) => void | Promise<void>
89
91
  ) => void
90
92
  }
91
93
  /* Callback when a message avatar is tapped */
@@ -140,11 +142,15 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
140
142
  /* Extra props to be passed to the MessageText component */
141
143
  messageTextProps?: Partial<MessageTextProps<TMessage>>
142
144
  renderQuickReplies?: (
143
- quickReplies: QuickRepliesProps<TMessage>,
145
+ quickReplies: QuickRepliesProps<TMessage>
144
146
  ) => React.ReactNode
145
147
  renderQuickReplySend?: () => React.ReactNode
146
148
  keyboardProviderProps?: React.ComponentProps<typeof KeyboardProvider>
149
+ /** Props for KeyboardAvoidingView. Use `keyboardVerticalOffset` to account for headers or iOS predictive text bar (~44pt). */
147
150
  keyboardAvoidingViewProps?: KeyboardAvoidingViewProps
148
151
  /** Enable animated day label that appears on scroll; default is true */
149
152
  isDayAnimationEnabled?: boolean
153
+
154
+ /** Reply functionality configuration */
155
+ reply?: ReplyProps<TMessage>
150
156
  }
@@ -1,15 +1,17 @@
1
- import React, { useMemo } from 'react'
2
- import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native'
1
+ import React, { useCallback, useMemo } from 'react'
2
+ import { StyleSheet, View, StyleProp, ViewStyle, TextStyle } from 'react-native'
3
3
 
4
4
  import { Actions, ActionsProps } from './Actions'
5
5
  import { Color } from './Color'
6
+ import { ReplyPreview, ReplyPreviewProps } from './components/ReplyPreview'
6
7
  import { Composer, ComposerProps } from './Composer'
7
8
  import { useColorScheme } from './hooks/useColorScheme'
8
- import { IMessage } from './Models'
9
+ import { IMessage, ReplyMessage } from './Models'
9
10
  import { Send, SendProps } from './Send'
10
- import { getColorSchemeStyle } from './styles'
11
11
  import { renderComponentOrElement } from './utils'
12
12
 
13
+ export type { ReplyPreviewProps } from './components/ReplyPreview'
14
+
13
15
  export interface InputToolbarProps<TMessage extends IMessage> {
14
16
  actions?: Array<{ title: string, action: () => void }>
15
17
  actionSheetOptionTintColor?: string
@@ -22,6 +24,16 @@ export interface InputToolbarProps<TMessage extends IMessage> {
22
24
  onPressActionButton?: () => void
23
25
  icon?: () => React.ReactNode
24
26
  wrapperStyle?: StyleProp<ViewStyle>
27
+ /** Reply message to show in preview */
28
+ replyMessage?: ReplyMessage | null
29
+ /** Callback to clear reply */
30
+ onClearReply?: () => void
31
+ /** Custom render for reply preview */
32
+ renderReplyPreview?: (props: ReplyPreviewProps) => React.ReactNode
33
+ /** Style for reply preview container */
34
+ replyPreviewContainerStyle?: StyleProp<ViewStyle>
35
+ /** Style for reply preview text */
36
+ replyPreviewTextStyle?: StyleProp<TextStyle>
25
37
  }
26
38
 
27
39
  export function InputToolbar<TMessage extends IMessage = IMessage> (
@@ -38,10 +50,26 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
38
50
  icon,
39
51
  wrapperStyle,
40
52
  containerStyle,
53
+ replyMessage,
54
+ onClearReply,
55
+ renderReplyPreview: renderReplyPreviewProp,
56
+ replyPreviewContainerStyle,
57
+ replyPreviewTextStyle,
41
58
  } = props
42
59
 
43
60
  const colorScheme = useColorScheme()
44
61
 
62
+ const containerStyles = useMemo(() => [
63
+ styles.container,
64
+ colorScheme === 'dark' && styles.container_dark,
65
+ containerStyle,
66
+ ], [colorScheme, containerStyle])
67
+
68
+ const primaryStyles = useMemo(() => [
69
+ styles.primary,
70
+ props.primaryStyle,
71
+ ], [props.primaryStyle])
72
+
45
73
  const actionsFragment = useMemo(() => {
46
74
  const actionsProps = {
47
75
  onPressActionButton,
@@ -92,11 +120,37 @@ export function InputToolbar<TMessage extends IMessage = IMessage> (
92
120
  return renderComponentOrElement(renderAccessory, props)
93
121
  }, [renderAccessory, props])
94
122
 
123
+ const handleClearReply = useCallback(() => {
124
+ onClearReply?.()
125
+ }, [onClearReply])
126
+
127
+ const replyPreviewFragment = useMemo(() => {
128
+ if (!replyMessage)
129
+ return null
130
+
131
+ const replyPreviewProps: ReplyPreviewProps = {
132
+ replyMessage,
133
+ onClearReply: handleClearReply,
134
+ containerStyle: replyPreviewContainerStyle,
135
+ textStyle: replyPreviewTextStyle,
136
+ }
137
+
138
+ if (renderReplyPreviewProp)
139
+ return renderComponentOrElement(renderReplyPreviewProp, replyPreviewProps)
140
+
141
+ return <ReplyPreview {...replyPreviewProps} />
142
+ }, [
143
+ replyMessage,
144
+ handleClearReply,
145
+ renderReplyPreviewProp,
146
+ replyPreviewContainerStyle,
147
+ replyPreviewTextStyle,
148
+ ])
149
+
95
150
  return (
96
- <View
97
- style={[getColorSchemeStyle(styles, 'container', colorScheme), containerStyle]}
98
- >
99
- <View style={[getColorSchemeStyle(styles, 'primary', colorScheme), props.primaryStyle]}>
151
+ <View style={containerStyles}>
152
+ {replyPreviewFragment}
153
+ <View style={primaryStyles}>
100
154
  {actionsFragment}
101
155
  {composerFragment}
102
156
  {sendFragment}