react-native-gifted-chat 3.2.3 → 3.3.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.
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.0",
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.28.0",
96
+ "react-native-keyboard-controller": "1.18.5",
97
+ "react-native-reanimated": "~4.1.1",
98
+ "react-native-safe-area-context": "~5.6.2",
99
+ "react-native-worklets": "0.5.1",
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
  }
@@ -8,6 +8,7 @@ import React, {
8
8
  RefObject,
9
9
  } from 'react'
10
10
  import {
11
+ Platform,
11
12
  View,
12
13
  LayoutChangeEvent,
13
14
  useColorScheme,
@@ -25,7 +26,7 @@ import { TEST_ID } from '../Constant'
25
26
  import { GiftedChatContext } from '../GiftedChatContext'
26
27
  import { InputToolbar } from '../InputToolbar'
27
28
  import { MessagesContainer, AnimatedList } from '../MessagesContainer'
28
- import { IMessage } from '../Models'
29
+ import { IMessage, ReplyMessage } from '../Models'
29
30
  import stylesCommon from '../styles'
30
31
  import { renderComponentOrElement } from '../utils'
31
32
  import styles from './styles'
@@ -33,6 +34,23 @@ import { GiftedChatProps } from './types'
33
34
 
34
35
  dayjs.extend(localizedFormat)
35
36
 
37
+ /**
38
+ * Default keyboard vertical offset values (similar to Stream Chat SDK)
39
+ * iOS: Compensates for predictive/suggestion text bar (~44-50pt) and headers
40
+ * Android: Negative offset to account for navigation bar in edge-to-edge mode
41
+ */
42
+ const DEFAULT_KEYBOARD_VERTICAL_OFFSET = Platform.select({
43
+ ios: 50,
44
+ android: 0,
45
+ default: 0,
46
+ })
47
+
48
+ const DEFAULT_KEYBOARD_BEHAVIOR = Platform.select({
49
+ ios: 'padding' as const,
50
+ android: 'padding' as const,
51
+ default: 'padding' as const,
52
+ })
53
+
36
54
  function GiftedChat<TMessage extends IMessage = IMessage> (
37
55
  props: GiftedChatProps<TMessage>
38
56
  ) {
@@ -56,8 +74,19 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
56
74
  renderChatFooter,
57
75
  renderInputToolbar,
58
76
  isInverted = true,
77
+
78
+ // Reply props
79
+ reply,
59
80
  } = props
60
81
 
82
+ // Extract reply props for internal use
83
+ const replyMessageProp = reply?.message
84
+ const onClearReply = reply?.onClear
85
+ const onSwipeToReply = reply?.swipe?.onSwipe
86
+ const renderReplyPreview = reply?.renderPreview
87
+ const replyPreviewContainerStyle = reply?.previewStyle?.containerStyle
88
+ const replyPreviewTextStyle = reply?.previewStyle?.textStyle
89
+
61
90
  const systemColorScheme = useColorScheme()
62
91
  const colorScheme = colorSchemeProp !== undefined ? colorSchemeProp : systemColorScheme
63
92
 
@@ -75,6 +104,10 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
75
104
 
76
105
  const [isInitialized, setIsInitialized] = useState<boolean>(false)
77
106
  const [text, setText] = useState<string | undefined>(() => props.text || '')
107
+ const [internalReplyMessage, setInternalReplyMessage] = useState<ReplyMessage | null>(null)
108
+
109
+ // Use controlled or uncontrolled reply state
110
+ const replyMessage = replyMessageProp !== undefined ? replyMessageProp : internalReplyMessage
78
111
 
79
112
  const getTextFromProp = useCallback(
80
113
  (fallback: string) => {
@@ -104,6 +137,31 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
104
137
  [isInverted, messagesContainerRef]
105
138
  )
106
139
 
140
+ const handleSwipeToReply = useCallback(
141
+ (message: TMessage) => {
142
+ if (replyMessageProp === undefined)
143
+ // Uncontrolled mode: manage state internally
144
+ setInternalReplyMessage({
145
+ _id: message._id,
146
+ text: message.text,
147
+ user: message.user,
148
+ image: message.image,
149
+ audio: message.audio,
150
+ })
151
+
152
+ onSwipeToReply?.(message)
153
+ },
154
+ [replyMessageProp, onSwipeToReply]
155
+ )
156
+
157
+ const clearReply = useCallback(() => {
158
+ if (replyMessageProp === undefined)
159
+ // Uncontrolled mode: manage state internally
160
+ setInternalReplyMessage(null)
161
+
162
+ onClearReply?.()
163
+ }, [replyMessageProp, onClearReply])
164
+
107
165
  const renderMessages = useMemo(() => {
108
166
  if (!isInitialized)
109
167
  return null
@@ -118,6 +176,13 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
118
176
  messages={messages}
119
177
  forwardRef={messagesContainerRef}
120
178
  isTyping={isTyping}
179
+ reply={{
180
+ ...reply,
181
+ swipe: reply?.swipe ? {
182
+ ...reply.swipe,
183
+ onSwipe: handleSwipeToReply,
184
+ } : undefined,
185
+ }}
121
186
  />
122
187
  {renderComponentOrElement(renderChatFooter, {})}
123
188
  </View>
@@ -130,6 +195,8 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
130
195
  isInverted,
131
196
  messagesContainerRef,
132
197
  renderChatFooter,
198
+ reply,
199
+ handleSwipeToReply,
133
200
  ])
134
201
 
135
202
  const notifyInputTextReset = useCallback(() => {
@@ -159,17 +226,22 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
159
226
  user: user!,
160
227
  createdAt: new Date(),
161
228
  _id: messageIdGenerator?.(),
229
+ // Attach reply message if exists
230
+ ...(replyMessage ? { replyMessage } : {}),
162
231
  }
163
232
  })
164
233
 
165
234
  if (shouldResetInputToolbar === true)
166
235
  resetInputToolbar()
167
236
 
237
+ // Clear reply after sending
238
+ clearReply()
239
+
168
240
  onSend?.(newMessages)
169
241
 
170
242
  setTimeout(() => scrollToBottom(), 10)
171
243
  },
