react-native-gifted-chat 3.0.0-alpha.0 → 3.0.0-alpha.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.
- package/README.md +60 -66
- package/package.json +2 -2
- package/src/GiftedChat/index.tsx +39 -125
- package/src/GiftedChat/types.ts +3 -6
- package/src/MessageContainer/index.tsx +2 -0
- package/src/MessageContainer/styles.ts +12 -5
- package/src/MessageImage.tsx +99 -66
- package/src/__tests__/GiftedChat.test.tsx +0 -28
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +31 -54
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<p align="center">
|
|
3
|
-
<a href="https://reactnative.gallery/FaridSafi/gifted-chat">
|
|
4
|
-
<img alt="react-native-gifted-chat" src="https://thumbs.gfycat.com/AbsoluteSadDobermanpinscher-size_restricted.gif" width="260" height="510" />
|
|
5
|
-
</a>
|
|
6
|
-
|
|
7
|
-
</p>
|
|
8
|
-
|
|
9
1
|
<h3 align="center">
|
|
10
2
|
💬 Gifted Chat
|
|
11
3
|
</h3>
|
|
@@ -16,26 +8,59 @@
|
|
|
16
8
|
<a href="https://www.npmjs.com/package/react-native-gifted-chat">
|
|
17
9
|
<img alt="npm downloads" src="https://img.shields.io/npm/dm/react-native-gifted-chat.svg"/></a>
|
|
18
10
|
<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
|
+
<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>
|
|
19
12
|
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<h3 align="center">
|
|
17
|
+
🚀 Try it now in your browser!
|
|
18
|
+
</h3>
|
|
20
19
|
<p align="center">
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<img src='https://img.shields.io/badge/license-MIT-blue.svg' />
|
|
20
|
+
<a href="https://snack.expo.dev/@kesha-antonov/gifted-chat-playground" target="_blank">
|
|
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"/>
|
|
24
22
|
</a>
|
|
25
|
-
<a href="#hire-an-expert"><img src="https://img.shields.io/badge/%F0%9F%92%AA-hire%20an%20expert-brightgreen"/></a>
|
|
26
23
|
</p>
|
|
24
|
+
<p align="center">
|
|
25
|
+
<strong>No installation required • Interactive examples • Edit and run in real-time</strong>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<br />
|
|
29
|
+
|
|
30
|
+
<!-- previews -->
|
|
27
31
|
|
|
28
32
|
<p align="center">
|
|
29
|
-
<
|
|
30
|
-
|
|
33
|
+
<img width="200" src="https://github.com/user-attachments/assets/c9da88f5-0b20-471c-8cd7-373bdb767517" />
|
|
34
|
+
|
|
35
|
+
<img width="200" src="https://github.com/user-attachments/assets/f72b17f1-6c2e-43b5-87e7-477011aa3b07" />
|
|
36
|
+
|
|
37
|
+
<img width="200" src="https://github.com/user-attachments/assets/86711e73-ee3c-4527-b38d-e4dab47a44fe" />
|
|
31
38
|
</p>
|
|
32
39
|
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- Fully customizable components
|
|
45
|
+
- Composer actions (to attach photos, etc.)
|
|
46
|
+
- Load earlier messages
|
|
47
|
+
- Copy messages to clipboard
|
|
48
|
+
- Touchable links using [react-native-autolink](https://github.com/joshswan/react-native-autolink)
|
|
49
|
+
- Avatar as user's initials
|
|
50
|
+
- Localized dates
|
|
51
|
+
- Multi-line TextInput
|
|
52
|
+
- InputToolbar avoiding keyboard
|
|
53
|
+
- System message
|
|
54
|
+
- Quick Reply messages (bot)
|
|
55
|
+
- Typing indicator
|
|
56
|
+
- react-native-web [web configuration](#react-native-web)
|
|
57
|
+
|
|
33
58
|
## Sponsor
|
|
34
59
|
|
|
35
60
|
<p align="center">
|
|
36
61
|
<br/>
|
|
37
62
|
<a href="https://www.lereacteur.io" target="_blank">
|
|
38
|
-
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/logo_sponsor.png">
|
|
63
|
+
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/logo_sponsor.png" height="60">
|
|
39
64
|
</a>
|
|
40
65
|
<br>
|
|
41
66
|
<p align="center">
|
|
@@ -51,7 +76,7 @@
|
|
|
51
76
|
<p align="center">
|
|
52
77
|
<br/>
|
|
53
78
|
<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">
|
|
54
|
-
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/stream-logo.png" height="
|
|
79
|
+
<img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/stream-logo.png" height="40">
|
|
55
80
|
</a>
|
|
56
81
|
<br>
|
|
57
82
|
<p align="center">
|
|
@@ -65,7 +90,7 @@
|
|
|
65
90
|
<p align="center">
|
|
66
91
|
<br/>
|
|
67
92
|
<a href="https://www.ethora.com" target="_blank">
|
|
68
|
-
<img src="https://www.dappros.com/wp-content/uploads/2023/12/Ethora-Logo.png"
|
|
93
|
+
<img src="https://www.dappros.com/wp-content/uploads/2023/12/Ethora-Logo.png" height="60">
|
|
69
94
|
</a>
|
|
70
95
|
<br>
|
|
71
96
|
<p align="center">
|
|
@@ -80,50 +105,26 @@
|
|
|
80
105
|
<a href="https://amzn.to/3ZmTyb2" target="_blank">React Key Concepts: Consolidate your knowledge of React’s core features (2nd ed. Edition)</a>
|
|
81
106
|
</p>
|
|
82
107
|
|
|
83
|
-
## Features
|
|
84
|
-
|
|
85
|
-
- Fully customizable components
|
|
86
|
-
- Composer actions (to attach photos, etc.)
|
|
87
|
-
- Load earlier messages
|
|
88
|
-
- Copy messages to clipboard
|
|
89
|
-
- Touchable links using [react-native-autolink](https://github.com/joshswan/react-native-autolink)
|
|
90
|
-
- Avatar as user's initials
|
|
91
|
-
- Localized dates
|
|
92
|
-
- Multi-line TextInput
|
|
93
|
-
- InputToolbar avoiding keyboard
|
|
94
|
-
- System message
|
|
95
|
-
- Quick Reply messages (bot)
|
|
96
|
-
- Typing indicator
|
|
97
|
-
- react-native-web [web configuration](#react-native-web)
|
|
98
|
-
|
|
99
108
|
# Getting started
|
|
100
109
|
|
|
101
|
-
## 🚧👷 Important notice
|
|
102
|
-
|
|
103
|
-
There's currently WIP going on to make the library more performant, modern in terms of chat UI and easier to maintain. If you have any issues, please report them. If you want to contribute, please do so.
|
|
104
|
-
|
|
105
|
-
The most stable version is `2.6.5`. If you want to use the latest version, please be aware that it's a work in progress.
|
|
106
|
-
|
|
107
|
-
Readme for this version: [2.6.5 readme](https://github.com/FaridSafi/react-native-gifted-chat/blob/eebab3751fcbe07715135e6e7b2aa3f76a10d8ac/README.md)
|
|
108
|
-
|
|
109
110
|
## Installation
|
|
110
111
|
|
|
111
112
|
### Install dependencies
|
|
112
113
|
|
|
113
114
|
Yarn:
|
|
114
115
|
```bash
|
|
115
|
-
yarn add react-native-gifted-chat react-native-reanimated react-native-
|
|
116
|
+
yarn add react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
116
117
|
```
|
|
117
118
|
|
|
118
119
|
Npm:
|
|
119
120
|
|
|
120
121
|
```bash
|
|
121
|
-
npm install --save react-native-gifted-chat react-native-reanimated react-native-
|
|
122
|
+
npm install --save react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
122
123
|
```
|
|
123
124
|
|
|
124
125
|
Expo
|
|
125
126
|
```bash
|
|
126
|
-
npx expo install react-native-gifted-chat react-native-reanimated react-native-
|
|
127
|
+
npx expo install react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
|
|
127
128
|
```
|
|
128
129
|
|
|
129
130
|
### Non-expo users
|
|
@@ -136,7 +137,9 @@ npx pod-install
|
|
|
136
137
|
|
|
137
138
|
Follow guide: [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#step-2-add-reanimateds-babel-plugin)
|
|
138
139
|
|
|
139
|
-
##
|
|
140
|
+
## Examples
|
|
141
|
+
|
|
142
|
+
### Basic usage
|
|
140
143
|
|
|
141
144
|
```jsx
|
|
142
145
|
import React, { useState, useCallback, useEffect } from 'react'
|
|
@@ -149,7 +152,7 @@ export function Example() {
|
|
|
149
152
|
|
|
150
153
|
// If you have a tab bar, include its height
|
|
151
154
|
const tabbarHeight = 50
|
|
152
|
-
const
|
|
155
|
+
const keyboardVerticalOffset = insets.bottom + tabbarHeight
|
|
153
156
|
|
|
154
157
|
useEffect(() => {
|
|
155
158
|
setMessages([
|
|
@@ -179,13 +182,14 @@ export function Example() {
|
|
|
179
182
|
user={{
|
|
180
183
|
_id: 1,
|
|
181
184
|
}}
|
|
182
|
-
|
|
185
|
+
|
|
186
|
+
keyboardAvoidingViewProps={{ keyboardVerticalOffset }}
|
|
183
187
|
/>
|
|
184
188
|
)
|
|
185
189
|
}
|
|
186
190
|
```
|
|
187
191
|
|
|
188
|
-
|
|
192
|
+
### Other examples
|
|
189
193
|
|
|
190
194
|
Check out code of [`examples`](example)
|
|
191
195
|
|
|
@@ -210,9 +214,8 @@ Messages, system messages, quick replies etc.: [data structure](src/Models.ts)
|
|
|
210
214
|
|
|
211
215
|
### Keyboard & Layout
|
|
212
216
|
|
|
213
|
-
- **`
|
|
214
|
-
- **`
|
|
215
|
-
- **`shouldFocusInputOnKeyboardOpen`** _(Bool)_ - Focus on <TextInput> automatically when opening the keyboard; default `true`
|
|
217
|
+
- **`keyboardProviderProps`** _(Object)_ - Props to be passed to the [`KeyboardProvider`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-provider) for keyboard handling.
|
|
218
|
+
- **`keyboardAvoidingViewProps`** _(Object)_ - Props to be passed to the [`KeyboardAvoidingView`](https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-avoiding-view). The `behavior` prop defaults to `'padding'`.
|
|
216
219
|
- **`isAlignedTop`** _(Boolean)_ Controls whether or not the message bubbles appear at the top of the chat (Default is false - bubbles align to bottom)
|
|
217
220
|
- **`isInverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
|
|
218
221
|
|
|
@@ -509,25 +512,16 @@ fireEvent(loadingWrapper, 'layout', {
|
|
|
509
512
|
1. Find responses in existing issues
|
|
510
513
|
1. Try to keep issues for issues
|
|
511
514
|
|
|
512
|
-
##
|
|
515
|
+
## Hire an expert
|
|
513
516
|
|
|
514
|
-
|
|
517
|
+
Looking for a React Native freelance expert with more than 14 years of experience? Contact Xavier from his [website](https://xaviercarpentier.com)
|
|
515
518
|
|
|
516
519
|
## Author
|
|
517
520
|
|
|
518
|
-
Feel free to ask me questions on Twitter [@FaridSafi](https://www.twitter.com/FaridSafi)
|
|
519
|
-
|
|
520
|
-
## Contributors
|
|
521
|
-
|
|
522
|
-
- Kevin Cooper [cooperka](https://github.com/cooperka)
|
|
523
|
-
- Kfir Golan [kfiroo](https://github.com/kfiroo)
|
|
524
|
-
- Bruno Cascio [brunocascio](https://github.com/brunocascio)
|
|
525
|
-
- Xavier Carpentier [xcarpentier](https://github.com/xcarpentier)
|
|
526
|
-
- Kesha Antonov [kesha-antonov](https://github.com/kesha-antonov)
|
|
527
|
-
- [more](https://github.com/FaridSafi/react-native-gifted-chat/graphs/contributors)
|
|
521
|
+
Feel free to ask me questions on Twitter [@FaridSafi](https://www.twitter.com/FaridSafi) or [@xcapetir](https://www.twitter.com/xcapetir)
|
|
528
522
|
|
|
529
|
-
##
|
|
523
|
+
## Maintainer
|
|
530
524
|
|
|
531
|
-
|
|
525
|
+
Have any questions? Reach out to [Kesha Antonov](https://github.com/kesha-antonov)
|
|
532
526
|
|
|
533
|
-
|
|
527
|
+
Please note that I'm maintaining this project in my free time for free. If you find any issues, feel free to open them, and I'll do my best to address them as time permits.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-gifted-chat",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"description": "The most complete chat UI for React Native",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"android",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"react-dom": "19.1.0",
|
|
95
95
|
"react-native": "0.81.5",
|
|
96
96
|
"react-native-gesture-handler": "^2.29.1",
|
|
97
|
-
"react-native-keyboard-controller": "^1.19.
|
|
97
|
+
"react-native-keyboard-controller": "^1.19.6",
|
|
98
98
|
"react-native-reanimated": "^3.19.4",
|
|
99
99
|
"react-native-safe-area-context": "^5.6.2",
|
|
100
100
|
"react-test-renderer": "19.1.0",
|
package/src/GiftedChat/index.tsx
CHANGED
|
@@ -19,14 +19,7 @@ import {
|
|
|
19
19
|
import dayjs from 'dayjs'
|
|
20
20
|
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
|
21
21
|
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
22
|
-
import {
|
|
23
|
-
import Animated, {
|
|
24
|
-
useAnimatedStyle,
|
|
25
|
-
useAnimatedReaction,
|
|
26
|
-
useSharedValue,
|
|
27
|
-
withTiming,
|
|
28
|
-
runOnJS,
|
|
29
|
-
} from 'react-native-reanimated'
|
|
22
|
+
import { KeyboardAvoidingView, KeyboardProvider } from 'react-native-keyboard-controller'
|
|
30
23
|
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
|
31
24
|
import { MAX_COMPOSER_HEIGHT, MIN_COMPOSER_HEIGHT, TEST_ID } from '../Constant'
|
|
32
25
|
import { GiftedChatContext } from '../GiftedChatContext'
|
|
@@ -61,12 +54,9 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
61
54
|
textInputProps,
|
|
62
55
|
renderChatFooter,
|
|
63
56
|
renderInputToolbar,
|
|
64
|
-
keyboardBottomOffset = 0,
|
|
65
|
-
shouldFocusInputOnKeyboardOpen = true,
|
|
66
57
|
isInverted = true,
|
|
67
58
|
minComposerHeight = MIN_COMPOSER_HEIGHT,
|
|
68
59
|
maxComposerHeight = MAX_COMPOSER_HEIGHT,
|
|
69
|
-
isKeyboardInternallyHandled = true,
|
|
70
60
|
} = props
|
|
71
61
|
|
|
72
62
|
const actionSheetRef = useRef<ActionSheetProviderRef>(null)
|
|
@@ -81,37 +71,12 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
81
71
|
[props.textInputRef]
|
|
82
72
|
)
|
|
83
73
|
|
|
84
|
-
const isTextInputWasFocused: RefObject<boolean> = useRef(false)
|
|
85
|
-
|
|
86
74
|
const [isInitialized, setIsInitialized] = useState<boolean>(false)
|
|
87
75
|
const [composerHeight, setComposerHeight] = useState<number>(
|
|
88
76
|
minComposerHeight!
|
|
89
77
|
)
|
|
90
78
|
const [text, setText] = useState<string | undefined>(() => props.text || '')
|
|
91
79
|
|
|
92
|
-
// Always call the hook, but conditionally use its data
|
|
93
|
-
const keyboardControllerData = useReanimatedKeyboardAnimation()
|
|
94
|
-
|
|
95
|
-
// Create a mock keyboard object when keyboard is not internally handled
|
|
96
|
-
const keyboard = useMemo(() => {
|
|
97
|
-
if (!isKeyboardInternallyHandled)
|
|
98
|
-
return { height: { value: 0 } }
|
|
99
|
-
|
|
100
|
-
return keyboardControllerData
|
|
101
|
-
}, [isKeyboardInternallyHandled, keyboardControllerData])
|
|
102
|
-
|
|
103
|
-
const trackingKeyboardMovement = useSharedValue(false)
|
|
104
|
-
const keyboardBottomOffsetAnim = useSharedValue(0)
|
|
105
|
-
|
|
106
|
-
const contentStyleAnim = useAnimatedStyle(
|
|
107
|
-
() => ({
|
|
108
|
-
transform: [
|
|
109
|
-
{ translateY: keyboard.height.value + keyboardBottomOffsetAnim.value },
|
|
110
|
-
],
|
|
111
|
-
}),
|
|
112
|
-
[keyboard, keyboardBottomOffsetAnim]
|
|
113
|
-
)
|
|
114
|
-
|
|
115
80
|
const getTextFromProp = useCallback(
|
|
116
81
|
(fallback: string) => {
|
|
117
82
|
if (props.text === undefined)
|
|
@@ -122,34 +87,6 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
122
87
|
[props.text]
|
|
123
88
|
)
|
|
124
89
|
|
|
125
|
-
/**
|
|
126
|
-
* Store text input focus status when keyboard hide to retrieve
|
|
127
|
-
* it afterwards if needed.
|
|
128
|
-
* `onKeyboardWillHide` may be called twice in sequence so we
|
|
129
|
-
* make a guard condition (eg. showing image picker)
|
|
130
|
-
*/
|
|
131
|
-
const handleTextInputFocusWhenKeyboardHide = useCallback(() => {
|
|
132
|
-
if (!isTextInputWasFocused.current)
|
|
133
|
-
isTextInputWasFocused.current =
|
|
134
|
-
textInputRef.current?.isFocused() || false
|
|
135
|
-
}, [textInputRef])
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Refocus the text input only if it was focused before showing keyboard.
|
|
139
|
-
* This is needed in some cases (eg. showing image picker).
|
|
140
|
-
*/
|
|
141
|
-
const handleTextInputFocusWhenKeyboardShow = useCallback(() => {
|
|
142
|
-
if (
|
|
143
|
-
textInputRef.current &&
|
|
144
|
-
isTextInputWasFocused.current &&
|
|
145
|
-
!textInputRef.current.isFocused()
|
|
146
|
-
)
|
|
147
|
-
textInputRef.current.focus()
|
|
148
|
-
|
|
149
|
-
// Reset the indicator since the keyboard is shown
|
|
150
|
-
isTextInputWasFocused.current = false
|
|
151
|
-
}, [textInputRef])
|
|
152
|
-
|
|
153
90
|
const scrollToBottom = useCallback(
|
|
154
91
|
(isAnimated = true) => {
|
|
155
92
|
if (!messageContainerRef?.current)
|
|
@@ -334,78 +271,55 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
334
271
|
setText(props.text)
|
|
335
272
|
}, [props.text])
|
|
336
273
|
|
|
337
|
-
// Only set up keyboard animation when keyboard is internally handled
|
|
338
|
-
useAnimatedReaction(
|
|
339
|
-
() => isKeyboardInternallyHandled ? keyboard.height.value : 0,
|
|
340
|
-
(value, prevValue) => {
|
|
341
|
-
// Skip keyboard handling when not internally handled
|
|
342
|
-
if (!isKeyboardInternallyHandled)
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
if (prevValue !== null && value !== prevValue) {
|
|
346
|
-
const isKeyboardMovingUp = value < prevValue
|
|
347
|
-
if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
|
|
348
|
-
trackingKeyboardMovement.value = isKeyboardMovingUp
|
|
349
|
-
keyboardBottomOffsetAnim.value = withTiming(
|
|
350
|
-
isKeyboardMovingUp ? keyboardBottomOffset : 0,
|
|
351
|
-
{
|
|
352
|
-
// If `keyboardBottomOffset` exists, we change the duration to a smaller value to fix the delay in the keyboard animation speed
|
|
353
|
-
duration: keyboardBottomOffset ? 150 : 400,
|
|
354
|
-
}
|
|
355
|
-
)
|
|
356
|
-
|
|
357
|
-
if (shouldFocusInputOnKeyboardOpen)
|
|
358
|
-
if (isKeyboardMovingUp)
|
|
359
|
-
runOnJS(handleTextInputFocusWhenKeyboardShow)()
|
|
360
|
-
else
|
|
361
|
-
runOnJS(handleTextInputFocusWhenKeyboardHide)()
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
[
|
|
366
|
-
keyboard,
|
|
367
|
-
trackingKeyboardMovement,
|
|
368
|
-
shouldFocusInputOnKeyboardOpen,
|
|
369
|
-
handleTextInputFocusWhenKeyboardHide,
|
|
370
|
-
handleTextInputFocusWhenKeyboardShow,
|
|
371
|
-
keyboardBottomOffset,
|
|
372
|
-
isKeyboardInternallyHandled,
|
|
373
|
-
]
|
|
374
|
-
)
|
|
375
|
-
|
|
376
274
|
return (
|
|
377
275
|
<GiftedChatContext.Provider value={contextValues}>
|
|
378
276
|
<ActionSheetProvider ref={actionSheetRef}>
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
277
|
+
{/* @ts-expect-error */}
|
|
278
|
+
<KeyboardAvoidingView
|
|
279
|
+
behavior='padding'
|
|
280
|
+
style={stylesCommon.fill}
|
|
281
|
+
{...props.keyboardAvoidingViewProps}
|
|
383
282
|
>
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
283
|
+
<View
|
|
284
|
+
testID={TEST_ID.WRAPPER}
|
|
285
|
+
style={[stylesCommon.fill, styles.contentContainer]}
|
|
286
|
+
onLayout={onInitialLayoutViewLayout}
|
|
287
|
+
>
|
|
288
|
+
{isInitialized
|
|
289
|
+
? (
|
|
290
|
+
<>
|
|
291
|
+
{renderMessages}
|
|
292
|
+
{inputToolbarFragment}
|
|
293
|
+
</>
|
|
294
|
+
)
|
|
295
|
+
: (
|
|
296
|
+
renderComponentOrElement(renderLoading, {})
|
|
297
|
+
)}
|
|
298
|
+
</View>
|
|
299
|
+
</KeyboardAvoidingView>
|
|
395
300
|
</ActionSheetProvider>
|
|
396
301
|
</GiftedChatContext.Provider>
|
|
397
302
|
)
|
|
398
303
|
}
|
|
399
304
|
|
|
400
305
|
function GiftedChatWrapper<TMessage extends IMessage = IMessage> (props: GiftedChatProps<TMessage>) {
|
|
306
|
+
const {
|
|
307
|
+
keyboardProviderProps,
|
|
308
|
+
...rest
|
|
309
|
+
} = props
|
|
310
|
+
|
|
401
311
|
return (
|
|
402
|
-
<
|
|
403
|
-
<
|
|
404
|
-
<
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
312
|
+
<GestureHandlerRootView style={styles.fill}>
|
|
313
|
+
<SafeAreaProvider>
|
|
314
|
+
<KeyboardProvider
|
|
315
|
+
statusBarTranslucent
|
|
316
|
+
navigationBarTranslucent
|
|
317
|
+
{...keyboardProviderProps}
|
|
318
|
+
>
|
|
319
|
+
<GiftedChat<TMessage> {...rest} />
|
|
320
|
+
</KeyboardProvider>
|
|
321
|
+
</SafeAreaProvider>
|
|
322
|
+
</GestureHandlerRootView>
|
|
409
323
|
)
|
|
410
324
|
}
|
|
411
325
|
|
package/src/GiftedChat/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
ActionSheetOptions,
|
|
10
10
|
} from '@expo/react-native-action-sheet'
|
|
11
|
+
import { KeyboardProvider, KeyboardAvoidingViewProps } from 'react-native-keyboard-controller'
|
|
11
12
|
import { ActionsProps } from '../Actions'
|
|
12
13
|
import { AvatarProps } from '../Avatar'
|
|
13
14
|
import { BubbleProps } from '../Bubble'
|
|
@@ -50,8 +51,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
50
51
|
dateFormat?: string
|
|
51
52
|
/* Format to use for rendering relative times; Today - for now. See more: https://day.js.org/docs/en/plugin/calendar */
|
|
52
53
|
dateFormatCalendar?: object
|
|
53
|
-
/* Determine whether to handle keyboard awareness inside the plugin. If you have your own keyboard handling outside the plugin set this to false; default is `true` */
|
|
54
|
-
isKeyboardInternallyHandled?: boolean
|
|
55
54
|
/* Whether to render an avatar for the current user; default is false, only show avatars for other users */
|
|
56
55
|
isUserAvatarVisible?: boolean
|
|
57
56
|
/* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
|
|
@@ -60,10 +59,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
60
59
|
isAvatarOnTop?: boolean
|
|
61
60
|
/* Extra props to be passed to the <Image> component created by the default renderMessageImage */
|
|
62
61
|
imageProps?: MessageImageProps<TMessage>
|
|
63
|
-
/* Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar); default is 0 */
|
|
64
|
-
keyboardBottomOffset?: number
|
|
65
|
-
/* Focus on <TextInput> automatically when opening the keyboard; default is true */
|
|
66
|
-
shouldFocusInputOnKeyboardOpen?: boolean
|
|
67
62
|
/* Minimum height of the input toolbar; default is 44 */
|
|
68
63
|
minInputToolbarHeight?: number
|
|
69
64
|
/* Extra props to be passed to the <TextInput>. See https://reactnative.dev/docs/textinput */
|
|
@@ -146,4 +141,6 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
146
141
|
quickReplies: QuickRepliesProps<TMessage>,
|
|
147
142
|
) => React.ReactNode
|
|
148
143
|
renderQuickReplySend?: () => React.ReactNode
|
|
144
|
+
keyboardProviderProps?: React.ComponentProps<typeof KeyboardProvider>
|
|
145
|
+
keyboardAvoidingViewProps?: KeyboardAvoidingViewProps
|
|
149
146
|
}
|
|
@@ -401,6 +401,8 @@ export const MessageContainer = <TMessage extends IMessage>(props: MessageContai
|
|
|
401
401
|
scrollEventThrottle={1}
|
|
402
402
|
onEndReached={onEndReached}
|
|
403
403
|
onEndReachedThreshold={0.1}
|
|
404
|
+
keyboardDismissMode='interactive'
|
|
405
|
+
keyboardShouldPersistTaps='handled'
|
|
404
406
|
{...listProps}
|
|
405
407
|
onScroll={scrollHandler}
|
|
406
408
|
onLayout={onLayoutList}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native'
|
|
1
|
+
import { Platform, StyleSheet } from 'react-native'
|
|
2
2
|
import { Color } from '../Color'
|
|
3
3
|
|
|
4
4
|
export default StyleSheet.create({
|
|
@@ -24,9 +24,16 @@ export default StyleSheet.create({
|
|
|
24
24
|
width: 40,
|
|
25
25
|
borderRadius: 20,
|
|
26
26
|
backgroundColor: Color.white,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
...Platform.select({
|
|
28
|
+
ios: {
|
|
29
|
+
shadowColor: Color.black,
|
|
30
|
+
shadowOpacity: 0.5,
|
|
31
|
+
shadowOffset: { width: 0, height: 0 },
|
|
32
|
+
shadowRadius: 1,
|
|
33
|
+
},
|
|
34
|
+
android: {
|
|
35
|
+
elevation: 5,
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
31
38
|
},
|
|
32
39
|
})
|
package/src/MessageImage.tsx
CHANGED
|
@@ -8,47 +8,25 @@ import {
|
|
|
8
8
|
StyleProp,
|
|
9
9
|
ImageStyle,
|
|
10
10
|
ImageURISource,
|
|
11
|
-
Modal,
|
|
12
11
|
TouchableOpacity,
|
|
13
12
|
LayoutChangeEvent,
|
|
14
13
|
useWindowDimensions,
|
|
14
|
+
StatusBar,
|
|
15
15
|
} from 'react-native'
|
|
16
16
|
import { BaseButton, GestureHandlerRootView, Text } from 'react-native-gesture-handler'
|
|
17
|
+
import { OverKeyboardView } from 'react-native-keyboard-controller'
|
|
18
|
+
import Animated, {
|
|
19
|
+
useAnimatedStyle,
|
|
20
|
+
useSharedValue,
|
|
21
|
+
withTiming,
|
|
22
|
+
runOnJS,
|
|
23
|
+
Easing,
|
|
24
|
+
} from 'react-native-reanimated'
|
|
17
25
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
18
26
|
import Zoom from 'react-native-zoom-reanimated'
|
|
19
27
|
import { IMessage } from './Models'
|
|
20
28
|
import commonStyles from './styles'
|
|
21
29
|
|
|
22
|
-
const styles = StyleSheet.create({
|
|
23
|
-
image: {
|
|
24
|
-
width: 150,
|
|
25
|
-
height: 100,
|
|
26
|
-
borderRadius: 13,
|
|
27
|
-
margin: 3,
|
|
28
|
-
resizeMode: 'cover',
|
|
29
|
-
},
|
|
30
|
-
modalContent: {
|
|
31
|
-
backgroundColor: '#000',
|
|
32
|
-
},
|
|
33
|
-
modalImageContainer: {
|
|
34
|
-
width: '100%',
|
|
35
|
-
height: '100%',
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
closeButtonContainer: {
|
|
39
|
-
flexDirection: 'row',
|
|
40
|
-
justifyContent: 'flex-end',
|
|
41
|
-
},
|
|
42
|
-
closeButtonContent: {
|
|
43
|
-
padding: 10,
|
|
44
|
-
},
|
|
45
|
-
closeButtonIcon: {
|
|
46
|
-
fontSize: 20,
|
|
47
|
-
lineHeight: 20,
|
|
48
|
-
color: 'white',
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
|
|
52
30
|
export interface MessageImageProps<TMessage extends IMessage> {
|
|
53
31
|
currentMessage: TMessage
|
|
54
32
|
containerStyle?: StyleProp<ViewStyle>
|
|
@@ -70,6 +48,10 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
|
|
|
70
48
|
|
|
71
49
|
const insets = useSafeAreaInsets()
|
|
72
50
|
|
|
51
|
+
// Animation values
|
|
52
|
+
const modalOpacity = useSharedValue(0)
|
|
53
|
+
const modalScale = useSharedValue(0.9)
|
|
54
|
+
|
|
73
55
|
const imageSource = useMemo(() => ({
|
|
74
56
|
...imageSourceProps,
|
|
75
57
|
uri: currentMessage?.image,
|
|
@@ -88,15 +70,23 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
|
|
|
88
70
|
|
|
89
71
|
setIsModalVisible(true)
|
|
90
72
|
|
|
73
|
+
// Animate modal entrance
|
|
74
|
+
modalOpacity.value = withTiming(1, { duration: 300, easing: Easing.out(Easing.ease) })
|
|
75
|
+
modalScale.value = withTiming(1, { duration: 300, easing: Easing.out(Easing.ease) })
|
|
76
|
+
|
|
91
77
|
if (isImageSourceChanged.current || !imageDimensions)
|
|
92
78
|
Image.getSize(imageSource.uri, (width, height) => {
|
|
93
79
|
setImageDimensions({ width, height })
|
|
94
80
|
})
|
|
95
|
-
}, [imageSource.uri, imageDimensions])
|
|
81
|
+
}, [imageSource.uri, imageDimensions, modalOpacity, modalScale])
|
|
96
82
|
|
|
97
83
|
const handleModalClose = useCallback(() => {
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
// Animate modal exit
|
|
85
|
+
modalOpacity.value = withTiming(0, { duration: 200, easing: Easing.in(Easing.ease) })
|
|
86
|
+
modalScale.value = withTiming(0.9, { duration: 200, easing: Easing.in(Easing.ease) }, () => {
|
|
87
|
+
runOnJS(setIsModalVisible)(false)
|
|
88
|
+
})
|
|
89
|
+
}, [modalOpacity, modalScale])
|
|
100
90
|
|
|
101
91
|
const handleImageLayout = useCallback((e: LayoutChangeEvent) => {
|
|
102
92
|
setImageDimensions({
|
|
@@ -125,6 +115,11 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
|
|
|
125
115
|
}
|
|
126
116
|
}, [imageDimensions, windowDimensions.height, windowDimensions.width])
|
|
127
117
|
|
|
118
|
+
const modalAnimatedStyle = useAnimatedStyle(() => ({
|
|
119
|
+
opacity: modalOpacity.value,
|
|
120
|
+
transform: [{ scale: modalScale.value }],
|
|
121
|
+
}), [modalOpacity, modalScale])
|
|
122
|
+
|
|
128
123
|
useEffect(() => {
|
|
129
124
|
isImageSourceChanged.current = true
|
|
130
125
|
}, [imageSource.uri])
|
|
@@ -140,42 +135,80 @@ export function MessageImage<TMessage extends IMessage = IMessage> ({
|
|
|
140
135
|
style={computedImageStyle}
|
|
141
136
|
source={imageSource}
|
|
142
137
|
onLayout={handleImageLayout}
|
|
138
|
+
resizeMode='cover'
|
|
143
139
|
/>
|
|
144
140
|
</TouchableOpacity>
|
|
145
141
|
|
|
146
|
-
|
|
147
|
-
visible={isModalVisible}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
</
|
|
142
|
+
{isModalVisible && (
|
|
143
|
+
<OverKeyboardView visible={isModalVisible}>
|
|
144
|
+
<StatusBar animated barStyle='dark-content' />
|
|
145
|
+
<Animated.View style={[styles.modalOverlay, modalAnimatedStyle]}>
|
|
146
|
+
<GestureHandlerRootView style={commonStyles.fill}>
|
|
147
|
+
<View style={[commonStyles.fill, styles.modalContent, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
|
|
148
|
+
|
|
149
|
+
{/* close button */}
|
|
150
|
+
<View style={styles.closeButtonContainer}>
|
|
151
|
+
<BaseButton onPress={handleModalClose}>
|
|
152
|
+
<View style={styles.closeButtonContent}>
|
|
153
|
+
<Text style={styles.closeButtonIcon}>
|
|
154
|
+
{'X'}
|
|
155
|
+
</Text>
|
|
156
|
+
</View>
|
|
157
|
+
</BaseButton>
|
|
158
|
+
</View>
|
|
159
|
+
|
|
160
|
+
<View style={[commonStyles.fill, commonStyles.centerItems]}>
|
|
161
|
+
<Zoom>
|
|
162
|
+
<Image
|
|
163
|
+
style={modalImageDimensions}
|
|
164
|
+
source={imageSource}
|
|
165
|
+
resizeMode='contain'
|
|
166
|
+
{...imageProps}
|
|
167
|
+
/>
|
|
168
|
+
</Zoom>
|
|
162
169
|
</View>
|
|
163
|
-
</
|
|
164
|
-
</
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<Image
|
|
169
|
-
style={modalImageDimensions}
|
|
170
|
-
source={imageSource}
|
|
171
|
-
resizeMode='contain'
|
|
172
|
-
{...imageProps}
|
|
173
|
-
/>
|
|
174
|
-
</Zoom>
|
|
175
|
-
</View>
|
|
176
|
-
</View>
|
|
177
|
-
</GestureHandlerRootView>
|
|
178
|
-
</Modal>
|
|
170
|
+
</View>
|
|
171
|
+
</GestureHandlerRootView>
|
|
172
|
+
</Animated.View>
|
|
173
|
+
</OverKeyboardView>
|
|
174
|
+
)}
|
|
179
175
|
</View>
|
|
180
176
|
)
|
|
181
177
|
}
|
|
178
|
+
|
|
179
|
+
const styles = StyleSheet.create({
|
|
180
|
+
image: {
|
|
181
|
+
width: 150,
|
|
182
|
+
height: 100,
|
|
183
|
+
borderRadius: 13,
|
|
184
|
+
margin: 3,
|
|
185
|
+
},
|
|
186
|
+
modalOverlay: {
|
|
187
|
+
position: 'absolute',
|
|
188
|
+
top: 0,
|
|
189
|
+
left: 0,
|
|
190
|
+
right: 0,
|
|
191
|
+
bottom: 0,
|
|
192
|
+
zIndex: 1000,
|
|
193
|
+
},
|
|
194
|
+
modalContent: {
|
|
195
|
+
backgroundColor: '#000',
|
|
196
|
+
},
|
|
197
|
+
modalImageContainer: {
|
|
198
|
+
width: '100%',
|
|
199
|
+
height: '100%',
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
closeButtonContainer: {
|
|
203
|
+
flexDirection: 'row',
|
|
204
|
+
justifyContent: 'flex-end',
|
|
205
|
+
},
|
|
206
|
+
closeButtonContent: {
|
|
207
|
+
padding: 20,
|
|
208
|
+
},
|
|
209
|
+
closeButtonIcon: {
|
|
210
|
+
fontSize: 20,
|
|
211
|
+
lineHeight: 20,
|
|
212
|
+
color: 'white',
|
|
213
|
+
},
|
|
214
|
+
})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { render } from '@testing-library/react-native'
|
|
3
3
|
|
|
4
|
-
import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'
|
|
5
4
|
import { GiftedChat } from '..'
|
|
6
5
|
|
|
7
6
|
const messages = [
|
|
@@ -17,32 +16,6 @@ const messages = [
|
|
|
17
16
|
]
|
|
18
17
|
|
|
19
18
|
it('should render <GiftedChat/> and compare with snapshot', () => {
|
|
20
|
-
(useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
|
|
21
|
-
height: {
|
|
22
|
-
value: 0,
|
|
23
|
-
},
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
const { toJSON } = render(
|
|
27
|
-
<GiftedChat
|
|
28
|
-
messages={messages}
|
|
29
|
-
onSend={() => {}}
|
|
30
|
-
user={{
|
|
31
|
-
_id: 1,
|
|
32
|
-
}}
|
|
33
|
-
/>
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
expect(toJSON()).toMatchSnapshot()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should render <GiftedChat/> with isKeyboardInternallyHandled=false', () => {
|
|
40
|
-
(useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
|
|
41
|
-
height: {
|
|
42
|
-
value: 0,
|
|
43
|
-
},
|
|
44
|
-
})
|
|
45
|
-
|
|
46
19
|
const { toJSON } = render(
|
|
47
20
|
<GiftedChat
|
|
48
21
|
messages={messages}
|
|
@@ -50,7 +23,6 @@ it('should render <GiftedChat/> with isKeyboardInternallyHandled=false', () => {
|
|
|
50
23
|
user={{
|
|
51
24
|
_id: 1,
|
|
52
25
|
}}
|
|
53
|
-
isKeyboardInternallyHandled={false}
|
|
54
26
|
/>
|
|
55
27
|
)
|
|
56
28
|
|
|
@@ -1,48 +1,16 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`should render <GiftedChat/> and compare with snapshot 1`] = `
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"flex": 1,
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
>
|
|
12
|
-
<View
|
|
13
|
-
style={
|
|
14
|
-
{
|
|
15
|
-
"flex": 1,
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
>
|
|
19
|
-
<View
|
|
20
|
-
onLayout={[Function]}
|
|
21
|
-
style={
|
|
22
|
-
[
|
|
23
|
-
{
|
|
24
|
-
"flex": 1,
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"overflow": "hidden",
|
|
28
|
-
},
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
testID="GC_WRAPPER"
|
|
32
|
-
/>
|
|
33
|
-
</View>
|
|
34
|
-
</View>
|
|
35
|
-
</KeyboardProvider>
|
|
36
|
-
`;
|
|
37
|
-
|
|
38
|
-
exports[`should render <GiftedChat/> with isKeyboardInternallyHandled=false 1`] = `
|
|
39
|
-
<KeyboardProvider>
|
|
40
|
-
<View
|
|
41
|
-
style={
|
|
42
|
-
{
|
|
43
|
-
"flex": 1,
|
|
44
|
-
}
|
|
4
|
+
<View
|
|
5
|
+
style={
|
|
6
|
+
{
|
|
7
|
+
"flex": 1,
|
|
45
8
|
}
|
|
9
|
+
}
|
|
10
|
+
>
|
|
11
|
+
<KeyboardProvider
|
|
12
|
+
navigationBarTranslucent={true}
|
|
13
|
+
statusBarTranslucent={true}
|
|
46
14
|
>
|
|
47
15
|
<View
|
|
48
16
|
style={
|
|
@@ -52,20 +20,29 @@ exports[`should render <GiftedChat/> with isKeyboardInternallyHandled=false 1`]
|
|
|
52
20
|
}
|
|
53
21
|
>
|
|
54
22
|
<View
|
|
55
|
-
|
|
23
|
+
behavior="padding"
|
|
56
24
|
style={
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"overflow": "hidden",
|
|
63
|
-
},
|
|
64
|
-
]
|
|
25
|
+
{
|
|
26
|
+
"flex": 1,
|
|
27
|
+
}
|
|
65
28
|
}
|
|
66
|
-
|
|
67
|
-
|
|
29
|
+
>
|
|
30
|
+
<View
|
|
31
|
+
onLayout={[Function]}
|
|
32
|
+
style={
|
|
33
|
+
[
|
|
34
|
+
{
|
|
35
|
+
"flex": 1,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"overflow": "hidden",
|
|
39
|
+
},
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
testID="GC_WRAPPER"
|
|
43
|
+
/>
|
|
44
|
+
</View>
|
|
68
45
|
</View>
|
|
69
|
-
</
|
|
70
|
-
</
|
|
46
|
+
</KeyboardProvider>
|
|
47
|
+
</View>
|
|
71
48
|
`;
|
|
@@ -38,6 +38,7 @@ exports[`MessageImage should render <MessageImage /> and compare with snapshot
|
|
|
38
38
|
>
|
|
39
39
|
<Image
|
|
40
40
|
onLayout={[Function]}
|
|
41
|
+
resizeMode="cover"
|
|
41
42
|
source={
|
|
42
43
|
{
|
|
43
44
|
"uri": "url://to/image.png",
|
|
@@ -49,7 +50,6 @@ exports[`MessageImage should render <MessageImage /> and compare with snapshot
|
|
|
49
50
|
"borderRadius": 13,
|
|
50
51
|
"height": 100,
|
|
51
52
|
"margin": 3,
|
|
52
|
-
"resizeMode": "cover",
|
|
53
53
|
"width": 150,
|
|
54
54
|
},
|
|
55
55
|
undefined,
|