@sujeetdotkumar/react-native-gifted-chat-performant 1.0.0 → 1.0.1

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 (2) hide show
  1. package/README.md +189 -663
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,102 +1,121 @@
1
1
  <p align="center">
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>
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>
2
+ <a href="https://www.npmjs.com/package/@sujeetdotkumar/react-native-gifted-chat-performant"><img alt="npm version" src="https://badge.fury.io/js/@sujeetdotkumar%2Freact-native-gifted-chat-performant.svg"/></a>
5
3
  <img src="https://img.shields.io/badge/platforms-iOS%20%7C%20Android%20%7C%20Web-lightgrey.svg" alt="platforms">
6
4
  <img src="https://img.shields.io/badge/TypeScript-supported-blue.svg" alt="TypeScript">
7
5
  <img src="https://img.shields.io/badge/Expo-compatible-000020.svg" alt="Expo compatible">
8
6
  </p>
9
7
 
10
- <h1 align="center">React Native Gifted Chat</h1>
8
+ <h1 align="center">react-native-gifted-chat-performant</h1>
11
9
 
12
10
  <p align="center">
13
- The most complete chat UI for React Native & Web
14
- </p>
15
-
16
- <p align="center">
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>
11
+ A high-performance fork of <a href="https://github.com/FaridSafi/react-native-gifted-chat">react-native-gifted-chat</a> built for large message lists.
20
12
  </p>
21
13
 
22
14
  ---
23
15
 
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
16
+ ## What's different from the original
43
17
 