172
- [messageIdGenerator, onSend, user, resetInputToolbar, scrollToBottom]
244
+ [messageIdGenerator, onSend, user, resetInputToolbar, scrollToBottom, replyMessage, clearReply]
173
245
  )
174
246
 
175
247
  const _onChangeText = useCallback(
@@ -214,6 +286,12 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
214
286
  onChangeText: _onChangeText,
215
287
  ref: textInputRef,
216
288
  },
289
+ // Reply preview props
290
+ replyMessage,
291
+ onClearReply: clearReply,
292
+ renderReplyPreview,
293
+ replyPreviewContainerStyle,
294
+ replyPreviewTextStyle,
217
295
  }
218
296
 
219
297
  if (renderInputToolbar)
@@ -230,6 +308,11 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
230
308
  textInputRef,
231
309
  textInputProps,
232
310
  _onChangeText,
311
+ replyMessage,
312
+ clearReply,
313
+ renderReplyPreview,
314
+ replyPreviewContainerStyle,
315
+ replyPreviewTextStyle,
233
316
  ])
234
317
 
235
318
  const contextValues = useMemo(
@@ -254,29 +337,32 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
254
337
  return (
255
338
  <GiftedChatContext.Provider value={contextValues}>
256
339
  <ActionSheetProvider ref={actionSheetRef}>
257
- {/* @ts-expect-error */}
258
- <KeyboardAvoidingView
259
- behavior='padding'
260
- style={stylesCommon.fill}
261
- {...props.keyboardAvoidingViewProps}
340
+ <View
341
+ testID={TEST_ID.WRAPPER}
342
+ style={[stylesCommon.fill, styles.contentContainer]}
343
+ onLayout={onInitialLayoutViewLayout}
262
344
  >
263
- <View
264
- testID={TEST_ID.WRAPPER}
265
- style={[stylesCommon.fill, styles.contentContainer]}
266
- onLayout={onInitialLayoutViewLayout}
345
+ {/* @ts-expect-error */}
346
+ <KeyboardAvoidingView
347
+ behavior={DEFAULT_KEYBOARD_BEHAVIOR}
348
+ keyboardVerticalOffset={DEFAULT_KEYBOARD_VERTICAL_OFFSET}
349
+ style={stylesCommon.fill}
350
+ {...props.keyboardAvoidingViewProps}
267
351
  >
268
- {isInitialized
269
- ? (
270
- <>
271
- {renderMessages}
272
- {inputToolbarFragment}
273
- </>
274
- )
275
- : (
276
- renderComponentOrElement(renderLoading, {})
277
- )}
278
- </View>
279
- </KeyboardAvoidingView>
352
+ <View style={stylesCommon.fill}>
353
+ {isInitialized
354
+ ? (
355
+ <>
356
+ {renderMessages}
357
+ {inputToolbarFragment}
358
+ </>
359
+ )
360
+ : (
361
+ renderComponentOrElement(renderLoading, {})
362
+ )}
363
+ </View>
364
+ </KeyboardAvoidingView>
365
+ </View>
280
366
  </ActionSheetProvider>
281
367
  </GiftedChatContext.Provider>
282
368
  )
@@ -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}