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/README.md +487 -165
- package/package.json +9 -8
- package/src/Bubble/index.tsx +34 -2
- package/src/Bubble/types.ts +17 -4
- package/src/Day/index.tsx +2 -2
- package/src/Day/types.ts +3 -2
- package/src/GiftedChat/index.tsx +87 -24
- package/src/GiftedChat/styles.ts +3 -0
- package/src/GiftedChat/types.ts +9 -3
- package/src/InputToolbar.tsx +62 -8
- package/src/Message/index.tsx +181 -21
- package/src/Message/types.ts +4 -0
- package/src/MessageReply.tsx +160 -0
- package/src/MessagesContainer/components/Item/index.tsx +17 -3
- package/src/MessagesContainer/index.tsx +16 -11
- package/src/MessagesContainer/types.ts +26 -3
- package/src/Models.ts +3 -0
- package/src/Reply/index.ts +1 -0
- package/src/Reply/types.ts +80 -0
- package/src/ReplyPreview.tsx +132 -0
- package/src/Send.tsx +8 -3
- package/src/__tests__/MessageReply.test.tsx +54 -0
- package/src/__tests__/ReplyPreview.test.tsx +41 -0
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +87 -45
- package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +10 -36
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +18 -102
- package/src/__tests__/__snapshots__/MessageReply.test.tsx.snap +181 -0
- package/src/__tests__/__snapshots__/ReplyPreview.test.tsx.snap +349 -0
- package/src/__tests__/__snapshots__/Send.test.tsx.snap +0 -63
- package/src/components/MessageReply.tsx +156 -0
- package/src/components/ReplyPreview.tsx +230 -0
- package/src/index.ts +6 -1
- package/src/types.ts +17 -16
- package/src/utils.ts +16 -3
package/README.md
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
<h3 align="center">
|
|
2
|
-
đŦ Gifted Chat
|
|
3
|
-
</h3>
|
|
4
1
|
<p align="center">
|
|
5
|
-
The most complete chat UI for React Native & Web
|
|
6
|
-
</p>
|
|
7
|
-
<p align="center">
|
|
8
|
-
<a href="https://www.npmjs.com/package/react-native-gifted-chat">
|
|
9
|
-
<img alt="npm downloads" src="https://img.shields.io/npm/dm/react-native-gifted-chat.svg"/></a>
|
|
10
2
|
<a href="https://www.npmjs.com/package/react-native-gifted-chat"><img alt="npm version" src="https://badge.fury.io/js/react-native-gifted-chat.svg"/></a>
|
|
11
|
-
|
|
3
|
+
<a href="https://www.npmjs.com/package/react-native-gifted-chat"><img alt="npm downloads" src="https://img.shields.io/npm/dm/react-native-gifted-chat.svg"/></a>
|
|
4
|
+
<a href="https://circleci.com/gh/FaridSafi/react-native-gifted-chat"><img src="https://circleci.com/gh/FaridSafi/react-native-gifted-chat.svg?style=shield" alt="build"></a>
|
|
5
|
+
<img src="https://img.shields.io/badge/platforms-iOS%20%7C%20Android%20%7C%20Web-lightgrey.svg" alt="platforms">
|
|
6
|
+
<img src="https://img.shields.io/badge/TypeScript-supported-blue.svg" alt="TypeScript">
|
|
7
|
+
<img src="https://img.shields.io/badge/Expo-compatible-000020.svg" alt="Expo compatible">
|
|
12
8
|
</p>
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
<h1 align="center">React Native Gifted Chat</h1>
|
|
15
11
|
|
|
16
|
-
<h3 align="center">
|
|
17
|
-
đ Try it now in your browser!
|
|
18
|
-
</h3>
|
|
19
12
|
<p align="center">
|
|
20
|
-
|
|
21
|
-
<img src="https://img.shields.io/badge/âļī¸_Try_GiftedChat_Playground-4630EB?style=for-the-badge&logo=expo&logoColor=white" alt="Try GiftedChat on Expo Snack"/>
|
|
22
|
-
</a>
|
|
13
|
+
The most complete chat UI for React Native & Web
|
|
23
14
|
</p>
|
|
15
|
+
|
|
24
16
|
<p align="center">
|
|
25
|
-
<
|
|
17
|
+
<a href="https://snack.expo.dev/@kesha-antonov/gifted-chat-playground" target="_blank">
|
|
18
|
+
<img src="https://img.shields.io/badge/âļī¸_Try_in_Browser-4630EB?style=for-the-badge&logo=expo&logoColor=white" alt="Try GiftedChat on Expo Snack"/>
|
|
19
|
+
</a>
|
|
26
20
|
</p>
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
---
|
|
29
23
|
|
|
30
|
-
|
|
24
|
+
## ⨠Features
|
|
25
|
+
|
|
26
|
+
- đ¨ **Fully Customizable** - Override any component with your own implementation
|
|
27
|
+
- đ **Composer Actions** - Attach photos, files, or trigger custom actions
|
|
28
|
+
- âŠī¸ **Reply to Messages** - Swipe-to-reply with reply preview and message threading
|
|
29
|
+
- âŽī¸ **Load Earlier Messages** - Infinite scroll with pagination support
|
|
30
|
+
- đ **Copy to Clipboard** - Long-press messages to copy text
|
|
31
|
+
- đ **Smart Link Parsing** - Auto-detect URLs, emails, phone numbers, hashtags, mentions
|
|
32
|
+
- đ¤ **Avatars** - User initials or custom avatar images
|
|
33
|
+
- đ **Localized Dates** - Full i18n support via Day.js
|
|
34
|
+
- â¨ī¸ **Keyboard Handling** - Smart keyboard avoidance for all platforms
|
|
35
|
+
- đŦ **System Messages** - Display system notifications in chat
|
|
36
|
+
- ⥠**Quick Replies** - Bot-style quick reply buttons
|
|
37
|
+
- âī¸ **Typing Indicator** - Show when users are typing
|
|
38
|
+
- â
**Message Status** - Tick indicators for sent/delivered/read states
|
|
39
|
+
- âŦī¸ **Scroll to Bottom** - Quick navigation button
|
|
40
|
+
- đ **Web Support** - Works with react-native-web
|
|
41
|
+
- đą **Expo Support** - Easy integration with Expo projects
|
|
42
|
+
- đ **TypeScript** - Complete TypeScript definitions included
|
|
31
43
|
|
|
32
44
|
<p align="center">
|
|
33
45
|
<img width="200" src="https://github.com/user-attachments/assets/c9da88f5-0b20-471c-8cd7-373bdb767517" />
|
|
@@ -39,124 +51,84 @@
|
|
|
39
51
|
|
|
40
52
|
---
|
|
41
53
|
|
|
42
|
-
##
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
- Ticks indicator to display message status ( delivered, read )
|
|
57
|
-
- Scroll to bottom button
|
|
58
|
-
- react-native-web [web configuration](#react-native-web)
|
|
59
|
-
|
|
60
|
-
## Sponsor
|
|
54
|
+
## đ Table of Contents
|
|
55
|
+
|
|
56
|
+
- [Features](#-features)
|
|
57
|
+
- [Requirements](#-requirements)
|
|
58
|
+
- [Installation](#-installation)
|
|
59
|
+
- [Usage](#-usage)
|
|
60
|
+
- [Props Reference](#-props-reference)
|
|
61
|
+
- [Data Structure](#-data-structure)
|
|
62
|
+
- [Platform Notes](#-platform-notes)
|
|
63
|
+
- [Example App](#-example-app)
|
|
64
|
+
- [Troubleshooting](#-troubleshooting)
|
|
65
|
+
- [Contributing](#-contributing)
|
|
66
|
+
- [Authors](#-authors)
|
|
67
|
+
- [License](#-license)
|
|
61
68
|
|
|
62
|
-
|
|
63
|
-
<br/>
|
|
64
|
-
<a href="https://www.lereacteur.io" target="_blank">
|
|
65
|
-
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/logo_sponsor.png" height="60">
|
|
66
|
-
</a>
|
|
67
|
-
<br>
|
|
68
|
-
<p align="center">
|
|
69
|
-
Coding Bootcamp in Paris co-founded by Farid Safi
|
|
70
|
-
</p>
|
|
71
|
-
<a href="https://www.lereacteur.io" target="_blank">
|
|
72
|
-
<p align="center">
|
|
73
|
-
Click to learn more
|
|
74
|
-
</p>
|
|
75
|
-
</a>
|
|
76
|
-
</p>
|
|
69
|
+
---
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
<br/>
|
|
80
|
-
<a href="https://getstream.io/chat/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_Chat&utm_term=react-native-gifted-chat" target="_blank">
|
|
81
|
-
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/stream-logo.png" height="40">
|
|
82
|
-
</a>
|
|
83
|
-
<br>
|
|
84
|
-
<p align="center">
|
|
85
|
-
Scalable <a href="https://getstream.io/chat/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_Chat&utm_term=react-native-gifted-chat" target="_blank">chat API/Server</a> written in Go
|
|
86
|
-
</p>
|
|
87
|
-
<p align="center">
|
|
88
|
-
<a href="https://getstream.io/chat/get_started/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_Chat&utm_term=react-native-gifted-chat" target="_blank">API Tour</a> | <a href="https://dev.to/nickparsons/react-native-chat-with-chuck-norris-3h7m?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_Chat&utm_term=react-native-gifted-chat" target="_blank">React Native Gifted tutorial</a>
|
|
89
|
-
</p>
|
|
90
|
-
</p>
|
|
71
|
+
## đ Requirements
|
|
91
72
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
A complete app engine featuring GiftedChat
|
|
100
|
-
</p>
|
|
101
|
-
<p align="center">
|
|
102
|
-
<a href="https://bit.ly/ethorachat" target="_blank">Check out our GitHub</a>
|
|
103
|
-
</p>
|
|
104
|
-
</p>
|
|
105
|
-
<br>
|
|
106
|
-
<p align="center">
|
|
107
|
-
<a href="https://amzn.to/3ZmTyb2" target="_blank">React Key Concepts: Consolidate your knowledge of Reactâs core features (2nd ed. Edition)</a>
|
|
108
|
-
</p>
|
|
73
|
+
| Requirement | Version |
|
|
74
|
+
|-------------|---------|
|
|
75
|
+
| React Native | >= 0.70.0 |
|
|
76
|
+
| iOS | >= 13.4 |
|
|
77
|
+
| Android | API 21+ (Android 5.0) |
|
|
78
|
+
| Expo | SDK 50+ |
|
|
79
|
+
| TypeScript | >= 5.0 (optional) |
|
|
109
80
|
|
|
110
|
-
|
|
81
|
+
---
|
|
111
82
|
|
|
112
|
-
## Installation
|
|
83
|
+
## đĻ Installation
|
|
113
84
|
|
|
114
|
-
###
|
|
85
|
+
### Expo Projects
|
|
115
86
|
|
|
116
|
-
Yarn:
|
|
117
87
|
```bash
|
|
118
|
-
|
|
88
|
+
npx expo install react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
119
89
|
```
|
|
120
90
|
|
|
121
|
-
|
|
91
|
+
### Bare React Native Projects
|
|
92
|
+
|
|
93
|
+
**Step 1:** Install the packages
|
|
122
94
|
|
|
95
|
+
Using yarn:
|
|
123
96
|
```bash
|
|
124
|
-
|
|
97
|
+
yarn add react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
125
98
|
```
|
|
126
99
|
|
|
127
|
-
|
|
100
|
+
Using npm:
|
|
128
101
|
```bash
|
|
129
|
-
|
|
102
|
+
npm install --save react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
130
103
|
```
|
|
131
104
|
|
|
132
|
-
|
|
105
|
+
**Step 2:** Install iOS pods
|
|
133
106
|
|
|
134
107
|
```bash
|
|
135
108
|
npx pod-install
|
|
136
109
|
```
|
|
137
110
|
|
|
138
|
-
|
|
111
|
+
**Step 3:** Configure react-native-reanimated
|
|
139
112
|
|
|
140
|
-
Follow
|
|
113
|
+
Follow the [react-native-reanimated installation guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#step-2-add-reanimateds-babel-plugin) to add the Babel plugin.
|
|
114
|
+
|
|
115
|
+
---
|
|
141
116
|
|
|
142
|
-
##
|
|
117
|
+
## đ Usage
|
|
143
118
|
|
|
144
|
-
### Basic
|
|
119
|
+
### Basic Example
|
|
145
120
|
|
|
146
121
|
```jsx
|
|
147
122
|
import React, { useState, useCallback, useEffect } from 'react'
|
|
148
|
-
import { Platform } from 'react-native'
|
|
149
123
|
import { GiftedChat } from 'react-native-gifted-chat'
|
|
150
|
-
import {
|
|
124
|
+
import { useHeaderHeight } from '@react-navigation/elements'
|
|
151
125
|
|
|
152
126
|
export function Example() {
|
|
153
127
|
const [messages, setMessages] = useState([])
|
|
154
|
-
const insets = useSafeAreaInsets()
|
|
155
128
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
const keyboardVerticalOffset = insets.bottom + tabbarHeight + keyboardTopToolbarHeight
|
|
129
|
+
// keyboardVerticalOffset = distance from screen top to GiftedChat container
|
|
130
|
+
// useHeaderHeight() returns status bar + navigation header height
|
|
131
|
+
const headerHeight = useHeaderHeight()
|
|
160
132
|
|
|
161
133
|
useEffect(() => {
|
|
162
134
|
setMessages([
|
|
@@ -186,22 +158,51 @@ export function Example() {
|
|
|
186
158
|
user={{
|
|
187
159
|
_id: 1,
|
|
188
160
|
}}
|
|
189
|
-
|
|
190
|
-
keyboardAvoidingViewProps={{ keyboardVerticalOffset }}
|
|
161
|
+
keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
|
|
191
162
|
/>
|
|
192
163
|
)
|
|
193
164
|
}
|
|
194
165
|
```
|
|
195
166
|
|
|
196
|
-
|
|
167
|
+
> **đĄ Tip:** Check out more examples in the [`example`](example) directory including Slack-style messages, quick replies, and custom components.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## đ Data Structure
|
|
172
|
+
|
|
173
|
+
Messages, system messages, and quick replies follow the structure defined in [Models.ts](src/Models.ts).
|
|
174
|
+
|
|
175
|
+
<details>
|
|
176
|
+
<summary><strong>Message Object Structure</strong></summary>
|
|
197
177
|
|
|
198
|
-
|
|
178
|
+
```typescript
|
|
179
|
+
interface IMessage {
|
|
180
|
+
_id: string | number
|
|
181
|
+
text: string
|
|
182
|
+
createdAt: Date | number
|
|
183
|
+
user: User
|
|
184
|
+
image?: string
|
|
185
|
+
video?: string
|
|
186
|
+
audio?: string
|
|
187
|
+
system?: boolean
|
|
188
|
+
sent?: boolean
|
|
189
|
+
received?: boolean
|
|
190
|
+
pending?: boolean
|
|
191
|
+
quickReplies?: QuickReplies
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface User {
|
|
195
|
+
_id: string | number
|
|
196
|
+
name?: string
|
|
197
|
+
avatar?: string | number | (() => React.ReactNode)
|
|
198
|
+
}
|
|
199
|
+
```
|
|
199
200
|
|
|
200
|
-
|
|
201
|
+
</details>
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
---
|
|
203
204
|
|
|
204
|
-
## Props
|
|
205
|
+
## đ Props Reference
|
|
205
206
|
|
|
206
207
|
### Core Configuration
|
|
207
208
|
|
|
@@ -219,16 +220,51 @@ Messages, system messages, quick replies etc.: [data structure](src/Models.ts)
|
|
|
219
220
|
|
|
220
221
|
### Keyboard & Layout
|
|
221
222
|
|
|
222
|
-
- **`keyboardProviderProps`** _(Object)_ - Props to be passed to the [`KeyboardProvider`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-provider) for keyboard handling.
|
|
223
|
-
-
|
|
223
|
+
- **`keyboardProviderProps`** _(Object)_ - Props to be passed to the [`KeyboardProvider`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-provider) for keyboard handling. Default values:
|
|
224
|
+
- `statusBarTranslucent: true` - Required on Android for correct keyboard height calculation when status bar is translucent (edge-to-edge mode)
|
|
225
|
+
- `navigationBarTranslucent: true` - Required on Android for correct keyboard height calculation when navigation bar is translucent (edge-to-edge mode)
|
|
226
|
+
- **`keyboardAvoidingViewProps`** _(Object)_ - Props to be passed to the [`KeyboardAvoidingView`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view). See **keyboardVerticalOffset** below for proper keyboard handling.
|
|
224
227
|
- **`isAlignedTop`** _(Boolean)_ Controls whether or not the message bubbles appear at the top of the chat (Default is false - bubbles align to bottom)
|
|
225
228
|
- **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
|
|
226
229
|
|
|
230
|
+
#### Understanding `keyboardVerticalOffset`
|
|
231
|
+
|
|
232
|
+
The [`keyboardVerticalOffset`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view#keyboardverticaloffset) tells the KeyboardAvoidingView where its container starts relative to the top of the screen. This is essential when GiftedChat is not positioned at the very top of the screen (e.g., when you have a navigation header).
|
|
233
|
+
|
|
234
|
+
**Default value:** `insets.top` (status bar height from `useSafeAreaInsets()`). This works correctly only when GiftedChat fills the entire screen without a navigation header. If you have a navigation header, you need to pass the correct offset via `keyboardAvoidingViewProps`.
|
|
235
|
+
|
|
236
|
+
**What the value means:** The offset equals the distance (in points) from the top of the screen to the top of your GiftedChat container. This typically includes:
|
|
237
|
+
- Status bar height
|
|
238
|
+
- Navigation header height (on iOS, `useHeaderHeight()` already includes status bar)
|
|
239
|
+
|
|
240
|
+
**How to use:**
|
|
241
|
+
|
|
242
|
+
```jsx
|
|
243
|
+
import { useHeaderHeight } from '@react-navigation/elements'
|
|
244
|
+
|
|
245
|
+
function ChatScreen() {
|
|
246
|
+
// useHeaderHeight() returns status bar + navigation header height on iOS
|
|
247
|
+
const headerHeight = useHeaderHeight()
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<GiftedChat
|
|
251
|
+
keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
|
|
252
|
+
// ... other props
|
|
253
|
+
/>
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
> **Note:** `useHeaderHeight()` requires your chat component to be rendered inside a proper navigation screen (not conditional rendering). If it returns `0`, ensure your chat screen is a real navigation screen with a visible header.
|
|
259
|
+
|
|
260
|
+
**Why this matters:** Without the correct offset, the keyboard may overlap the input field or leave extra space. The KeyboardAvoidingView uses this value to calculate how much to shift the content when the keyboard appears.
|
|
261
|
+
|
|
227
262
|
### Text Input & Composer
|
|
228
263
|
|
|
229
264
|
- **`text`** _(String)_ - Input text; default is `undefined`, but if specified, it will override GiftedChat's internal state. Useful for managing text state outside of GiftedChat (e.g. with Redux). Don't forget to implement `textInputProps.onChangeText` to update the text state.
|
|
230
265
|
- **`initialText`** _(String)_ - Initial text to display in the input field
|
|
231
266
|
- **`isSendButtonAlwaysVisible`** _(Bool)_ - Always show send button in input text composer; default `false`, show only when text input is not empty
|
|
267
|
+
- **`isTextOptional`** _(Bool)_ - Allow sending messages without text (useful for media-only messages); default `false`. Use with `isSendButtonAlwaysVisible` for media attachments.
|
|
232
268
|
- **`minComposerHeight`** _(Object)_ - Custom min-height of the composer.
|
|
233
269
|
- **`maxComposerHeight`** _(Object)_ - Custom max height of the composer.
|
|
234
270
|
- **`minInputToolbarHeight`** _(Integer)_ - Minimum height of the input toolbar; default is `44`
|
|
@@ -253,7 +289,7 @@ Messages, system messages, quick replies etc.: [data structure](src/Models.ts)
|
|
|
253
289
|
- **`renderLoading`** _(Component | Function)_ - Render a loading view when initializing
|
|
254
290
|
- **`renderChatEmpty`** _(Component | Function)_ - Custom component to render in the ListView when messages are empty
|
|
255
291
|
- **`renderChatFooter`** _(Component | Function)_ - Custom component to render below the MessagesContainer (separate from the ListView)
|
|
256
|
-
- **`listProps`** _(Object)_ - Extra props to be passed to the messages [`<FlatList>`](https://reactnative.dev/docs/flatlist)
|
|
292
|
+
- **`listProps`** _(Object)_ - Extra props to be passed to the messages [`<FlatList>`](https://reactnative.dev/docs/flatlist). Supports all FlatList props including `maintainVisibleContentPosition` for keeping scroll position when new messages arrive (useful for AI chatbots).
|
|
257
293
|
|
|
258
294
|
### Message Bubbles & Content
|
|
259
295
|
|
|
@@ -352,6 +388,10 @@ See full example in [LinksExample](example/components/chat-examples/LinksExample
|
|
|
352
388
|
- **`dateFormat`** _(String)_ - Format to use for rendering dates; default is `'D MMMM'` (see [Day.js Format](https://day.js.org/docs/en/display/format))
|
|
353
389
|
- **`dateFormatCalendar`** _(Object)_ - Format to use for rendering relative times; default is `{ sameDay: '[Today]' }` (see [Day.js Calendar](https://day.js.org/docs/en/plugin/calendar))
|
|
354
390
|
- **`renderDay`** _(Component | Function)_ - Custom day above a message
|
|
391
|
+
- **`dayProps`** _(Object)_ - Props to pass to the Day component:
|
|
392
|
+
- `containerStyle` - Custom style for the day container
|
|
393
|
+
- `wrapperStyle` - Custom style for the day wrapper
|
|
394
|
+
- `textProps` - Props to pass to the Text component (e.g., `style`, `allowFontScaling`, `numberOfLines`)
|
|
355
395
|
- **`renderTime`** _(Component | Function)_ - Custom time inside a message
|
|
356
396
|
- **`timeTextStyle`** _(Object)_ - Custom text style for time inside messages (supports left/right styles)
|
|
357
397
|
- **`isDayAnimationEnabled`** _(Bool)_ - Enable animated day label that appears on scroll; default is `true`
|
|
@@ -394,46 +434,214 @@ See [Quick Replies example in messages.ts](example/example-expo/data/messages.ts
|
|
|
394
434
|
- **`quickReplyContainerStyle`** _(StyleProp<ViewStyle>)_ - Custom container style for quick replies
|
|
395
435
|
- **`renderQuickReplySend`** _(Function)_ - Custom quick reply **send** view
|
|
396
436
|
|
|
437
|
+
### Reply to Messages
|
|
438
|
+
|
|
439
|
+
Gifted Chat supports swipe-to-reply functionality out of the box. When enabled, users can swipe on a message to reply to it, displaying a reply preview in the input toolbar and the replied message above the new message bubble.
|
|
440
|
+
|
|
441
|
+
> **Note:** This feature uses `ReanimatedSwipeable` from `react-native-gesture-handler` and `react-native-reanimated` for smooth, performant animations.
|
|
442
|
+
|
|
443
|
+
#### Basic Usage
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
<GiftedChat
|
|
447
|
+
messages={messages}
|
|
448
|
+
onSend={onSend}
|
|
449
|
+
user={{ _id: 1 }}
|
|
450
|
+
reply={{
|
|
451
|
+
swipe: {
|
|
452
|
+
isEnabled: true,
|
|
453
|
+
direction: 'left', // swipe left to reply
|
|
454
|
+
},
|
|
455
|
+
}}
|
|
456
|
+
/>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### Reply Props (Grouped)
|
|
460
|
+
|
|
461
|
+
The `reply` prop accepts an object with the following structure:
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
interface ReplyProps<TMessage> {
|
|
465
|
+
// Swipe gesture configuration
|
|
466
|
+
swipe?: {
|
|
467
|
+
isEnabled?: boolean // Enable swipe-to-reply; default false
|
|
468
|
+
direction?: 'left' | 'right' // Swipe direction; default 'left'
|
|
469
|
+
onSwipe?: (message: TMessage) => void // Callback when swiped
|
|
470
|
+
renderAction?: ( // Custom swipe action component
|
|
471
|
+
progress: SharedValue<number>,
|
|
472
|
+
translation: SharedValue<number>,
|
|
473
|
+
position: 'left' | 'right'
|
|
474
|
+
) => React.ReactNode
|
|
475
|
+
actionContainerStyle?: StyleProp<ViewStyle>
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Reply preview styling (above input toolbar)
|
|
479
|
+
previewStyle?: {
|
|
480
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
481
|
+
textStyle?: StyleProp<TextStyle>
|
|
482
|
+
imageStyle?: StyleProp<ImageStyle>
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// In-bubble reply styling
|
|
486
|
+
messageStyle?: {
|
|
487
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
488
|
+
containerStyleLeft?: StyleProp<ViewStyle>
|
|
489
|
+
containerStyleRight?: StyleProp<ViewStyle>
|
|
490
|
+
textStyle?: StyleProp<TextStyle>
|
|
491
|
+
textStyleLeft?: StyleProp<TextStyle>
|
|
492
|
+
textStyleRight?: StyleProp<TextStyle>
|
|
493
|
+
imageStyle?: StyleProp<ImageStyle>
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Callbacks and state
|
|
497
|
+
message?: ReplyMessage // Controlled reply state
|
|
498
|
+
onClear?: () => void // Called when reply cleared
|
|
499
|
+
onPress?: (message: TMessage) => void // Called when reply preview tapped
|
|
500
|
+
|
|
501
|
+
// Custom renderers
|
|
502
|
+
renderPreview?: (props: ReplyPreviewProps) => React.ReactNode
|
|
503
|
+
renderMessageReply?: (props: MessageReplyProps) => React.ReactNode
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
#### ReplyMessage Structure
|
|
508
|
+
|
|
509
|
+
When a message has a reply, it includes a `replyMessage` property:
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
interface ReplyMessage {
|
|
513
|
+
_id: string | number
|
|
514
|
+
text: string
|
|
515
|
+
user: User
|
|
516
|
+
image?: string
|
|
517
|
+
audio?: string
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
#### Advanced Example with External State
|
|
522
|
+
|
|
523
|
+
```tsx
|
|
524
|
+
const [replyMessage, setReplyMessage] = useState<ReplyMessage | null>(null)
|
|
525
|
+
|
|
526
|
+
<GiftedChat
|
|
527
|
+
messages={messages}
|
|
528
|
+
onSend={messages => {
|
|
529
|
+
const newMessages = messages.map(msg => ({
|
|
530
|
+
...msg,
|
|
531
|
+
replyMessage: replyMessage || undefined,
|
|
532
|
+
}))
|
|
533
|
+
setMessages(prev => GiftedChat.append(prev, newMessages))
|
|
534
|
+
setReplyMessage(null)
|
|
535
|
+
}}
|
|
536
|
+
user={{ _id: 1 }}
|
|
537
|
+
reply={{
|
|
538
|
+
swipe: {
|
|
539
|
+
isEnabled: true,
|
|
540
|
+
direction: 'right',
|
|
541
|
+
onSwipe: setReplyMessage,
|
|
542
|
+
},
|
|
543
|
+
message: replyMessage,
|
|
544
|
+
onClear: () => setReplyMessage(null),
|
|
545
|
+
onPress: (msg) => scrollToMessage(msg._id),
|
|
546
|
+
}}
|
|
547
|
+
/>
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
#### Smooth Animations
|
|
551
|
+
|
|
552
|
+
The reply preview automatically animates when:
|
|
553
|
+
- **Appearing**: Smoothly expands from zero height with fade-in effect
|
|
554
|
+
- **Disappearing**: Smoothly collapses with fade-out effect
|
|
555
|
+
- **Content changes**: Smoothly transitions when replying to a different message
|
|
556
|
+
|
|
557
|
+
These animations use `react-native-reanimated` for 60fps performance.
|
|
558
|
+
|
|
397
559
|
### Scroll to Bottom
|
|
398
560
|
|
|
399
561
|
- **`isScrollToBottomEnabled`** _(Bool)_ - Enables the scroll to bottom Component (Default is false)
|
|
400
562
|
- **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
|
|
401
563
|
- **`scrollToBottomOffset`** _(Integer)_ - Custom Height Offset upon which to begin showing Scroll To Bottom Component (Default is 200)
|
|
402
|
-
- **`scrollToBottomStyle`** _(Object)_ - Custom style for Bottom
|
|
564
|
+
- **`scrollToBottomStyle`** _(Object)_ - Custom style for Scroll To Bottom wrapper (position, bottom, right, etc.)
|
|
565
|
+
- **`scrollToBottomContentStyle`** _(Object)_ - Custom style for Scroll To Bottom content (size, background, shadow, etc.)
|
|
403
566
|
|
|
404
|
-
|
|
567
|
+
### Maintaining Scroll Position (AI Chatbots)
|
|
405
568
|
|
|
406
|
-
|
|
569
|
+
For AI chat interfaces where long responses arrive and you don't want to disrupt the user's reading position, use [`maintainVisibleContentPosition`](https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition) via `listProps`:
|
|
407
570
|
|
|
408
|
-
|
|
571
|
+
```tsx
|
|
572
|
+
// Basic usage - always maintain scroll position
|
|
573
|
+
<GiftedChat
|
|
574
|
+
listProps={{
|
|
575
|
+
maintainVisibleContentPosition: {
|
|
576
|
+
minIndexForVisible: 0,
|
|
577
|
+
},
|
|
578
|
+
}}
|
|
579
|
+
/>
|
|
409
580
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
581
|
+
// With auto-scroll threshold - auto-scroll if within 10 pixels of newest content
|
|
582
|
+
<GiftedChat
|
|
583
|
+
listProps={{
|
|
584
|
+
maintainVisibleContentPosition: {
|
|
585
|
+
minIndexForVisible: 0,
|
|
586
|
+
autoscrollToTopThreshold: 10,
|
|
587
|
+
},
|
|
588
|
+
}}
|
|
589
|
+
/>
|
|
417
590
|
|
|
418
|
-
|
|
591
|
+
// Conditionally enable based on scroll state (recommended for chatbots)
|
|
592
|
+
const [isScrolledUp, setIsScrolledUp] = useState(false)
|
|
419
593
|
|
|
420
|
-
|
|
594
|
+
<GiftedChat
|
|
595
|
+
listProps={{
|
|
596
|
+
onScroll: (event) => {
|
|
597
|
+
setIsScrolledUp(event.contentOffset.y > 50)
|
|
598
|
+
},
|
|
599
|
+
maintainVisibleContentPosition: isScrolledUp
|
|
600
|
+
? { minIndexForVisible: 0, autoscrollToTopThreshold: 10 }
|
|
601
|
+
: undefined,
|
|
602
|
+
}}
|
|
603
|
+
/>
|
|
604
|
+
```
|
|
421
605
|
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## đą Platform Notes
|
|
609
|
+
|
|
610
|
+
### Android
|
|
611
|
+
|
|
612
|
+
<details>
|
|
613
|
+
<summary><strong>Keyboard configuration</strong></summary>
|
|
614
|
+
|
|
615
|
+
If you are using Create React Native App / Expo, no Android specific installation steps are required. Otherwise, we recommend modifying your project configuration:
|
|
616
|
+
|
|
617
|
+
Make sure you have `android:windowSoftInputMode="adjustResize"` in your `AndroidManifest.xml`:
|
|
618
|
+
|
|
619
|
+
```xml
|
|
620
|
+
<activity
|
|
621
|
+
android:name=".MainActivity"
|
|
622
|
+
android:label="@string/app_name"
|
|
623
|
+
android:windowSoftInputMode="adjustResize"
|
|
624
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
|
422
625
|
```
|
|
626
|
+
|
|
627
|
+
For **Expo**, you can append `KeyboardAvoidingView` after GiftedChat (Android only):
|
|
628
|
+
|
|
629
|
+
```jsx
|
|
423
630
|
<View style={{ flex: 1 }}>
|
|
424
631
|
<GiftedChat />
|
|
425
|
-
{
|
|
426
|
-
Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />
|
|
427
|
-
}
|
|
632
|
+
{Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />}
|
|
428
633
|
</View>
|
|
429
634
|
```
|
|
430
635
|
|
|
431
|
-
|
|
636
|
+
</details>
|
|
637
|
+
|
|
638
|
+
### Web (react-native-web)
|
|
432
639
|
|
|
433
|
-
|
|
640
|
+
<details>
|
|
641
|
+
<summary><strong>With create-react-app</strong></summary>
|
|
434
642
|
|
|
435
|
-
1. `yarn add -D react-app-rewired`
|
|
436
|
-
2. `
|
|
643
|
+
1. Install react-app-rewired: `yarn add -D react-app-rewired`
|
|
644
|
+
2. Create `config-overrides.js`:
|
|
437
645
|
|
|
438
646
|
```js
|
|
439
647
|
module.exports = function override(config, env) {
|
|
@@ -453,23 +661,30 @@ module.exports = function override(config, env) {
|
|
|
453
661
|
},
|
|
454
662
|
},
|
|
455
663
|
})
|
|
456
|
-
|
|
457
664
|
return config
|
|
458
665
|
}
|
|
459
666
|
```
|
|
460
667
|
|
|
461
|
-
>
|
|
668
|
+
> **Examples:**
|
|
669
|
+
> - [xcarpentier/gifted-chat-web-demo](https://github.com/xcarpentier/gifted-chat-web-demo)
|
|
670
|
+
> - [Gatsby example](https://github.com/xcarpentier/clean-archi-boilerplate/tree/develop/apps/web)
|
|
671
|
+
|
|
672
|
+
</details>
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## đ§Ē Testing
|
|
462
677
|
|
|
463
|
-
>
|
|
678
|
+
<details>
|
|
679
|
+
<summary><strong>Triggering layout events in tests</strong></summary>
|
|
464
680
|
|
|
465
|
-
|
|
466
|
-
`TEST_ID` is exported as constants that can be used in your testing library of choice
|
|
681
|
+
`TEST_ID` is exported as constants that can be used in your testing library of choice.
|
|
467
682
|
|
|
468
|
-
Gifted Chat uses `onLayout` to determine the height of the chat container. To trigger `onLayout` during your tests
|
|
683
|
+
Gifted Chat uses `onLayout` to determine the height of the chat container. To trigger `onLayout` during your tests:
|
|
469
684
|
|
|
470
685
|
```typescript
|
|
471
|
-
const WIDTH = 200
|
|
472
|
-
const HEIGHT = 2000
|
|
686
|
+
const WIDTH = 200
|
|
687
|
+
const HEIGHT = 2000
|
|
473
688
|
|
|
474
689
|
const loadingWrapper = getByTestId(TEST_ID.LOADING_WRAPPER)
|
|
475
690
|
fireEvent(loadingWrapper, 'layout', {
|
|
@@ -482,37 +697,144 @@ fireEvent(loadingWrapper, 'layout', {
|
|
|
482
697
|
})
|
|
483
698
|
```
|
|
484
699
|
|
|
485
|
-
|
|
700
|
+
</details>
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## đĻ Example App
|
|
705
|
+
|
|
706
|
+
The repository includes a comprehensive example app demonstrating all features:
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
# Clone and install
|
|
710
|
+
git clone https://github.com/FaridSafi/react-native-gifted-chat.git
|
|
711
|
+
cd react-native-gifted-chat/example
|
|
712
|
+
yarn install
|
|
713
|
+
|
|
714
|
+
# Run on iOS
|
|
715
|
+
npx expo run:ios
|
|
716
|
+
|
|
717
|
+
# Run on Android
|
|
718
|
+
npx expo run:android
|
|
719
|
+
|
|
720
|
+
# Run on Web
|
|
721
|
+
npx expo start --web
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
The example app showcases:
|
|
725
|
+
- đŦ Basic chat functionality
|
|
726
|
+
- đ¨ Custom message bubbles and avatars
|
|
727
|
+
- âŠī¸ Reply to messages with swipe gesture
|
|
728
|
+
- ⥠Quick replies (bot-style)
|
|
729
|
+
- âī¸ Typing indicators
|
|
730
|
+
- đ Attachment actions
|
|
731
|
+
- đ Link parsing and custom matchers
|
|
732
|
+
- đ Web compatibility
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
## â Troubleshooting
|
|
737
|
+
|
|
738
|
+
<details>
|
|
739
|
+
<summary><strong>TextInput is hidden on Android</strong></summary>
|
|
740
|
+
|
|
741
|
+
Make sure you have `android:windowSoftInputMode="adjustResize"` in your `AndroidManifest.xml`. See [Android configuration](#android) above.
|
|
742
|
+
|
|
743
|
+
</details>
|
|
744
|
+
|
|
745
|
+
<details>
|
|
746
|
+
<summary><strong>How to set Bubble color for each user?</strong></summary>
|
|
486
747
|
|
|
487
|
-
|
|
488
|
-
- [How can I pass style props to InputToolbar design and customize its color and other styles properties?](https://github.com/FaridSafi/react-native-gifted-chat/issues/662)
|
|
489
|
-
- [How can I change the color of the message box?](https://github.com/FaridSafi/react-native-gifted-chat/issues/640)
|
|
490
|
-
- [Is there a way to manually dismiss the keyboard?](https://github.com/FaridSafi/react-native-gifted-chat/issues/647)
|
|
491
|
-
- [I want to implement a popover that pops right after clicking on a specific avatar,
|
|
492
|
-
what is the best implementation in this case and how?](https://github.com/FaridSafi/react-native-gifted-chat/issues/660)
|
|
493
|
-
- [Why TextInput is hidden on Android?](https://github.com/FaridSafi/react-native-gifted-chat/issues/680#issuecomment-359699364)
|
|
494
|
-
- [How to use renderLoading?](https://github.com/FaridSafi/react-native-gifted-chat/issues/298)
|
|
495
|
-
- [Can I use MySql to save the message?](https://github.com/FaridSafi/react-native-gifted-chat/issues/738)
|
|
748
|
+
See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/672) for examples.
|
|
496
749
|
|
|
497
|
-
|
|
750
|
+
</details>
|
|
498
751
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
1. Find responses in existing issues
|
|
502
|
-
1. Try to keep issues for issues
|
|
752
|
+
<details>
|
|
753
|
+
<summary><strong>How to customize InputToolbar styles?</strong></summary>
|
|
503
754
|
|
|
504
|
-
|
|
755
|
+
See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/662) for examples.
|
|
505
756
|
|
|
506
|
-
|
|
757
|
+
</details>
|
|
507
758
|
|
|
508
|
-
|
|
759
|
+
<details>
|
|
760
|
+
<summary><strong>How to manually dismiss the keyboard?</strong></summary>
|
|
761
|
+
|
|
762
|
+
See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/647) for examples.
|
|
763
|
+
|
|
764
|
+
</details>
|
|
765
|
+
|
|
766
|
+
<details>
|
|
767
|
+
<summary><strong>How to use renderLoading?</strong></summary>
|
|
768
|
+
|
|
769
|
+
See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/298) for examples.
|
|
770
|
+
|
|
771
|
+
</details>
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
## đ¤ Have a Question?
|
|
776
|
+
|
|
777
|
+
1. Check this README first
|
|
778
|
+
2. Search [existing issues](https://github.com/FaridSafi/react-native-gifted-chat/issues)
|
|
779
|
+
3. Ask on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native-gifted-chat)
|
|
780
|
+
4. Open a new issue if needed
|
|
781
|
+
|
|
782
|
+
---
|
|
509
783
|
|
|
510
|
-
|
|
784
|
+
## đ¤ Contributing
|
|
511
785
|
|
|
512
|
-
|
|
786
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
513
787
|
|
|
514
|
-
|
|
788
|
+
1. Fork the repository
|
|
789
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
790
|
+
3. Install dependencies (`yarn install`)
|
|
791
|
+
4. Make your changes
|
|
792
|
+
5. Run tests (`yarn test`)
|
|
793
|
+
6. Run linting (`yarn lint`)
|
|
794
|
+
7. Build the library (`yarn build`)
|
|
795
|
+
8. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
796
|
+
9. Push to the branch (`git push origin feature/amazing-feature`)
|
|
797
|
+
10. Open a Pull Request
|
|
515
798
|
|
|
516
|
-
|
|
799
|
+
### Development Setup
|
|
517
800
|
|
|
518
|
-
|
|
801
|
+
```bash
|
|
802
|
+
# Install dependencies
|
|
803
|
+
yarn install
|
|
804
|
+
|
|
805
|
+
# Build the library
|
|
806
|
+
yarn build
|
|
807
|
+
|
|
808
|
+
# Run tests
|
|
809
|
+
yarn test
|
|
810
|
+
|
|
811
|
+
# Run linting
|
|
812
|
+
yarn lint
|
|
813
|
+
|
|
814
|
+
# Full validation
|
|
815
|
+
yarn prepublishOnly
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
---
|
|
819
|
+
|
|
820
|
+
## đĨ Authors
|
|
821
|
+
|
|
822
|
+
**Original Author:** [Farid Safi](https://www.x.com/FaridSafi)
|
|
823
|
+
|
|
824
|
+
**Co-maintainer:** [Xavier Carpentier](https://www.x.com/xcapetir) - [Hire Xavier](https://xaviercarpentier.com)
|
|
825
|
+
|
|
826
|
+
**Maintainer:** [Kesha Antonov](https://github.com/kesha-antonov)
|
|
827
|
+
|
|
828
|
+
> Please note that this project is maintained in free time. If you find it helpful, please consider [becoming a sponsor](https://github.com/sponsors/kesha-antonov).
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## đ License
|
|
833
|
+
|
|
834
|
+
[MIT](LICENSE)
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
<p align="center">
|
|
839
|
+
<sub>Built with â¤ī¸ by the React Native community</sub>
|
|
840
|
+
</p>
|