44
- <p align="center">
45
- <img width="200" src="https://github.com/user-attachments/assets/c9da88f5-0b20-471c-8cd7-373bdb767517" />
46
- &nbsp;&nbsp;&nbsp;&nbsp;
47
- <img width="200" src="https://github.com/user-attachments/assets/f72b17f1-6c2e-43b5-87e7-477011aa3b07" />
48
- &nbsp;&nbsp;&nbsp;&nbsp;
49
- <img width="200" src="https://github.com/user-attachments/assets/86711e73-ee3c-4527-b38d-e4dab47a44fe" />
50
- </p>
18
+ This fork replaces the core rendering stack with purpose-built, higher-performance primitives while keeping the full public API intact (except the date/time format props — see [Breaking Changes](#breaking-changes)).
19
+
20
+ ### List renderer — LegendList v3
21
+
22
+ The `AnimatedFlatList` (a `react-native-gesture-handler` FlatList wrapped in `Animated.createAnimatedComponent`) has been replaced with [`KeyboardChatLegendList`](https://www.legendapp.com/open-source/list/v3/) from `@legendapp/list`.
23
+
24
+ LegendList is purpose-built for chat and large lists in React Native. Key advantages over FlatList:
25
+ - Separate recycling pools per item type (`'message'` vs `'day'`) — prevents layout thrash between different-height items
26
+ - `maintainScrollAtEnd`, `alignItemsAtEnd`, `initialScrollAtEnd` — purpose-built chat scroll semantics without an `inverted` prop hack
27
+ - `sharedValues` prop syncs scroll offset directly to a Reanimated `SharedValue` — no `useAnimatedScrollHandler` needed
28
+ - Pure JS, no native code, no extra `pod install`
29
+
30
+ ### Day separator tracking — eliminated
31
+
32
+ The original implementation tracked day separator positions using a `CellRendererComponent` that fired a layout worklet on **every message item** on every render. Those positions were stored in a `daysPositions` SharedValue, sorted (O(n log n)), and interpolated on every scroll frame. All of that is gone.
33
+
34
+ Day separators are now interleaved directly in the data array (`displayData`) alongside messages. An `onViewableItemsChanged` callback tracks the topmost visible day for the animated overlay — zero per-item overhead.
35
+
36
+ ### Keyboard handling — KeyboardStickyView
37
+
38
+ `KeyboardAvoidingView` (which can cause layout jumps on keyboard open) has been replaced with:
39
+ - `KeyboardChatLegendList` handles keyboard-aware scroll internally
40
+ - `KeyboardStickyView` from `react-native-keyboard-controller` keeps the input toolbar pinned above the keyboard
41
+
42
+ ### dayjs removed — native Intl APIs
43
+
44
+ `dayjs` (~5 KB gzipped) has been removed entirely. All date and time formatting now uses the built-in `Intl.DateTimeFormat` API, which is zero-cost (already part of the JS engine), supports the same locale strings, and produces identical output.
45
+
46
+ ### lodash.isequal removed
47
+
48
+ `lodash.isequal` was listed as a dependency in the original but was not imported anywhere in `src/`. Removed.
49
+
50
+ ### React.memo on leaf components
51
+
52
+ `Day`, `Time`, and `GiftedAvatar` are now wrapped with `React.memo` to prevent unnecessary re-renders when parent state changes don't affect their props.
53
+
54
+ ### Performance summary
55
+
56
+ | Bottleneck | Original | This fork |
57
+ |---|---|---|
58
+ | List virtualization | RNGH FlatList + Animated wrapper | LegendList v3 with separate recycling pools |
59
+ | Day position tracking | O(n log n) sort + worklet per item layout | Eliminated — data-driven via `displayData` |
60
+ | Per-item CellRendererComponent | Fires worklet on every item layout | Removed |
61
+ | `daysPositions` SharedValue | Modified per-item, read per scroll frame | Removed |
62
+ | dayjs bundle | ~5 KB gzipped | 0 (native Intl) |
63
+ | lodash.isequal | ~4 KB gzipped | 0 (removed) |
51
64
 
52
65
  ---
53
66
 
54
- <h3 align="center">Sponsors</h3>
55
-
56
- <table align="center" border="0" cellspacing="20">
57
- <tr>
58
- <td align="center" valign="middle">
59
- <a href="https://www.lereacteur.io" target="_blank"><img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/logo_sponsor.png" height="50"></a>
60
- </td>
61
- <td align="center" valign="middle">
62
- <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"><img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/stream-logo.png" height="35"></a>
63
- </td>
64
- <td align="center" valign="middle">
65
- <a href="https://www.ethora.com" target="_blank"><img src="https://www.dappros.com/wp-content/uploads/2023/12/Ethora-Logo.png" height="50"></a>
66
- </td>
67
- </tr>
68
- </table>
67
+ ## Breaking Changes
69
68
 
70
- <p align="center">
71
- <a href="https://www.lereacteur.io" target="_blank"><strong>Le Reacteur</strong></a> - Coding Bootcamp in Paris co-founded by Farid Safi
72
- <br>
73
- <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"><strong>Stream</strong></a> - Scalable chat API/Server written in Go (<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">Tutorial</a>)
74
- <br>
75
- <a href="https://www.ethora.com" target="_blank"><strong>Ethora</strong></a> - A complete app engine featuring GiftedChat (<a href="https://bit.ly/ethorachat" target="_blank">GitHub</a>)
76
- <br><br>
77
- 📚 <a href="https://amzn.to/3ZmTyb2" target="_blank">React Key Concepts (2nd ed.)</a>
78
- </p>
69
+ ### Date & time format props
70
+
71
+ The original `dayjs`-based format props have been replaced with `Intl.DateTimeFormatOptions`:
72
+
73
+ | Original prop | Type | Replacement | Type |
74
+ |---|---|---|---|
75
+ | `timeFormat` | `string` (dayjs format, e.g. `'LT'`) | `timeFormatOptions` | `Intl.DateTimeFormatOptions` |
76
+ | `dateFormat` | `string` (dayjs format, e.g. `'D MMMM'`) | `dateFormatOptions` | `Intl.DateTimeFormatOptions` |
77
+ | `dateFormatCalendar` | `object` (dayjs calendar options) | removed — use `dateFormatOptions` | — |
78
+
79
+ **Migration example:**
80
+
81
+ ```tsx
82
+ // Before
83
+ <GiftedChat timeFormat='HH:mm' dateFormat='D MMMM' />
84
+
85
+ // After
86
+ <GiftedChat
87
+ timeFormatOptions={{ hour: '2-digit', minute: '2-digit', hour12: false }}
88
+ dateFormatOptions={{ day: 'numeric', month: 'long' }}
89
+ />
90
+ ```
91
+
92
+ The `locale` prop continues to work — it is passed directly to `Intl.DateTimeFormat` as the locale string.
79
93
 
80
94
  ---
81
95
 
82
- ## 📖 Table of Contents
83
-
84
- - [Features](#-features)
85
- - [Requirements](#-requirements)
86
- - [Installation](#-installation)
87
- - [Usage](#-usage)
88
- - [Props Reference](#-props-reference)
89
- - [Data Structure](#-data-structure)
90
- - [Platform Notes](#-platform-notes)
91
- - [Example App](#-example-app)
92
- - [Troubleshooting](#-troubleshooting)
93
- - [Contributing](#-contributing)
94
- - [Authors](#-authors)
95
- - [License](#-license)
96
+ ## Features
97
+
98
+ - Fully customizable — override any component with your own implementation
99
+ - Composer actions — attach photos, files, or trigger custom actions
100
+ - Reply to messages — swipe-to-reply with reply preview and message threading
101
+ - Load earlier messages — infinite scroll with pagination support
102
+ - Copy to clipboard — long-press messages to copy text
103
+ - Smart link parsing — auto-detect URLs, emails, phone numbers, hashtags, mentions
104
+ - Avatars — user initials or custom avatar images
105
+ - Localized dates — full i18n support via native `Intl.DateTimeFormat`
106
+ - Keyboard handling — `KeyboardChatLegendList` + `KeyboardStickyView` for all platforms
107
+ - System messages — display system notifications in chat
108
+ - Quick replies — bot-style quick reply buttons
109
+ - Typing indicator — show when users are typing
110
+ - Message status — tick indicators for sent/delivered/read states
111
+ - Scroll to bottom — quick navigation button
112
+ - Web support — works with react-native-web
113
+ - Expo support — easy integration with Expo projects
114
+ - TypeScript — complete TypeScript definitions included
96
115
 
97
116
  ---
98
117
 
99
- ## 📋 Requirements
118
+ ## Requirements
100
119
 
101
120
  | Requirement | Version |
102
121
  |-------------|---------|
@@ -104,58 +123,44 @@
104
123
  | iOS | >= 13.4 |
105
124
  | Android | API 21+ (Android 5.0) |
106
125
  | Expo | SDK 50+ |
126
+ | react-native-keyboard-controller | >= 1.21.0 |
107
127
  | TypeScript | >= 5.0 (optional) |
108
128
 
109
129
  ---
110
130
 
111
- ## 📦 Installation
131
+ ## Installation
112
132
 
113
133
  ### Expo Projects
114
134
 
115
135
  ```bash
116
- npx expo install react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
136
+ npx expo install @sujeetdotkumar/react-native-gifted-chat-performant @legendapp/list react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
117
137
  ```
118
138
 
119
139
  ### Bare React Native Projects
120
140
 
121
- **Step 1:** Install the packages
122
-
123
- Using yarn:
124
141
  ```bash
125
- yarn add react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
142
+ yarn add @sujeetdotkumar/react-native-gifted-chat-performant @legendapp/list react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
126
143
  ```
127
144
 
128
- Using npm:
129
- ```bash
130
- npm install --save react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
131
- ```
132
-
133
- **Step 2:** Install iOS pods
145
+ Then install iOS pods:
134
146
 
135
147
  ```bash
136
148
  npx pod-install
137
149
  ```
138
150
 
139
- **Step 3:** Configure react-native-reanimated
140
-
141
- 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.
151
+ And 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.
142
152
 
143
153
  ---
144
154
 
145
- ## 🚀 Usage
146
-
147
- ### Basic Example
155
+ ## Usage
148
156
 
149
157
  ```jsx
150
158
  import React, { useState, useCallback, useEffect } from 'react'
151
- import { GiftedChat } from 'react-native-gifted-chat'
159
+ import { GiftedChat } from '@sujeetdotkumar/react-native-gifted-chat-performant'
152
160
  import { useHeaderHeight } from '@react-navigation/elements'
153
161
 
154
162
  export function Example() {
155
163
  const [messages, setMessages] = useState([])
156
-
157
- // keyboardVerticalOffset = distance from screen top to GiftedChat container
158
- // useHeaderHeight() returns status bar + navigation header height
159
164
  const headerHeight = useHeaderHeight()
160
165
 
161
166
  useEffect(() => {
@@ -183,54 +188,16 @@ export function Example() {
183
188
  <GiftedChat
184
189
  messages={messages}
185
190
  onSend={messages => onSend(messages)}
186
- user={{
187
- _id: 1,
188
- }}
191
+ user={{ _id: 1 }}
189
192
  keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
190
193
  />
191
194
  )
192
195
  }
193
196
  ```
194
197
 
195
- > **💡 Tip:** Check out more examples in the [`example`](example) directory including Slack-style messages, quick replies, and custom components.
196
-
197
- ---
198
-
199
- ## 📊 Data Structure
200
-
201
- Messages, system messages, and quick replies follow the structure defined in [Models.ts](src/Models.ts).
202
-
203
- <details>
204
- <summary><strong>Message Object Structure</strong></summary>
205
-
206
- ```typescript
207
- interface IMessage {
208
- _id: string | number
209
- text: string
210
- createdAt: Date | number
211
- user: User
212
- image?: string
213
- video?: string
214
- audio?: string
215
- system?: boolean
216
- sent?: boolean
217
- received?: boolean
218
- pending?: boolean
219
- quickReplies?: QuickReplies
220
- }
221
-
222
- interface User {
223
- _id: string | number
224
- name?: string
225
- avatar?: string | number | (() => React.ReactNode)
226
- }
227
- ```
228
-
229
- </details>
230
-
231
198
  ---
232
199
 
233
- ## 📖 Props Reference
200
+ ## Props Reference
234
201
 
235
202
  ### Core Configuration
236
203
 
@@ -238,191 +205,78 @@ interface User {
238
205
  - **`user`** _(Object)_ - User sending the messages: `{ _id, name, avatar }`
239
206
  - **`onSend`** _(Function)_ - Callback when sending a message
240
207
  - **`messageIdGenerator`** _(Function)_ - Generate an id for new messages. Defaults to a simple random string generator.
241
- - **`locale`** _(String)_ - Locale to localize the dates. You need first to import the locale you need (ie. `require('dayjs/locale/de')` or `import 'dayjs/locale/fr'`)
242
- - **`colorScheme`** _('light' | 'dark')_ - Force color scheme (light/dark mode). When set to `'light'` or `'dark'`, it overrides the system color scheme. When `undefined`, it uses the system color scheme. Default is `undefined`.
208
+ - **`locale`** _(String)_ - Locale string passed to `Intl.DateTimeFormat` (e.g. `'fr'`, `'de'`, `'ja'`)
209
+ - **`colorScheme`** _('light' | 'dark')_ - Force color scheme. When `undefined`, uses the system color scheme.
243
210
 
244
211
  ### Refs
245
212
 
246
- - **`messagesContainerRef`** _(FlatList ref)_ - Ref to the flatlist
213
+ - **`messagesContainerRef`** _(LegendList ref)_ - Ref to the list
247
214
  - **`textInputRef`** _(TextInput ref)_ - Ref to the text input
248
215
 
249
216
  ### Keyboard & Layout
250
217
 
251
- - **`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:
252
- - `statusBarTranslucent: true` - Required on Android for correct keyboard height calculation when status bar is translucent (edge-to-edge mode)
253
- - `navigationBarTranslucent: true` - Required on Android for correct keyboard height calculation when navigation bar is translucent (edge-to-edge mode)
254
- - **`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.
255
- - **`isAlignedTop`** _(Boolean)_ Controls whether or not the message bubbles appear at the top of the chat (Default is false - bubbles align to bottom)
256
- - **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
257
-
258
- #### Understanding `keyboardVerticalOffset`
259
-
260
- 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).
261
-
262
- **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`.
263
-
264
- **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:
265
- - Status bar height
266
- - Navigation header height (on iOS, `useHeaderHeight()` already includes status bar)
267
-
268
- **How to use:**
269
-
270
- ```jsx
271
- import { useHeaderHeight } from '@react-navigation/elements'
272
-
273
- function ChatScreen() {
274
- // useHeaderHeight() returns status bar + navigation header height on iOS
275
- const headerHeight = useHeaderHeight()
276
-
277
- return (
278
- <GiftedChat
279
- keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
280
- // ... other props
281
- />
282
- )
283
- }
284
- ```
285
-
286
- > **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.
287
-
288
- **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.
218
+ - **`keyboardProviderProps`** _(Object)_ - Props for [`KeyboardProvider`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-provider)
219
+ - **`keyboardAvoidingViewProps`** _(Object)_ - Props including `keyboardVerticalOffset` (distance from screen top to GiftedChat container use `useHeaderHeight()` when inside a navigation stack)
220
+ - **`isAlignedTop`** _(Boolean)_ - Align bubbles to top instead of bottom; default `false`
221
+ - **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default `true`
289
222
 
290
223
  ### Text Input & Composer
291
224
 
292
- - **`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.
293
- - **`initialText`** _(String)_ - Initial text to display in the input field
294
- - **`isSendButtonAlwaysVisible`** _(Bool)_ - Always show send button in input text composer; default `false`, show only when text input is not empty
295
- - **`isTextOptional`** _(Bool)_ - Allow sending messages without text (useful for media-only messages); default `false`. Use with `isSendButtonAlwaysVisible` for media attachments.
296
- - **`minComposerHeight`** _(Object)_ - Custom min-height of the composer.
297
- - **`maxComposerHeight`** _(Object)_ - Custom max height of the composer.
298
- - **`minInputToolbarHeight`** _(Integer)_ - Minimum height of the input toolbar; default is `44`
299
- - **`renderInputToolbar`** _(Component | Function)_ - Custom message composer container
300
- - **`renderComposer`** _(Component | Function)_ - Custom text input message composer
301
- - **`renderSend`** _(Component | Function)_ - Custom send button; you can pass children to the original `Send` component quite easily, for example, to use a custom icon ([example](https://github.com/FaridSafi/react-native-gifted-chat/pull/487))
302
- - **`renderActions`** _(Component | Function)_ - Custom action button on the left of the message composer
303
- - **`renderAccessory`** _(Component | Function)_ - Custom second line of actions below the message composer
304
- - **`textInputProps`** _(Object)_ - props to be passed to the [`<TextInput>`](https://reactnative.dev/docs/textinput).
305
-
306
- ### Actions & Action Sheet
307
-
308
- - **`onPressActionButton`** _(Function)_ - Callback when the Action button is pressed (if set, the default `actionSheet` will not be used)
309
- - **`actionSheet`** _(Function)_ - Custom action sheet interface for showing action options
310
- - **`actions`** _(Array)_ - Custom action options for the input toolbar action button; array of objects with `title` (string) and `action` (function) properties
311
- - **`actionSheetOptionTintColor`** _(String)_ - Tint color for action sheet options
225
+ - **`text`** _(String)_ - Controlled input text
226
+ - **`initialText`** _(String)_ - Initial text in the input field
227
+ - **`isSendButtonAlwaysVisible`** _(Bool)_ - Always show send button; default `false`
228
+ - **`minComposerHeight`** / **`maxComposerHeight`** _(Number)_ - Composer height bounds
229
+ - **`minInputToolbarHeight`** _(Integer)_ - Minimum toolbar height; default `44`
230
+ - **`renderInputToolbar`** _(Component | Function)_ - Custom input toolbar
231
+ - **`renderComposer`** _(Component | Function)_ - Custom text input
232
+ - **`renderSend`** _(Component | Function)_ - Custom send button
233
+ - **`renderActions`** _(Component | Function)_ - Custom action button (left of composer)
234
+ - **`renderAccessory`** _(Component | Function)_ - Custom second line below composer
235
+ - **`textInputProps`** _(Object)_ - Props passed to `<TextInput>`
312
236
 
313
237
  ### Messages & Message Container
314
238
 
315
- - **`messagesContainerStyle`** _(Object)_ - Custom style for the messages container
239
+ - **`messagesContainerStyle`** _(Object)_ - Custom style for messages container
316
240
  - **`renderMessage`** _(Component | Function)_ - Custom message container
317
- - **`renderLoading`** _(Component | Function)_ - Render a loading view when initializing
318
- - **`renderChatEmpty`** _(Component | Function)_ - Custom component to render in the ListView when messages are empty
319
- - **`renderChatFooter`** _(Component | Function)_ - Custom component to render below the MessagesContainer (separate from the ListView)
320
- - **`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).
241
+ - **`renderLoading`** _(Component | Function)_ - Loading view while initializing
242
+ - **`renderChatEmpty`** _(Component | Function)_ - Component when messages are empty
243
+ - **`renderChatFooter`** _(Component | Function)_ - Component below the message list
244
+ - **`listProps`** _(Object)_ - Extra props passed to the underlying `LegendList`
321
245
 
322
246
  ### Message Bubbles & Content
323
247
 
324
- - **`renderBubble`** _(Component | Function(`props: BubbleProps`))_ - Custom message bubble. Receives [BubbleProps](src/Bubble/types.ts) as parameter.
248
+ - **`renderBubble`** _(Component | Function)_ - Custom message bubble
325
249
  - **`renderMessageText`** _(Component | Function)_ - Custom message text
326
250
  - **`renderMessageImage`** _(Component | Function)_ - Custom message image
327
251
  - **`renderMessageVideo`** _(Component | Function)_ - Custom message video
328
252
  - **`renderMessageAudio`** _(Component | Function)_ - Custom message audio
329
253
  - **`renderCustomView`** _(Component | Function)_ - Custom view inside the bubble
330
- - **`isCustomViewBottom`** _(Bool)_ - Determine whether renderCustomView is displayed before or after the text, image and video views; default is `false`
331
- - **`onPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is pressed
332
- - **`onLongPressMessage`** _(Function(`context`, `message`))_ - Callback when a message bubble is long-pressed; you can use this to show action sheets (e.g., copy, delete, reply)
333
- - **`imageProps`** _(Object)_ - Extra props to be passed to the [`<Image>`](https://reactnative.dev/docs/image) component created by the default `renderMessageImage`
334
- - **`imageStyle`** _(Object)_ - Custom style for message images
335
- - **`videoProps`** _(Object)_ - Extra props to be passed to the video component created by the required `renderMessageVideo`
336
- - **`messageTextProps`** _(Object)_ - Extra props to be passed to the MessageText component. Useful for customizing link parsing behavior, text styles, and matchers. Supports the following props:
337
- - `matchers` - Custom matchers for linking message content (like URLs, phone numbers, hashtags, mentions)
338
- - `linkStyle` - Custom style for links
339
- - `email` - Enable/disable email parsing (default: true)
340
- - `phone` - Enable/disable phone number parsing (default: true)
341
- - `url` - Enable/disable URL parsing (default: true)
342
- - `hashtag` - Enable/disable hashtag parsing (default: false)
343
- - `mention` - Enable/disable mention parsing (default: false)
344
- - `hashtagUrl` - Base URL for hashtags (e.g., 'https://x.com/hashtag')
345
- - `mentionUrl` - Base URL for mentions (e.g., 'https://x.com')
346
- - `stripPrefix` - Strip 'http://' or 'https://' from URL display (default: false)
347
- - `TextComponent` - Custom Text component to use (e.g., from react-native-gesture-handler)
348
-
349
- Example:
350
-
351
- ```tsx
352
- <GiftedChat
353
- messageTextProps={{
354
- phone: false, // Disable default phone number linking
355
- matchers: [
356
- {
357
- type: 'phone',
358
- pattern: /\+?[1-9][0-9\-\(\) ]{7,}[0-9]/g,
359
- getLinkUrl: (replacerArgs: ReplacerArgs): string => {
360
- return replacerArgs[0].replace(/[\-\(\) ]/g, '')
361
- },
362
- getLinkText: (replacerArgs: ReplacerArgs): string => {
363
- return replacerArgs[0]
364
- },
365
- style: styles.linkStyle,
366
- onPress: (match: CustomMatch) => {
367
- const url = match.getAnchorHref()
368
-
369
- const options: {
370
- title: string
371
- action?: () => void
372
- }[] = [
373
- { title: 'Copy', action: () => setStringAsync(url) },
374
- { title: 'Call', action: () => Linking.openURL(`tel:${url}`) },
375
- { title: 'Send SMS', action: () => Linking.openURL(`sms:${url}`) },
376
- { title: 'Cancel' },
377
- ]
378
-
379
- showActionSheetWithOptions({
380
- options: options.map(o => o.title),
381
- cancelButtonIndex: options.length - 1,
382
- }, (buttonIndex?: number) => {
383
- if (buttonIndex === undefined)
384
- return
385
-
386
- const option = options[buttonIndex]
387
- option.action?.()
388
- })
389
- },
390
- },
391
- ],
392
- linkStyle: { left: { color: 'blue' }, right: { color: 'lightblue' } },
393
- }}
394
- />
395
- ```
396
-
397
- See full example in [LinksExample](example/components/chat-examples/LinksExample.tsx)
254
+ - **`isCustomViewBottom`** _(Bool)_ - Render custom view below text/image; default `false`
255
+ - **`onPressMessage`** / **`onLongPressMessage`** _(Function)_ - Message tap/long-press callbacks
256
+ - **`imageProps`** / **`imageStyle`** / **`videoProps`** - Image and video customization
257
+ - **`messageTextProps`** _(Object)_ - Props for `MessageText` (link parsing, matchers, styles)
398
258
 
399
259
  ### Avatars
400
260
 
401
- - **`renderAvatar`** _(Component | Function)_ - Custom message avatar; set to `null` to not render any avatar for the message
402
- - **`isUserAvatarVisible`** _(Bool)_ - Whether to render an avatar for the current user; default is `false`, only show avatars for other users
403
- - **`isAvatarVisibleForEveryMessage`** _(Bool)_ - When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is `false`
404
- - **`onPressAvatar`** _(Function(`user`))_ - Callback when a message avatar is tapped
405
- - **`onLongPressAvatar`** _(Function(`user`))_ - Callback when a message avatar is long-pressed
406
- - **`isAvatarOnTop`** _(Bool)_ - Render the message avatar at the top of consecutive messages, rather than the bottom; default is `false`
261
+ - **`renderAvatar`** _(Component | Function | null)_ - Custom avatar; `null` to hide
262
+ - **`isUserAvatarVisible`** _(Bool)_ - Show avatar for current user; default `false`
263
+ - **`isAvatarVisibleForEveryMessage`** _(Bool)_ - Show avatar on every message; default `false`
264
+ - **`onPressAvatar`** / **`onLongPressAvatar`** _(Function)_ - Avatar tap callbacks
265
+ - **`isAvatarOnTop`** _(Bool)_ - Show avatar at top of consecutive messages; default `false`
407
266
 
408
267
  ### Username
409
268
 
410
- - **`isUsernameVisible`** _(Bool)_ - Indicate whether to show the user's username inside the message bubble; default is `false`
411
- - **`renderUsername`** _(Component | Function)_ - Custom Username container
269
+ - **`isUsernameVisible`** _(Bool)_ - Show username in bubble; default `false`
270
+ - **`renderUsername`** _(Component | Function)_ - Custom username component
412
271
 
413
272
  ### Date & Time
414
273
 
415
- - **`timeFormat`** _(String)_ - Format to use for rendering times; default is `'LT'` (see [Day.js Format](https://day.js.org/docs/en/display/format))
416
- - **`dateFormat`** _(String)_ - Format to use for rendering dates; default is `'D MMMM'` (see [Day.js Format](https://day.js.org/docs/en/display/format))
417
- - **`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))
418
- - **`renderDay`** _(Component | Function)_ - Custom day above a message
419
- - **`dayProps`** _(Object)_ - Props to pass to the Day component:
420
- - `containerStyle` - Custom style for the day container
421
- - `wrapperStyle` - Custom style for the day wrapper
422
- - `textProps` - Props to pass to the Text component (e.g., `style`, `allowFontScaling`, `numberOfLines`)
423
- - **`renderTime`** _(Component | Function)_ - Custom time inside a message
424
- - **`timeTextStyle`** _(Object)_ - Custom text style for time inside messages (supports left/right styles)
425
- - **`isDayAnimationEnabled`** _(Bool)_ - Enable animated day label that appears on scroll; default is `true`
274
+ - **`timeFormatOptions`** _(Intl.DateTimeFormatOptions)_ - Format for message times; default `{ hour: '2-digit', minute: '2-digit' }`
275
+ - **`dateFormatOptions`** _(Intl.DateTimeFormatOptions)_ - Format for day separators; default `{ day: 'numeric', month: 'long' }`
276
+ - **`renderDay`** _(Component | Function)_ - Custom day separator
277
+ - **`renderTime`** _(Component | Function)_ - Custom time component
278
+ - **`timeTextStyle`** _(Object)_ - Custom time text style (supports left/right)
279
+ - **`isDayAnimationEnabled`** _(Bool)_ - Animated day label on scroll; default `true`
426
280
 
427
281
  ### System Messages
428
282
 
@@ -430,439 +284,111 @@ See full example in [LinksExample](example/components/chat-examples/LinksExample
430
284
 
431
285
  ### Load Earlier Messages
432
286
 
433
- - **`loadEarlierMessagesProps`** _(Object)_ - Props to pass to the LoadEarlierMessages component. The button is only visible when `isAvailable` is `true`. Supports the following props:
434
- - `isAvailable` - Controls button visibility (default: false)
435
- - `onPress` - Callback when button is pressed
436
- - `isLoading` - Display loading indicator (default: false)
437
- - `isInfiniteScrollEnabled` - Enable infinite scroll up when reaching the top of messages container, automatically calls `onPress` (not yet supported for web)
438
- - `label` - Override the default "Load earlier messages" text
439
- - `containerStyle` - Custom style for the button container
440
- - `wrapperStyle` - Custom style for the button wrapper
441
- - `textStyle` - Custom style for the button text
442
- - `activityIndicatorStyle` - Custom style for the loading indicator
443
- - `activityIndicatorColor` - Color of the loading indicator (default: 'white')
444
- - `activityIndicatorSize` - Size of the loading indicator (default: 'small')
445
- - **`renderLoadEarlier`** _(Component | Function)_ - Custom "Load earlier messages" button
287
+ - **`loadEarlierMessagesProps`** _(Object)_
288
+ - `isAvailable` - Show/hide button
289
+ - `onPress` - Load callback
290
+ - `isLoading` - Show spinner
291
+ - `isInfiniteScrollEnabled` - Auto-trigger `onPress` at top of list
292
+ - `label`, `containerStyle`, `wrapperStyle`, `textStyle` - Customization
293
+ - **`renderLoadEarlier`** _(Component | Function)_ - Custom load-earlier button
446
294
 
447
295
  ### Typing Indicator
448
296
 
449
- - **`isTyping`** _(Bool)_ - Typing Indicator state; default `false`. If you use`renderFooter` it will override this.
450
- - **`renderTypingIndicator`** _(Component | Function)_ - Custom typing indicator component
451
- - **`typingIndicatorStyle`** _(StyleProp<ViewStyle>)_ - Custom style for the TypingIndicator component.
452
- - **`renderFooter`** _(Component | Function)_ - Custom footer component on the ListView, e.g. `'User is typing...'`; see [CustomizedFeaturesExample.tsx](example/components/chat-examples/CustomizedFeaturesExample.tsx) for an example. Overrides default typing indicator that triggers when `isTyping` is true.
297
+ - **`isTyping`** _(Bool)_ - Show typing indicator; default `false`
298
+ - **`renderTypingIndicator`** _(Component | Function)_ - Custom typing indicator
299
+ - **`renderFooter`** _(Component | Function)_ - Custom footer (overrides typing indicator)
453
300
 
454
301
  ### Quick Replies
455
302
 
456
- See [Quick Replies example in messages.ts](example/example-expo/data/messages.ts)
457
-
458
- - **`onQuickReply`** _(Function)_ - Callback when sending a quick reply (to backend server)
459
- - **`renderQuickReplies`** _(Function)_ - Custom all quick reply view
460
- - **`quickReplyStyle`** _(StyleProp<ViewStyle>)_ - Custom quick reply view style
461
- - **`quickReplyTextStyle`** _(StyleProp<TextStyle>)_ - Custom text style for quick reply buttons
462
- - **`quickReplyContainerStyle`** _(StyleProp<ViewStyle>)_ - Custom container style for quick replies
463
- - **`renderQuickReplySend`** _(Function)_ - Custom quick reply **send** view
303
+ - **`onQuickReply`** _(Function)_ - Callback when quick reply is sent
304
+ - **`renderQuickReplies`** / **`renderQuickReplySend`** _(Function)_ - Custom renderers
305
+ - **`quickReplyStyle`** / **`quickReplyTextStyle`** / **`quickReplyContainerStyle`** - Styles
464
306
 
465
307
  ### Reply to Messages
466
308
 
467
- 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.
468
-
469
- > **Note:** This feature uses `ReanimatedSwipeable` from `react-native-gesture-handler` and `react-native-reanimated` for smooth, performant animations.
470
-
471
- #### Basic Usage
472
-
473
309
  ```tsx
474
310
  <GiftedChat
475
- messages={messages}
476
- onSend={onSend}
477
- user={{ _id: 1 }}
478
311
  reply={{
479
312
  swipe: {
480
313
  isEnabled: true,
481
- direction: 'left', // swipe left to reply
314
+ direction: 'left',
315
+ onSwipe: (message) => setReplyMessage(message),
482
316
  },
317
+ message: replyMessage,
318
+ onClear: () => setReplyMessage(null),
483
319
  }}
484
320
  />
485
321
  ```
486
322
 
487
- #### Reply Props (Grouped)
488
-
489
- The `reply` prop accepts an object with the following structure:
323
+ Full `reply` prop shape:
490
324
 
491
325
  ```typescript
492
326
  interface ReplyProps<TMessage> {
493
- // Swipe gesture configuration
494
327
  swipe?: {
495
- isEnabled?: boolean // Enable swipe-to-reply; default false
496
- direction?: 'left' | 'right' // Swipe direction; default 'left'
497
- onSwipe?: (message: TMessage) => void // Callback when swiped
498
- renderAction?: ( // Custom swipe action component
499
- progress: SharedValue<number>,
500
- translation: SharedValue<number>,
501
- position: 'left' | 'right'
502
- ) => React.ReactNode
328
+ isEnabled?: boolean
329
+ direction?: 'left' | 'right'
330
+ onSwipe?: (message: TMessage) => void
331
+ renderAction?: (progress, translation, position) => React.ReactNode
503
332
  actionContainerStyle?: StyleProp<ViewStyle>
504
333
  }
505
-
506
- // Reply preview styling (above input toolbar)
507
- previewStyle?: {
508
- containerStyle?: StyleProp<ViewStyle>
509
- textStyle?: StyleProp<TextStyle>
510
- imageStyle?: StyleProp<ImageStyle>
511
- }
512
-
513
- // In-bubble reply styling
514
- messageStyle?: {
515
- containerStyle?: StyleProp<ViewStyle>
516
- containerStyleLeft?: StyleProp<ViewStyle>
517
- containerStyleRight?: StyleProp<ViewStyle>
518
- textStyle?: StyleProp<TextStyle>
519
- textStyleLeft?: StyleProp<TextStyle>
520
- textStyleRight?: StyleProp<TextStyle>
521
- imageStyle?: StyleProp<ImageStyle>
522
- }
523
-
524
- // Callbacks and state
525
- message?: ReplyMessage // Controlled reply state
526
- onClear?: () => void // Called when reply cleared
527
- onPress?: (message: TMessage) => void // Called when reply preview tapped
528
-
529
- // Custom renderers
334
+ previewStyle?: { containerStyle?, textStyle?, imageStyle? }
335
+ messageStyle?: { containerStyle?, textStyle?, imageStyle?, ...left/right variants }
336
+ message?: ReplyMessage
337
+ onClear?: () => void
338
+ onPress?: (message: TMessage) => void
530
339
  renderPreview?: (props: ReplyPreviewProps) => React.ReactNode
531
340
  renderMessageReply?: (props: MessageReplyProps) => React.ReactNode
532
341
  }
533
342
  ```
534
343
 
535
- #### ReplyMessage Structure
536
-
537
- When a message has a reply, it includes a `replyMessage` property:
538
-
539
- ```typescript
540
- interface ReplyMessage {
541
- _id: string | number
542
- text: string
543
- user: User
544
- image?: string
545
- audio?: string
546
- }
547
- ```
548
-
549
- #### Advanced Example with External State
550
-
551
- ```tsx
552
- const [replyMessage, setReplyMessage] = useState<ReplyMessage | null>(null)
553
-
554
- <GiftedChat
555
- messages={messages}
556
- onSend={messages => {
557
- const newMessages = messages.map(msg => ({
558
- ...msg,
559
- replyMessage: replyMessage || undefined,
560
- }))
561
- setMessages(prev => GiftedChat.append(prev, newMessages))
562
- setReplyMessage(null)
563
- }}
564
- user={{ _id: 1 }}
565
- reply={{
566
- swipe: {
567
- isEnabled: true,
568
- direction: 'right',
569
- onSwipe: setReplyMessage,
570
- },
571
- message: replyMessage,
572
- onClear: () => setReplyMessage(null),
573
- onPress: (msg) => scrollToMessage(msg._id),
574
- }}
575
- />
576
- ```
577
-
578
- #### Smooth Animations
579
-
580
- The reply preview automatically animates when:
581
- - **Appearing**: Smoothly expands from zero height with fade-in effect
582
- - **Disappearing**: Smoothly collapses with fade-out effect
583
- - **Content changes**: Smoothly transitions when replying to a different message
584
-
585
- These animations use `react-native-reanimated` for 60fps performance.
586
-
587
344
  ### Scroll to Bottom
588
345
 
589
- - **`isScrollToBottomEnabled`** _(Bool)_ - Enables the scroll to bottom Component (Default is false)
590
- - **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
591
- - **`scrollToBottomOffset`** _(Integer)_ - Custom Height Offset upon which to begin showing Scroll To Bottom Component (Default is 200)
592
- - **`scrollToBottomStyle`** _(Object)_ - Custom style for Scroll To Bottom wrapper (position, bottom, right, etc.)
593
- - **`scrollToBottomContentStyle`** _(Object)_ - Custom style for Scroll To Bottom content (size, background, shadow, etc.)
594
-
595
- ### Maintaining Scroll Position (AI Chatbots)
596
-
597
- 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`:
598
-
599
- ```tsx
600
- // Basic usage - always maintain scroll position
601
- <GiftedChat
602
- listProps={{
603
- maintainVisibleContentPosition: {
604
- minIndexForVisible: 0,
605
- },
606
- }}
607
- />
608
-
609
- // With auto-scroll threshold - auto-scroll if within 10 pixels of newest content
610
- <GiftedChat
611
- listProps={{
612
- maintainVisibleContentPosition: {
613
- minIndexForVisible: 0,
614
- autoscrollToTopThreshold: 10,
615
- },
616
- }}
617
- />
618
-
619
- // Conditionally enable based on scroll state (recommended for chatbots)
620
- const [isScrolledUp, setIsScrolledUp] = useState(false)
621
-
622
- <GiftedChat
623
- listProps={{
624
- onScroll: (event) => {
625
- setIsScrolledUp(event.contentOffset.y > 50)
626
- },
627
- maintainVisibleContentPosition: isScrolledUp
628
- ? { minIndexForVisible: 0, autoscrollToTopThreshold: 10 }
629
- : undefined,
630
- }}
631
- />
632
- ```
346
+ - **`isScrollToBottomEnabled`** _(Bool)_ - Show scroll-to-bottom button; default `false`
347
+ - **`scrollToBottomComponent`** _(Function)_ - Custom button content
348
+ - **`scrollToBottomStyle`** / **`scrollToBottomContentStyle`** - Styles
633
349
 
634
350
  ---
635
351
 
636
- ## 📱 Platform Notes
352
+ ## Platform Notes
637
353
 
638
354
  ### Android
639
355
 
640
- <details>
641
- <summary><strong>Keyboard configuration</strong></summary>
642
-
643
- If you are using Create React Native App / Expo, no Android specific installation steps are required. Otherwise, we recommend modifying your project configuration:
644
-
645
- Make sure you have `android:windowSoftInputMode="adjustResize"` in your `AndroidManifest.xml`:
356
+ Add `android:windowSoftInputMode="adjustResize"` to your `AndroidManifest.xml`:
646
357
 
647
358
  ```xml
648
359
  <activity
649
360
  android:name=".MainActivity"
650
- android:label="@string/app_name"
651
361
  android:windowSoftInputMode="adjustResize"
652
362
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
653
363
  ```
654
364
 
655
- For **Expo**, you can append `KeyboardAvoidingView` after GiftedChat (Android only):
656
-
657
- ```jsx
658
- <View style={{ flex: 1 }}>
659
- <GiftedChat />
660
- {Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />}
661
- </View>
662
- ```
663
-
664
- </details>
665
-
666
365
  ### Web (react-native-web)
667
366
 
668
- <details>
669
- <summary><strong>With create-react-app</strong></summary>
670
-
671
- 1. Install react-app-rewired: `yarn add -D react-app-rewired`
672
- 2. Create `config-overrides.js`:
673
-
674
- ```js
675
- module.exports = function override(config, env) {
676
- config.module.rules.push({
677
- test: /\.js$/,
678
- exclude: /node_modules[/\\](?!react-native-gifted-chat)/,
679
- use: {
680
- loader: 'babel-loader',
681
- options: {
682
- babelrc: false,
683
- configFile: false,
684
- presets: [
685
- ['@babel/preset-env', { useBuiltIns: 'usage' }],
686
- '@babel/preset-react',
687
- ],
688
- plugins: ['@babel/plugin-proposal-class-properties'],
689
- },
690
- },
691
- })
692
- return config
693
- }
694
- ```
695
-
696
- > **Examples:**
697
- > - [xcarpentier/gifted-chat-web-demo](https://github.com/xcarpentier/gifted-chat-web-demo)
698
- > - [Gatsby example](https://github.com/xcarpentier/clean-archi-boilerplate/tree/develop/apps/web)
699
-
700
- </details>
367
+ `@legendapp/list` is pure JS and works with react-native-web. Follow the standard `react-native-web` webpack config to alias `react-native` imports.
701
368
 
702
369
  ---
703
370
 
704
- ## 🧪 Testing
705
-
706
- <details>
707
- <summary><strong>Triggering layout events in tests</strong></summary>
708
-
709
- `TEST_ID` is exported as constants that can be used in your testing library of choice.
710
-
711
- Gifted Chat uses `onLayout` to determine the height of the chat container. To trigger `onLayout` during your tests:
712
-
713
- ```typescript
714
- const WIDTH = 200
715
- const HEIGHT = 2000
716
-
717
- const loadingWrapper = getByTestId(TEST_ID.LOADING_WRAPPER)
718
- fireEvent(loadingWrapper, 'layout', {
719
- nativeEvent: {
720
- layout: {
721
- width: WIDTH,
722
- height: HEIGHT,
723
- },
724
- },
725
- })
726
- ```
727
-
728
- </details>
729
-
730
- ---
731
-
732
- ## 📦 Example App
733
-
734
- The repository includes a comprehensive example app demonstrating all features:
371
+ ## Contributing
735
372
 
736
373
  ```bash
737
- # Clone and install
738
- git clone https://github.com/FaridSafi/react-native-gifted-chat.git
739
- cd react-native-gifted-chat/example
740
374
  yarn install
741
-
742
- # Run on iOS
743
- npx expo run:ios
744
-
745
- # Run on Android
746
- npx expo run:android
747
-
748
- # Run on Web
749
- npx expo start --web
375
+ yarn build # outputs to lib/
376
+ yarn test # runs all tests
377
+ yarn lint # check for lint errors
378
+ yarn lint:fix # auto-fix lint errors
379
+ yarn prepublishOnly # full validation: lint + test + build
750
380
  ```
751
381
 
752
- The example app showcases:
753
- - 💬 Basic chat functionality
754
- - 🎨 Custom message bubbles and avatars
755
- - ↩️ Reply to messages with swipe gesture
756
- - ⚡ Quick replies (bot-style)
757
- - ✍️ Typing indicators
758
- - 📎 Attachment actions
759
- - 🔗 Link parsing and custom matchers
760
- - 🌐 Web compatibility
761
-
762
382
  ---
763
383
 
764
- ## ❓ Troubleshooting
765
-
766
- <details>
767
- <summary><strong>TextInput is hidden on Android</strong></summary>
768
-
769
- Make sure you have `android:windowSoftInputMode="adjustResize"` in your `AndroidManifest.xml`. See [Android configuration](#android) above.
770
-
771
- </details>
772
-
773
- <details>
774
- <summary><strong>How to set Bubble color for each user?</strong></summary>
775
-
776
- See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/672) for examples.
777
-
778
- </details>
779
-
780
- <details>
781
- <summary><strong>How to customize InputToolbar styles?</strong></summary>
782
-
783
- See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/662) for examples.
784
-
785
- </details>
786
-
787
- <details>
788
- <summary><strong>How to manually dismiss the keyboard?</strong></summary>
789
-
790
- See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/647) for examples.
791
-
792
- </details>
793
-
794
- <details>
795
- <summary><strong>How to use renderLoading?</strong></summary>
796
-
797
- See [this issue](https://github.com/FaridSafi/react-native-gifted-chat/issues/298) for examples.
798
-
799
- </details>
800
-
801
- ---
384
+ ## Credits
802
385
 
803
- ## 🤔 Have a Question?
386
+ Based on [react-native-gifted-chat](https://github.com/FaridSafi/react-native-gifted-chat) by [Farid Safi](https://www.x.com/FaridSafi) and [contributors](https://github.com/FaridSafi/react-native-gifted-chat/graphs/contributors).
804
387
 
805
- 1. Check this README first
806
- 2. Search [existing issues](https://github.com/FaridSafi/react-native-gifted-chat/issues)
807
- 3. Ask on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native-gifted-chat)
808
- 4. Open a new issue if needed
388
+ Performance improvements by [Sujeet Kumar](https://github.com/sujeetdotkumar).
809
389
 
810
390
  ---
811
391
 
812
- ## 🤝 Contributing
813
-
814
- Contributions are welcome! Please feel free to submit a Pull Request.
815
-
816
- 1. Fork the repository
817
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
818
- 3. Install dependencies (`yarn install`)
819
- 4. Make your changes
820
- 5. Run tests (`yarn test`)
821
- 6. Run linting (`yarn lint`)
822
- 7. Build the library (`yarn build`)
823
- 8. Commit your changes (`git commit -m 'Add amazing feature'`)
824
- 9. Push to the branch (`git push origin feature/amazing-feature`)
825
- 10. Open a Pull Request
826
-
827
- ### Development Setup
828
-
829
- ```bash
830
- # Install dependencies
831
- yarn install
832
-
833
- # Build the library
834
- yarn build
835
-
836
- # Run tests
837
- yarn test
838
-
839
- # Run linting
840
- yarn lint
841
-
842
- # Full validation
843
- yarn prepublishOnly
844
- ```
845
-
846
- ---
847
-
848
- ## 👥 Authors
849
-
850
- **Original Author:** [Farid Safi](https://www.x.com/FaridSafi)
851
-
852
- **Co-author:** [Xavier Carpentier](https://www.x.com/xcapetir) - [Hire Xavier](https://xaviercarpentier.com)
853
-
854
- **Maintainer:** [Kesha Antonov](https://github.com/kesha-antonov)
855
-
856
- > I've been maintaining this project for 2 years, completely in my free time and without any compensation. If you find it helpful, please consider [becoming a sponsor](https://github.com/sponsors/kesha-antonov) to support continued development. 💖
857
-
858
- ---
859
-
860
- ## 📄 License
392
+ ## License
861
393
 
862
394
  [MIT](LICENSE)
863
-
864
- ---
865
-
866
- <p align="center">
867
- <sub>Built with ❤️ by the React Native community</sub>
868
- </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sujeetdotkumar/react-native-gifted-chat-performant",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Performant chat UI for React Native — LegendList v3, native Intl, KeyboardChatLegendList",
5
5
  "keywords": [
6
6
  "android",