react-native-gifted-chat 2.8.0 → 2.8.2-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/lib/Bubble/index.d.ts +3 -27
- package/lib/Bubble/index.js +138 -125
- package/lib/Bubble/index.js.map +1 -1
- package/lib/Bubble/types.d.ts +3 -3
- package/lib/GiftedChat/index.js +19 -4
- package/lib/GiftedChat/index.js.map +1 -1
- package/lib/GiftedChat/types.d.ts +5 -10
- package/lib/Message/index.js +7 -12
- package/lib/Message/index.js.map +1 -1
- package/lib/Message/types.d.ts +2 -2
- package/lib/MessageContainer/components/Item/index.js +3 -1
- package/lib/MessageContainer/components/Item/index.js.map +1 -1
- package/lib/MessageContainer/index.js +69 -46
- package/lib/MessageContainer/index.js.map +1 -1
- package/lib/MessageContainer/styles.d.ts +3 -2
- package/lib/MessageContainer/styles.js +3 -2
- package/lib/MessageContainer/styles.js.map +1 -1
- package/lib/MessageContainer/types.d.ts +6 -9
- package/lib/MessageText.d.ts +11 -7
- package/lib/MessageText.js +57 -96
- package/lib/MessageText.js.map +1 -1
- package/lib/SystemMessage.d.ts +2 -1
- package/lib/SystemMessage.js +3 -2
- package/lib/SystemMessage.js.map +1 -1
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +66 -0
- package/lib/utils.js.map +1 -1
- package/package.json +37 -30
- package/src/Bubble/index.tsx +171 -172
- package/src/Bubble/types.ts +3 -3
- package/src/GiftedChat/index.tsx +23 -3
- package/src/GiftedChat/types.ts +6 -4
- package/src/Message/index.tsx +10 -16
- package/src/Message/types.ts +2 -2
- package/src/MessageContainer/components/Item/index.tsx +1 -0
- package/src/MessageContainer/index.tsx +93 -58
- package/src/MessageContainer/styles.ts +3 -2
- package/src/MessageContainer/types.ts +6 -9
- package/src/MessageText.tsx +86 -121
- package/src/SystemMessage.tsx +4 -1
- package/src/__tests__/DayAnimated.test.tsx +54 -0
- package/src/__tests__/GiftedChat.test.tsx +25 -0
- package/src/__tests__/__snapshots__/DayAnimated.test.tsx.snap +5 -0
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +25 -0
- package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +11 -9
- package/src/utils.ts +77 -1
package/src/Bubble/index.tsx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { JSX, useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Text,
|
|
4
4
|
TouchableWithoutFeedback,
|
|
5
5
|
View,
|
|
6
6
|
} from 'react-native'
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { useChatContext } from '../GiftedChatContext'
|
|
9
9
|
import { QuickReplies } from '../QuickReplies'
|
|
10
10
|
import { MessageText } from '../MessageText'
|
|
11
11
|
import { MessageImage } from '../MessageImage'
|
|
@@ -22,49 +22,41 @@ import styles from './styles'
|
|
|
22
22
|
|
|
23
23
|
export * from './types'
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log('onLongPress', { buttonIndex })
|
|
61
|
-
}
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
styledBubbleToNext () {
|
|
66
|
-
const { currentMessage, nextMessage, position, containerToNextStyle } =
|
|
67
|
-
this.props
|
|
25
|
+
const Bubble = <TMessage extends IMessage = IMessage>(props: BubbleProps<TMessage>): JSX.Element => {
|
|
26
|
+
const {
|
|
27
|
+
currentMessage,
|
|
28
|
+
nextMessage,
|
|
29
|
+
position,
|
|
30
|
+
containerToNextStyle,
|
|
31
|
+
previousMessage,
|
|
32
|
+
containerToPreviousStyle,
|
|
33
|
+
onQuickReply,
|
|
34
|
+
renderQuickReplySend,
|
|
35
|
+
quickReplyStyle,
|
|
36
|
+
quickReplyTextStyle,
|
|
37
|
+
quickReplyContainerStyle,
|
|
38
|
+
containerStyle,
|
|
39
|
+
wrapperStyle,
|
|
40
|
+
bottomContainerStyle,
|
|
41
|
+
onPress: onPressProp,
|
|
42
|
+
onLongPress: onLongPressProp,
|
|
43
|
+
} = props
|
|
44
|
+
|
|
45
|
+
const context = useChatContext()
|
|
46
|
+
|
|
47
|
+
const onPress = useCallback(() => {
|
|
48
|
+
onPressProp?.(context, currentMessage)
|
|
49
|
+
}, [onPressProp, context, currentMessage])
|
|
50
|
+
|
|
51
|
+
const onLongPress = useCallback(() => {
|
|
52
|
+
onLongPressProp?.(context, currentMessage)
|
|
53
|
+
}, [
|
|
54
|
+
currentMessage,
|
|
55
|
+
context,
|
|
56
|
+
onLongPressProp,
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
const styledBubbleToNext = useCallback(() => {
|
|
68
60
|
if (
|
|
69
61
|
currentMessage &&
|
|
70
62
|
nextMessage &&
|
|
@@ -78,15 +70,14 @@ export default class Bubble<
|
|
|
78
70
|
]
|
|
79
71
|
|
|
80
72
|
return null
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
} = this.props
|
|
73
|
+
}, [
|
|
74
|
+
currentMessage,
|
|
75
|
+
nextMessage,
|
|
76
|
+
position,
|
|
77
|
+
containerToNextStyle,
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
const styledBubbleToPrevious = useCallback(() => {
|
|
90
81
|
if (
|
|
91
82
|
currentMessage &&
|
|
92
83
|
previousMessage &&
|
|
@@ -96,23 +87,18 @@ export default class Bubble<
|
|
|
96
87
|
)
|
|
97
88
|
return [
|
|
98
89
|
styles[position].containerToPrevious,
|
|
99
|
-
containerToPreviousStyle
|
|
90
|
+
containerToPreviousStyle?.[position],
|
|
100
91
|
]
|
|
101
92
|
|
|
102
93
|
return null
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
quickReplyStyle,
|
|
112
|
-
quickReplyTextStyle,
|
|
113
|
-
quickReplyContainerStyle,
|
|
114
|
-
} = this.props
|
|
115
|
-
|
|
94
|
+
}, [
|
|
95
|
+
currentMessage,
|
|
96
|
+
previousMessage,
|
|
97
|
+
position,
|
|
98
|
+
containerToPreviousStyle,
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
const renderQuickReplies = useCallback(() => {
|
|
116
102
|
if (currentMessage?.quickReplies) {
|
|
117
103
|
const {
|
|
118
104
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
@@ -120,10 +106,10 @@ export default class Bubble<
|
|
|
120
106
|
wrapperStyle,
|
|
121
107
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
122
108
|
...quickReplyProps
|
|
123
|
-
} =
|
|
109
|
+
} = props
|
|
124
110
|
|
|
125
|
-
if (
|
|
126
|
-
return
|
|
111
|
+
if (props.renderQuickReplies)
|
|
112
|
+
return props.renderQuickReplies(quickReplyProps)
|
|
127
113
|
|
|
128
114
|
return (
|
|
129
115
|
<QuickReplies
|
|
@@ -139,46 +125,55 @@ export default class Bubble<
|
|
|
139
125
|
}
|
|
140
126
|
|
|
141
127
|
return null
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
128
|
+
}, [
|
|
129
|
+
currentMessage,
|
|
130
|
+
onQuickReply,
|
|
131
|
+
renderQuickReplySend,
|
|
132
|
+
quickReplyStyle,
|
|
133
|
+
quickReplyTextStyle,
|
|
134
|
+
quickReplyContainerStyle,
|
|
135
|
+
nextMessage,
|
|
136
|
+
props,
|
|
137
|
+
])
|
|
138
|
+
|
|
139
|
+
const renderMessageText = useCallback(() => {
|
|
140
|
+
if (currentMessage?.text) {
|
|
146
141
|
const {
|
|
147
142
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
148
143
|
containerStyle,
|
|
149
144
|
wrapperStyle,
|
|
150
|
-
optionTitles,
|
|
151
145
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
152
146
|
...messageTextProps
|
|
153
|
-
} =
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
} = props
|
|
148
|
+
|
|
149
|
+
if (props.renderMessageText)
|
|
150
|
+
return props.renderMessageText(messageTextProps)
|
|
156
151
|
|
|
157
152
|
return <MessageText {...messageTextProps} />
|
|
158
153
|
}
|
|
159
154
|
return null
|
|
160
|
-
}
|
|
155
|
+
}, [props, currentMessage])
|
|
161
156
|
|
|
162
|
-
renderMessageImage () {
|
|
163
|
-
if (
|
|
157
|
+
const renderMessageImage = useCallback(() => {
|
|
158
|
+
if (currentMessage?.image) {
|
|
164
159
|
const {
|
|
165
160
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
166
161
|
containerStyle,
|
|
167
162
|
wrapperStyle,
|
|
168
163
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
169
164
|
...messageImageProps
|
|
170
|
-
} =
|
|
165
|
+
} = props
|
|
171
166
|
|
|
172
|
-
if (
|
|
173
|
-
return
|
|
167
|
+
if (props.renderMessageImage)
|
|
168
|
+
return props.renderMessageImage(messageImageProps)
|
|
174
169
|
|
|
175
170
|
return <MessageImage {...messageImageProps} />
|
|
176
171
|
}
|
|
177
172
|
return null
|
|
178
|
-
}
|
|
173
|
+
}, [props, currentMessage])
|
|
179
174
|
|
|
180
|
-
renderMessageVideo () {
|
|
181
|
-
if (!
|
|
175
|
+
const renderMessageVideo = useCallback(() => {
|
|
176
|
+
if (!currentMessage?.video)
|
|
182
177
|
return null
|
|
183
178
|
|
|
184
179
|
const {
|
|
@@ -187,16 +182,16 @@ export default class Bubble<
|
|
|
187
182
|
wrapperStyle,
|
|
188
183
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
189
184
|
...messageVideoProps
|
|
190
|
-
} =
|
|
185
|
+
} = props
|
|
191
186
|
|
|
192
|
-
if (
|
|
193
|
-
return
|
|
187
|
+
if (props.renderMessageVideo)
|
|
188
|
+
return props.renderMessageVideo(messageVideoProps)
|
|
194
189
|
|
|
195
190
|
return <MessageVideo />
|
|
196
|
-
}
|
|
191
|
+
}, [props, currentMessage])
|
|
197
192
|
|
|
198
|
-
renderMessageAudio () {
|
|
199
|
-
if (!
|
|
193
|
+
const renderMessageAudio = useCallback(() => {
|
|
194
|
+
if (!currentMessage?.audio)
|
|
200
195
|
return null
|
|
201
196
|
|
|
202
197
|
const {
|
|
@@ -205,20 +200,19 @@ export default class Bubble<
|
|
|
205
200
|
wrapperStyle,
|
|
206
201
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
207
202
|
...messageAudioProps
|
|
208
|
-
} =
|
|
203
|
+
} = props
|
|
209
204
|
|
|
210
|
-
if (
|
|
211
|
-
return
|
|
205
|
+
if (props.renderMessageAudio)
|
|
206
|
+
return props.renderMessageAudio(messageAudioProps)
|
|
212
207
|
|
|
213
208
|
return <MessageAudio />
|
|
214
|
-
}
|
|
209
|
+
}, [props, currentMessage])
|
|
215
210
|
|
|
216
|
-
renderTicks () {
|
|
211
|
+
const renderTicks = useCallback(() => {
|
|
217
212
|
const {
|
|
218
|
-
currentMessage,
|
|
219
213
|
renderTicks,
|
|
220
214
|
user,
|
|
221
|
-
} =
|
|
215
|
+
} = props
|
|
222
216
|
|
|
223
217
|
if (renderTicks && currentMessage)
|
|
224
218
|
return renderTicks(currentMessage)
|
|
@@ -237,17 +231,17 @@ export default class Bubble<
|
|
|
237
231
|
return (
|
|
238
232
|
<View style={styles.content.tickView}>
|
|
239
233
|
{!!currentMessage.sent && (
|
|
240
|
-
<Text style={[styles.content.tick,
|
|
234
|
+
<Text style={[styles.content.tick, props.tickStyle]}>
|
|
241
235
|
{'✓'}
|
|
242
236
|
</Text>
|
|
243
237
|
)}
|
|
244
238
|
{!!currentMessage.received && (
|
|
245
|
-
<Text style={[styles.content.tick,
|
|
239
|
+
<Text style={[styles.content.tick, props.tickStyle]}>
|
|
246
240
|
{'✓'}
|
|
247
241
|
</Text>
|
|
248
242
|
)}
|
|
249
243
|
{!!currentMessage.pending && (
|
|
250
|
-
<Text style={[styles.content.tick,
|
|
244
|
+
<Text style={[styles.content.tick, props.tickStyle]}>
|
|
251
245
|
{'🕓'}
|
|
252
246
|
</Text>
|
|
253
247
|
)}
|
|
@@ -255,10 +249,13 @@ export default class Bubble<
|
|
|
255
249
|
)
|
|
256
250
|
|
|
257
251
|
return null
|
|
258
|
-
}
|
|
252
|
+
}, [
|
|
253
|
+
props,
|
|
254
|
+
currentMessage,
|
|
255
|
+
])
|
|
259
256
|
|
|
260
|
-
renderTime () {
|
|
261
|
-
if (
|
|
257
|
+
const renderTime = useCallback(() => {
|
|
258
|
+
if (currentMessage?.createdAt) {
|
|
262
259
|
const {
|
|
263
260
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
264
261
|
containerStyle,
|
|
@@ -266,24 +263,23 @@ export default class Bubble<
|
|
|
266
263
|
textStyle,
|
|
267
264
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
268
265
|
...timeProps
|
|
269
|
-
} =
|
|
266
|
+
} = props
|
|
270
267
|
|
|
271
|
-
if (
|
|
272
|
-
return
|
|
268
|
+
if (props.renderTime)
|
|
269
|
+
return props.renderTime(timeProps)
|
|
273
270
|
|
|
274
271
|
return <Time {...timeProps} />
|
|
275
272
|
}
|
|
276
273
|
return null
|
|
277
|
-
}
|
|
274
|
+
}, [props, currentMessage])
|
|
278
275
|
|
|
279
|
-
renderUsername () {
|
|
276
|
+
const renderUsername = useCallback(() => {
|
|
280
277
|
const {
|
|
281
|
-
currentMessage,
|
|
282
278
|
user,
|
|
283
279
|
renderUsername,
|
|
284
|
-
} =
|
|
280
|
+
} = props
|
|
285
281
|
|
|
286
|
-
if (
|
|
282
|
+
if (props.renderUsernameOnMessage && currentMessage) {
|
|
287
283
|
if (user && currentMessage.user._id === user._id)
|
|
288
284
|
return null
|
|
289
285
|
|
|
@@ -294,7 +290,7 @@ export default class Bubble<
|
|
|
294
290
|
<View style={styles.content.usernameView}>
|
|
295
291
|
<Text
|
|
296
292
|
style={
|
|
297
|
-
[styles.content.username,
|
|
293
|
+
[styles.content.username, props.usernameStyle]
|
|
298
294
|
}
|
|
299
295
|
>
|
|
300
296
|
{'~ '}
|
|
@@ -305,75 +301,78 @@ export default class Bubble<
|
|
|
305
301
|
}
|
|
306
302
|
|
|
307
303
|
return null
|
|
308
|
-
}
|
|
304
|
+
}, [
|
|
305
|
+
currentMessage,
|
|
306
|
+
props,
|
|
307
|
+
])
|
|
309
308
|
|
|
310
|
-
renderCustomView () {
|
|
311
|
-
if (
|
|
312
|
-
return
|
|
309
|
+
const renderCustomView = useCallback(() => {
|
|
310
|
+
if (props.renderCustomView)
|
|
311
|
+
return props.renderCustomView(props)
|
|
313
312
|
|
|
314
313
|
return null
|
|
315
|
-
}
|
|
314
|
+
}, [props])
|
|
316
315
|
|
|
317
|
-
renderBubbleContent () {
|
|
316
|
+
const renderBubbleContent = useCallback(() => {
|
|
318
317
|
return (
|
|
319
318
|
<View>
|
|
320
|
-
{!
|
|
321
|
-
{
|
|
322
|
-
{
|
|
323
|
-
{
|
|
324
|
-
{
|
|
325
|
-
{
|
|
319
|
+
{!props.isCustomViewBottom && renderCustomView()}
|
|
320
|
+
{renderMessageImage()}
|
|
321
|
+
{renderMessageVideo()}
|
|
322
|
+
{renderMessageAudio()}
|
|
323
|
+
{renderMessageText()}
|
|
324
|
+
{props.isCustomViewBottom && renderCustomView()}
|
|
326
325
|
</View>
|
|
327
326
|
)
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
327
|
+
}, [
|
|
328
|
+
renderCustomView,
|
|
329
|
+
renderMessageImage,
|
|
330
|
+
renderMessageVideo,
|
|
331
|
+
renderMessageAudio,
|
|
332
|
+
renderMessageText,
|
|
333
|
+
props.isCustomViewBottom,
|
|
334
|
+
])
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<View
|
|
338
|
+
style={[
|
|
339
|
+
stylesCommon.fill,
|
|
340
|
+
styles[position].container,
|
|
341
|
+
containerStyle && containerStyle[position],
|
|
342
|
+
]}
|
|
343
|
+
>
|
|
339
344
|
<View
|
|
340
345
|
style={[
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
styles[position].wrapper,
|
|
347
|
+
styledBubbleToNext(),
|
|
348
|
+
styledBubbleToPrevious(),
|
|
349
|
+
wrapperStyle && wrapperStyle[position],
|
|
344
350
|
]}
|
|
345
351
|
>
|
|
346
|
-
<
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
wrapperStyle && wrapperStyle[position],
|
|
352
|
-
]}
|
|
352
|
+
<TouchableWithoutFeedback
|
|
353
|
+
onPress={onPress}
|
|
354
|
+
onLongPress={onLongPress}
|
|
355
|
+
accessibilityRole='text'
|
|
356
|
+
{...props.touchableProps}
|
|
353
357
|
>
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
bottomContainerStyle && bottomContainerStyle[position],
|
|
366
|
-
]}
|
|
367
|
-
>
|
|
368
|
-
{this.renderUsername()}
|
|
369
|
-
{this.renderTime()}
|
|
370
|
-
{this.renderTicks()}
|
|
371
|
-
</View>
|
|
358
|
+
<View>
|
|
359
|
+
{renderBubbleContent()}
|
|
360
|
+
<View
|
|
361
|
+
style={[
|
|
362
|
+
styles[position].bottom,
|
|
363
|
+
bottomContainerStyle?.[position],
|
|
364
|
+
]}
|
|
365
|
+
>
|
|
366
|
+
{renderUsername()}
|
|
367
|
+
{renderTime()}
|
|
368
|
+
{renderTicks()}
|
|
372
369
|
</View>
|
|
373
|
-
</
|
|
374
|
-
</
|
|
375
|
-
{this.renderQuickReplies()}
|
|
370
|
+
</View>
|
|
371
|
+
</TouchableWithoutFeedback>
|
|
376
372
|
</View>
|
|
377
|
-
|
|
378
|
-
|
|
373
|
+
{renderQuickReplies()}
|
|
374
|
+
</View>
|
|
375
|
+
)
|
|
379
376
|
}
|
|
377
|
+
|
|
378
|
+
export default Bubble
|
package/src/Bubble/types.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
TextStyle,
|
|
6
6
|
} from 'react-native'
|
|
7
7
|
import { QuickRepliesProps } from '../QuickReplies'
|
|
8
|
-
import { MessageTextProps } from '../MessageText'
|
|
8
|
+
import { MessageTextProps, MessageOption } from '../MessageText'
|
|
9
9
|
import { MessageImageProps } from '../MessageImage'
|
|
10
10
|
import { TimeProps } from '../Time'
|
|
11
11
|
import {
|
|
@@ -39,7 +39,7 @@ export type RenderMessageAudioProps<TMessage extends IMessage> = Omit<
|
|
|
39
39
|
|
|
40
40
|
export type RenderMessageTextProps<TMessage extends IMessage> = Omit<
|
|
41
41
|
BubbleProps<TMessage>,
|
|
42
|
-
'containerStyle' | 'wrapperStyle'
|
|
42
|
+
'containerStyle' | 'wrapperStyle' | 'options'
|
|
43
43
|
> &
|
|
44
44
|
MessageTextProps<TMessage>
|
|
45
45
|
/* eslint-enable no-use-before-define */
|
|
@@ -54,7 +54,7 @@ export interface BubbleProps<TMessage extends IMessage> {
|
|
|
54
54
|
currentMessage: TMessage
|
|
55
55
|
nextMessage?: TMessage
|
|
56
56
|
previousMessage?: TMessage
|
|
57
|
-
|
|
57
|
+
options?: MessageOption[]
|
|
58
58
|
containerStyle?: LeftRightStyle<ViewStyle>
|
|
59
59
|
wrapperStyle?: LeftRightStyle<ViewStyle>
|
|
60
60
|
textStyle?: LeftRightStyle<TextStyle>
|
package/src/GiftedChat/index.tsx
CHANGED
|
@@ -89,6 +89,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
89
89
|
minComposerHeight = MIN_COMPOSER_HEIGHT,
|
|
90
90
|
maxComposerHeight = MAX_COMPOSER_HEIGHT,
|
|
91
91
|
isKeyboardInternallyHandled = true,
|
|
92
|
+
disableKeyboardController = false,
|
|
92
93
|
} = props
|
|
93
94
|
|
|
94
95
|
const actionSheetRef = useRef<ActionSheetProviderRef>(null)
|
|
@@ -112,7 +113,16 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
112
113
|
const [text, setText] = useState<string | undefined>(() => props.text || '')
|
|
113
114
|
const [isTypingDisabled, setIsTypingDisabled] = useState<boolean>(false)
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
// Always call the hook, but conditionally use its data
|
|
117
|
+
const keyboardControllerData = useReanimatedKeyboardAnimation()
|
|
118
|
+
|
|
119
|
+
// Create a mock keyboard object when disabled
|
|
120
|
+
const keyboard = useMemo(() => {
|
|
121
|
+
if (disableKeyboardController)
|
|
122
|
+
return { height: { value: 0 } }
|
|
123
|
+
return keyboardControllerData
|
|
124
|
+
}, [disableKeyboardController, keyboardControllerData])
|
|
125
|
+
|
|
116
126
|
const trackingKeyboardMovement = useSharedValue(false)
|
|
117
127
|
const debounceEnableTypingTimeoutId = useRef<ReturnType<typeof setTimeout>>(undefined)
|
|
118
128
|
const keyboardOffsetBottom = useSharedValue(0)
|
|
@@ -380,9 +390,14 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
380
390
|
setText(props.text)
|
|
381
391
|
}, [props.text])
|
|
382
392
|
|
|
393
|
+
// Only set up keyboard animation when keyboard controller is enabled
|
|
383
394
|
useAnimatedReaction(
|
|
384
|
-
() => -keyboard.height.value,
|
|
395
|
+
() => disableKeyboardController ? 0 : -keyboard.height.value,
|
|
385
396
|
(value, prevValue) => {
|
|
397
|
+
// Skip keyboard handling when disabled
|
|
398
|
+
if (disableKeyboardController)
|
|
399
|
+
return
|
|
400
|
+
|
|
386
401
|
if (prevValue !== null && value !== prevValue) {
|
|
387
402
|
const isKeyboardMovingUp = value > prevValue
|
|
388
403
|
if (isKeyboardMovingUp !== trackingKeyboardMovement.value) {
|
|
@@ -420,6 +435,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
420
435
|
disableTyping,
|
|
421
436
|
debounceEnableTyping,
|
|
422
437
|
bottomOffset,
|
|
438
|
+
disableKeyboardController,
|
|
423
439
|
]
|
|
424
440
|
)
|
|
425
441
|
|
|
@@ -433,7 +449,7 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
433
449
|
>
|
|
434
450
|
{isInitialized
|
|
435
451
|
? (
|
|
436
|
-
<Animated.View style={[stylesCommon.fill, isKeyboardInternallyHandled && contentStyleAnim]}>
|
|
452
|
+
<Animated.View style={[stylesCommon.fill, (isKeyboardInternallyHandled && !disableKeyboardController) && contentStyleAnim]}>
|
|
437
453
|
{renderMessages}
|
|
438
454
|
{inputToolbarFragment}
|
|
439
455
|
</Animated.View>
|
|
@@ -448,6 +464,10 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
|
|
|
448
464
|
}
|
|
449
465
|
|
|
450
466
|
function GiftedChatWrapper<TMessage extends IMessage = IMessage> (props: GiftedChatProps<TMessage>) {
|
|
467
|
+
// Don't use KeyboardProvider when keyboard controller is disabled
|
|
468
|
+
if (props.disableKeyboardController)
|
|
469
|
+
return <GiftedChat<TMessage> {...props} />
|
|
470
|
+
|
|
451
471
|
return (
|
|
452
472
|
<KeyboardProvider>
|
|
453
473
|
<GiftedChat<TMessage> {...props} />
|
package/src/GiftedChat/types.ts
CHANGED
|
@@ -31,7 +31,7 @@ import { SendProps } from '../Send'
|
|
|
31
31
|
import { SystemMessageProps } from '../SystemMessage'
|
|
32
32
|
import { TimeProps } from '../Time'
|
|
33
33
|
import { AnimatedList, ListViewProps, MessageContainerProps } from '../MessageContainer'
|
|
34
|
-
import
|
|
34
|
+
import { BubbleProps } from '../Bubble'
|
|
35
35
|
|
|
36
36
|
export interface GiftedChatProps<TMessage extends IMessage> extends Partial<MessageContainerProps<TMessage>> {
|
|
37
37
|
/* Message container ref */
|
|
@@ -75,6 +75,8 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
75
75
|
isLoadingEarlier?: boolean
|
|
76
76
|
/* 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` */
|
|
77
77
|
isKeyboardInternallyHandled?: boolean
|
|
78
|
+
/* Completely disable react-native-keyboard-controller. Useful when using react-native-navigation or other conflicting keyboard libraries; default is `false` */
|
|
79
|
+
disableKeyboardController?: boolean
|
|
78
80
|
/* Whether to render an avatar for the current user; default is false, only show avatars for other users */
|
|
79
81
|
showUserAvatar?: boolean
|
|
80
82
|
/* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */
|
|
@@ -144,7 +146,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
144
146
|
/* Custom message avatar; set to null to not render any avatar for the message */
|
|
145
147
|
renderAvatar?: null | ((props: AvatarProps<TMessage>) => React.ReactNode)
|
|
146
148
|
/* Custom message bubble */
|
|
147
|
-
renderBubble?(props:
|
|
149
|
+
renderBubble?(props: BubbleProps<TMessage>): React.ReactNode
|
|
148
150
|
/* Custom system message */
|
|
149
151
|
renderSystemMessage?(props: SystemMessageProps<TMessage>): React.ReactNode
|
|
150
152
|
/* Callback when a message bubble is pressed; default is to do nothing */
|
|
@@ -165,7 +167,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
165
167
|
/* Custom message video */
|
|
166
168
|
renderMessageAudio?(props: MessageAudioProps<TMessage>): React.ReactNode
|
|
167
169
|
/* Custom view inside the bubble */
|
|
168
|
-
renderCustomView?(props:
|
|
170
|
+
renderCustomView?(props: BubbleProps<TMessage>): React.ReactNode
|
|
169
171
|
/* Custom day above a message */
|
|
170
172
|
renderDay?(props: DayProps): React.ReactNode
|
|
171
173
|
/* Custom time inside a message */
|
|
@@ -191,7 +193,7 @@ export interface GiftedChatProps<TMessage extends IMessage> extends Partial<Mess
|
|
|
191
193
|
/* Callback when the input text changes */
|
|
192
194
|
onInputTextChanged?(text: string): void
|
|
193
195
|
/* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */
|
|
194
|
-
|
|
196
|
+
matchers?: MessageTextProps<TMessage>['matchers']
|
|
195
197
|
onQuickReply?(replies: Reply[]): void
|
|
196
198
|
renderQuickReplies?(
|
|
197
199
|
quickReplies: QuickRepliesProps<TMessage>,
|
package/src/Message/index.tsx
CHANGED
|
@@ -114,22 +114,16 @@ let Message: React.FC<MessageProps<IMessage>> = (props: MessageProps<IMessage>)
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
Message = memo(Message, (props, nextProps) => {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
shouldUpdate ||
|
|
128
|
-
!isEqual(current, next) ||
|
|
129
|
-
!isEqual(previousMessage, nextPropsPreviousMessage) ||
|
|
130
|
-
!isEqual(nextMessage, nextPropsMessage)
|
|
131
|
-
|
|
132
|
-
return shouldUpdate
|
|
117
|
+
const shouldUpdate =
|
|
118
|
+
props.shouldUpdateMessage?.(props, nextProps) ||
|
|
119
|
+
!isEqual(props.currentMessage!, nextProps.currentMessage!) ||
|
|
120
|
+
!isEqual(props.previousMessage, nextProps.previousMessage) ||
|
|
121
|
+
!isEqual(props.nextMessage, nextProps.nextMessage)
|
|
122
|
+
|
|
123
|
+
if (shouldUpdate)
|
|
124
|
+
return false
|
|
125
|
+
|
|
126
|
+
return true
|
|
133
127
|
})
|
|
134
128
|
|
|
135
129
|
export default Message
|