stream-chat-react-native-core 4.1.4 → 4.2.0-beta.3

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 (97) hide show
  1. package/lib/commonjs/components/Attachment/Attachment.js +16 -10
  2. package/lib/commonjs/components/Attachment/Attachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/FileIcon.js +20 -20
  4. package/lib/commonjs/components/Attachment/FileIcon.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Giphy.js +61 -40
  6. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  7. package/lib/commonjs/components/Channel/Channel.js +16 -13
  8. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  9. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +2 -0
  10. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  11. package/lib/commonjs/components/ChannelList/ChannelListMessenger.js +3 -3
  12. package/lib/commonjs/components/ChannelList/ChannelListMessenger.js.map +1 -1
  13. package/lib/commonjs/components/Message/MessageSimple/MessageContent.js +42 -20
  14. package/lib/commonjs/components/Message/MessageSimple/MessageContent.js.map +1 -1
  15. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +4 -7
  16. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  17. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.test.js +183 -173
  18. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.test.js.map +1 -1
  19. package/lib/commonjs/components/MessageInput/MessageInput.js +3 -3
  20. package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
  21. package/lib/commonjs/components/MessageList/utils/getLastReceivedMessage.js +3 -3
  22. package/lib/commonjs/components/MessageList/utils/getLastReceivedMessage.js.map +1 -1
  23. package/lib/commonjs/components/MessageList/utils/getReadStates.js +8 -8
  24. package/lib/commonjs/components/MessageList/utils/getReadStates.js.map +1 -1
  25. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +32 -32
  26. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  27. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +9 -9
  28. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  29. package/lib/commonjs/contexts/messagesContext/MessagesContext.js +2 -2
  30. package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
  31. package/lib/commonjs/contexts/themeContext/utils/theme.js +1 -0
  32. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  33. package/lib/commonjs/version.json +1 -1
  34. package/lib/module/components/Attachment/Attachment.js +16 -10
  35. package/lib/module/components/Attachment/Attachment.js.map +1 -1
  36. package/lib/module/components/Attachment/FileIcon.js +20 -20
  37. package/lib/module/components/Attachment/FileIcon.js.map +1 -1
  38. package/lib/module/components/Attachment/Giphy.js +61 -40
  39. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  40. package/lib/module/components/Channel/Channel.js +16 -13
  41. package/lib/module/components/Channel/Channel.js.map +1 -1
  42. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +2 -0
  43. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  44. package/lib/module/components/ChannelList/ChannelListMessenger.js +3 -3
  45. package/lib/module/components/ChannelList/ChannelListMessenger.js.map +1 -1
  46. package/lib/module/components/Message/MessageSimple/MessageContent.js +42 -20
  47. package/lib/module/components/Message/MessageSimple/MessageContent.js.map +1 -1
  48. package/lib/module/components/Message/MessageSimple/utils/renderText.js +4 -7
  49. package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  50. package/lib/module/components/Message/MessageSimple/utils/renderText.test.js +183 -173
  51. package/lib/module/components/Message/MessageSimple/utils/renderText.test.js.map +1 -1
  52. package/lib/module/components/MessageInput/MessageInput.js +3 -3
  53. package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
  54. package/lib/module/components/MessageList/utils/getLastReceivedMessage.js +3 -3
  55. package/lib/module/components/MessageList/utils/getLastReceivedMessage.js.map +1 -1
  56. package/lib/module/components/MessageList/utils/getReadStates.js +8 -8
  57. package/lib/module/components/MessageList/utils/getReadStates.js.map +1 -1
  58. package/lib/module/contexts/messageInputContext/MessageInputContext.js +32 -32
  59. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  60. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +9 -9
  61. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  62. package/lib/module/contexts/messagesContext/MessagesContext.js +2 -2
  63. package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
  64. package/lib/module/contexts/themeContext/utils/theme.js +1 -0
  65. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  66. package/lib/module/version.json +1 -1
  67. package/lib/typescript/components/Attachment/Attachment.d.ts +2 -2
  68. package/lib/typescript/components/Attachment/Giphy.d.ts +2 -2
  69. package/lib/typescript/components/Channel/Channel.d.ts +1 -1
  70. package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
  71. package/lib/typescript/components/MessageOverlay/hooks/useMessageActionAnimation.d.ts +2 -3
  72. package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +5 -1
  73. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +1 -0
  74. package/package.json +14 -12
  75. package/src/components/Attachment/Attachment.tsx +29 -4
  76. package/src/components/Attachment/Giphy.tsx +55 -22
  77. package/src/components/Attachment/__tests__/Attachment.test.js +41 -0
  78. package/src/components/Channel/Channel.tsx +3 -0
  79. package/src/components/Channel/hooks/useCreateMessagesContext.ts +2 -0
  80. package/src/components/ChannelList/ChannelListMessenger.tsx +0 -1
  81. package/src/components/ImageGallery/components/__tests__/ImageGalleryHeader.test.tsx +14 -4
  82. package/src/components/Message/MessageSimple/MessageContent.tsx +20 -13
  83. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageReplies.test.js.snap +1 -0
  84. package/src/components/Message/MessageSimple/utils/renderText.test.tsx +30 -23
  85. package/src/components/MessageInput/__tests__/AttachButton.test.js +8 -8
  86. package/src/components/MessageInput/__tests__/SendButton.test.js +12 -20
  87. package/src/components/MessageInput/__tests__/__snapshots__/AttachButton.test.js.snap +8 -0
  88. package/src/components/MessageInput/__tests__/__snapshots__/FileUploadPreview.test.js.snap +24 -68
  89. package/src/components/MessageInput/__tests__/__snapshots__/ImageUploadPreview.test.js.snap +20 -36
  90. package/src/components/MessageInput/__tests__/__snapshots__/MessageInput.test.js.snap +16 -10
  91. package/src/components/MessageInput/__tests__/__snapshots__/SendButton.test.js.snap +16 -0
  92. package/src/components/MessageInput/__tests__/__snapshots__/UploadProgressIndicator.test.js.snap +1 -3
  93. package/src/components/MessageList/__tests__/__snapshots__/ScrollToBottomButton.test.js.snap +1 -0
  94. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +10 -7
  95. package/src/contexts/messagesContext/MessagesContext.tsx +5 -2
  96. package/src/contexts/themeContext/utils/theme.ts +1 -0
  97. package/src/version.json +1 -1
@@ -18,7 +18,15 @@ import type { DefaultStreamChatGenerics } from '../../types/types';
18
18
  import { makeImageCompatibleUrl } from '../../utils/utils';
19
19
 
20
20
  const styles = StyleSheet.create({
21
- buttonContainer: { alignItems: 'center', borderTopWidth: 1, flex: 1, justifyContent: 'center' },
21
+ actionsRow: {
22
+ flexDirection: 'row',
23
+ },
24
+ buttonContainer: {
25
+ alignItems: 'center',
26
+ borderTopWidth: 1,
27
+ flex: 1,
28
+ justifyContent: 'center',
29
+ },
22
30
  cancel: {
23
31
  fontSize: 14,
24
32
  fontWeight: '600',
@@ -29,8 +37,10 @@ const styles = StyleSheet.create({
29
37
  width: 270,
30
38
  },
31
39
  giphy: {
40
+ alignSelf: 'center',
32
41
  borderRadius: 2,
33
42
  height: 170,
43
+ maxWidth: 270,
34
44
  width: 270,
35
45
  },
36
46
  giphyContainer: {
@@ -53,7 +63,10 @@ const styles = StyleSheet.create({
53
63
  left: 8,
54
64
  position: 'absolute',
55
65
  },
56
- giphyMaskText: { fontSize: 13, fontWeight: '600' },
66
+ giphyMaskText: {
67
+ fontSize: 13,
68
+ fontWeight: '600',
69
+ },
57
70
  header: {
58
71
  alignItems: 'center',
59
72
  display: 'flex',
@@ -62,16 +75,16 @@ const styles = StyleSheet.create({
62
75
  padding: 8,
63
76
  width: '60%',
64
77
  },
65
- margin: {
66
- margin: 1,
67
- },
68
- row: { flexDirection: 'row' },
69
78
  selectionContainer: {
70
79
  borderBottomLeftRadius: 8,
71
80
  borderWidth: 1,
72
81
  overflow: 'hidden',
73
82
  width: 272,
74
83
  },
84
+ selectionImageContainer: {
85
+ alignSelf: 'center',
86
+ margin: 1,
87
+ },
75
88
  send: {
76
89
  fontSize: 14,
77
90
  fontWeight: '600',
@@ -98,7 +111,7 @@ export type GiphyPropsWithContext<
98
111
  MessageContextValue<StreamChatGenerics>,
99
112
  'handleAction' | 'onLongPress' | 'onPress' | 'onPressIn' | 'preventPress'
100
113
  > &
101
- Pick<MessagesContextValue<StreamChatGenerics>, 'additionalTouchableProps'> & {
114
+ Pick<MessagesContextValue<StreamChatGenerics>, 'giphyVersion' | 'additionalTouchableProps'> & {
102
115
  attachment: Attachment<StreamChatGenerics>;
103
116
  };
104
117
 
@@ -117,11 +130,11 @@ const GiphyWithContext = <
117
130
  preventPress,
118
131
  } = props;
119
132
 
120
- const { actions, image_url, thumb_url, title, type } = attachment;
133
+ const { actions, giphy: giphyData, image_url, thumb_url, title, type } = attachment;
121
134
 
122
135
  const {
123
136
  theme: {
124
- colors: { accent_blue, black, grey, grey_dark, grey_gainsboro, white },
137
+ colors: { accent_blue, black, grey, grey_dark, grey_gainsboro, label_bg_transparent, white },
125
138
  messageSimple: {
126
139
  giphy: {
127
140
  buttonContainer,
@@ -142,7 +155,15 @@ const GiphyWithContext = <
142
155
  },
143
156
  } = useTheme();
144
157
 
145
- const uri = image_url || thumb_url;
158
+ let uri = image_url || thumb_url;
159
+ const giphyDimensions: { height?: number; width?: number } = {};
160
+
161
+ if (type === 'giphy' && giphyData) {
162
+ const giphyVersionInfo = giphyData[props.giphyVersion];
163
+ uri = giphyVersionInfo.url;
164
+ giphyDimensions.height = parseFloat(giphyVersionInfo.height);
165
+ giphyDimensions.width = parseFloat(giphyVersionInfo.width);
166
+ }
146
167
 
147
168
  if (!uri) return null;
148
169
 
@@ -161,15 +182,15 @@ const GiphyWithContext = <
161
182
  style={[styles.giphyHeaderTitle, giphyHeaderTitle, { color: grey_dark }]}
162
183
  >{`/giphy ${title}`}</Text>
163
184
  </View>
164
- <View style={styles.margin}>
185
+ <View style={styles.selectionImageContainer}>
165
186
  <Image
166
- resizeMode='cover'
187
+ resizeMode='contain'
167
188
  source={{ uri: makeImageCompatibleUrl(uri) }}
168
- style={[styles.giphy, giphy]}
189
+ style={[styles.giphy, giphyDimensions, giphy]}
169
190
  />
170
191
  </View>
171
192
  <View>
172
- <View style={styles.row}>
193
+ <View style={styles.actionsRow}>
173
194
  <TouchableOpacity
174
195
  onPress={() => {
175
196
  if (actions?.[2].name && actions?.[2].value && handleAction) {
@@ -238,18 +259,24 @@ const GiphyWithContext = <
238
259
  });
239
260
  }
240
261
  }}
241
- style={[styles.container, container]}
242
262
  testID='giphy-attachment'
243
263
  {...additionalTouchableProps}
244
264
  >
245
- <View>
265
+ <View style={[styles.container, container]}>
246
266
  <Image
247
- resizeMode='cover'
267
+ resizeMode='contain'
248
268
  source={{ uri: makeImageCompatibleUrl(uri) }}
249
- style={[styles.giphy, giphy]}
269
+ style={[styles.giphy, giphyDimensions, giphy]}
270
+ testID='giphy-attachment-image'
250
271
  />
251
272
  <View style={[styles.giphyMask, giphyMask]}>
252
- <View style={[styles.giphyContainer, { backgroundColor: grey_dark }, giphyContainer]}>
273
+ <View
274
+ style={[
275
+ styles.giphyContainer,
276
+ { backgroundColor: label_bg_transparent },
277
+ giphyContainer,
278
+ ]}
279
+ >
253
280
  <Lightning height={16} pathFill={white} width={16} />
254
281
  <Text style={[styles.giphyMaskText, { color: white }, giphyMaskText]}>
255
282
  {type?.toUpperCase()}
@@ -267,9 +294,11 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
267
294
  ) => {
268
295
  const {
269
296
  attachment: { actions: prevActions, image_url: prevImageUrl, thumb_url: prevThumbUrl },
297
+ giphyVersion: prevGiphyVersion,
270
298
  } = prevProps;
271
299
  const {
272
300
  attachment: { actions: nextActions, image_url: nextImageUrl, thumb_url: nextThumbUrl },
301
+ giphyVersion: nextGiphyVersion,
273
302
  } = nextProps;
274
303
 
275
304
  const imageUrlEqual = prevImageUrl === nextImageUrl;
@@ -278,6 +307,9 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
278
307
  const thumbUrlEqual = prevThumbUrl === nextThumbUrl;
279
308
  if (!thumbUrlEqual) return false;
280
309
 
310
+ const giphyVersionEqual = prevGiphyVersion === nextGiphyVersion;
311
+ if (!giphyVersionEqual) return false;
312
+
281
313
  const actionsEqual =
282
314
  Array.isArray(prevActions) === Array.isArray(nextActions) &&
283
315
  ((Array.isArray(prevActions) &&
@@ -294,8 +326,8 @@ const MemoizedGiphy = React.memo(GiphyWithContext, areEqual) as typeof GiphyWith
294
326
  export type GiphyProps<
295
327
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
296
328
  > = Partial<
297
- Pick<MessageContextValue<StreamChatGenerics>, 'onLongPress' | 'onPressIn'> &
298
- Pick<MessagesContextValue<StreamChatGenerics>, 'additionalTouchableProps'>
329
+ Pick<MessageContextValue<StreamChatGenerics>, 'isMyMessage' | 'onLongPress' | 'onPressIn'> &
330
+ Pick<MessagesContextValue<StreamChatGenerics>, 'giphyVersion' | 'additionalTouchableProps'>
299
331
  > & {
300
332
  attachment: Attachment<StreamChatGenerics>;
301
333
  };
@@ -310,12 +342,13 @@ export const Giphy = <
310
342
  ) => {
311
343
  const { handleAction, onLongPress, onPress, onPressIn, preventPress } =
312
344
  useMessageContext<StreamChatGenerics>();
313
- const { additionalTouchableProps } = useMessagesContext<StreamChatGenerics>();
345
+ const { additionalTouchableProps, giphyVersion } = useMessagesContext<StreamChatGenerics>();
314
346
 
315
347
  return (
316
348
  <MemoizedGiphy
317
349
  {...{
318
350
  additionalTouchableProps,
351
+ giphyVersion,
319
352
  handleAction,
320
353
  onLongPress,
321
354
  onPress,
@@ -71,6 +71,47 @@ describe('Attachment', () => {
71
71
  });
72
72
  });
73
73
 
74
+ it('"giphy" attachment size should be customisable', async () => {
75
+ const attachment = generateGiphyAttachment();
76
+ attachment.giphy = {
77
+ fixed_height: {
78
+ height: '200',
79
+ url: 'https://media1.giphy.com/media/test/fixed_height.gif',
80
+ width: '375',
81
+ },
82
+ original: {
83
+ height: '256',
84
+ url: 'https://media1.giphy.com/media/test/original.gif',
85
+ width: '480',
86
+ },
87
+ };
88
+ const { getByTestId: getByTestIdFixedHeight } = render(
89
+ getAttachmentComponent({ attachment, giphyVersion: 'fixed_height' }),
90
+ );
91
+ const { getByTestId: getByTestIdOriginal } = render(
92
+ getAttachmentComponent({ attachment, giphyVersion: 'original' }),
93
+ );
94
+ await waitFor(() => {
95
+ const checkImageProps = (imageProps, specificSizedGiphyData) => {
96
+ let imageStyle = imageProps.style;
97
+ if (Array.isArray(imageStyle)) {
98
+ imageStyle = Object.assign({}, ...imageStyle);
99
+ }
100
+ expect(imageStyle.height).toBe(parseFloat(specificSizedGiphyData.height));
101
+ expect(imageStyle.width).toBe(parseFloat(specificSizedGiphyData.width));
102
+ expect(imageProps.source.uri).toBe(specificSizedGiphyData.url);
103
+ };
104
+ checkImageProps(
105
+ getByTestIdFixedHeight('giphy-attachment-image').props,
106
+ attachment.giphy.fixed_height,
107
+ );
108
+ checkImageProps(
109
+ getByTestIdOriginal('giphy-attachment-image').props,
110
+ attachment.giphy.original,
111
+ );
112
+ });
113
+ });
114
+
74
115
  it('should render UrlPreview component if attachment has title_link or og_scrape_url', async () => {
75
116
  const attachment = generateImageAttachment({
76
117
  og_scrape_url: uuidv4(),
@@ -238,6 +238,7 @@ export type ChannelPropsWithContext<
238
238
  | 'formatDate'
239
239
  | 'Gallery'
240
240
  | 'Giphy'
241
+ | 'giphyVersion'
241
242
  | 'handleBlock'
242
243
  | 'handleCopy'
243
244
  | 'handleDelete'
@@ -426,6 +427,7 @@ const ChannelWithContext = <
426
427
  Gallery = GalleryDefault,
427
428
  Giphy = GiphyDefault,
428
429
  giphyEnabled,
430
+ giphyVersion = 'fixed_height',
429
431
  globalUnreadCountLimit = 255,
430
432
  handleBlock,
431
433
  handleCopy,
@@ -1672,6 +1674,7 @@ const ChannelWithContext = <
1672
1674
  formatDate,
1673
1675
  Gallery,
1674
1676
  Giphy,
1677
+ giphyVersion,
1675
1678
  handleBlock,
1676
1679
  handleCopy,
1677
1680
  handleDelete,
@@ -27,6 +27,7 @@ export const useCreateMessagesContext = <
27
27
  formatDate,
28
28
  Gallery,
29
29
  Giphy,
30
+ giphyVersion,
30
31
  handleBlock,
31
32
  handleCopy,
32
33
  handleDelete,
@@ -111,6 +112,7 @@ export const useCreateMessagesContext = <
111
112
  formatDate,
112
113
  Gallery,
113
114
  Giphy,
115
+ giphyVersion,
114
116
  handleBlock,
115
117
  handleCopy,
116
118
  handleDelete,
@@ -164,7 +164,6 @@ const ChannelListMessengerWithContext = <
164
164
  ListHeaderComponent={ListFooterComponent}
165
165
  onEndReached={onEndReached}
166
166
  onEndReachedThreshold={loadMoreThreshold}
167
- // @ts-expect-error waiting for this merged PR to be released https://github.com/software-mansion/react-native-gesture-handler/pull/1394
168
167
  ref={setFlatListRef}
169
168
  refreshControl={<RefreshControl onRefresh={refreshList} refreshing={refreshing} />}
170
169
  renderItem={renderItem}
@@ -1,27 +1,37 @@
1
1
  import React from 'react';
2
-
3
2
  import type Animated from 'react-native-reanimated';
3
+ import { useSharedValue } from 'react-native-reanimated';
4
+
5
+ import { renderHook } from '@testing-library/react-hooks';
4
6
 
5
7
  import { render } from '@testing-library/react-native';
6
8
 
7
9
  import { ThemeProvider } from '../../../../contexts/themeContext/ThemeContext';
10
+
8
11
  import { ImageGalleryHeader } from '../ImageGalleryHeader';
9
12
 
10
13
  it('doesnt fail if fromNow is not available on first render', () => {
11
14
  try {
15
+ let sharedValueOpacity: Animated.SharedValue<number>;
16
+ let sharedValueVisible: Animated.SharedValue<number>;
17
+ renderHook(() => {
18
+ sharedValueOpacity = useSharedValue(1);
19
+ sharedValueVisible = useSharedValue(1);
20
+ });
12
21
  const { getAllByText } = render(
13
22
  <ThemeProvider>
14
23
  <ImageGalleryHeader
15
- opacity={1 as unknown as Animated.SharedValue<number>}
24
+ // @ts-ignore
25
+ opacity={sharedValueOpacity}
16
26
  photo={{
17
27
  id: 'id',
18
28
  uri: 'file:///bogus/uri/to/photo.jpg',
19
29
  }}
20
- visible={1 as unknown as Animated.SharedValue<number>}
30
+ // @ts-ignore
31
+ visible={sharedValueVisible}
21
32
  />
22
33
  </ThemeProvider>,
23
34
  );
24
-
25
35
  expect(getAllByText('Unknown User')).toBeTruthy();
26
36
  } catch (error: unknown) {
27
37
  if (error instanceof Error) {
@@ -185,7 +185,14 @@ const MessageContentWithContext = <
185
185
 
186
186
  const hasThreadReplies = !!message?.reply_count;
187
187
 
188
- const noBorder = (onlyEmojis && !message.quoted_message) || !!otherAttachments.length;
188
+ let noBorder = onlyEmojis && !message.quoted_message;
189
+ if (otherAttachments.length) {
190
+ if (otherAttachments[0].type === 'giphy' && !isMyMessage) {
191
+ noBorder = false;
192
+ } else {
193
+ noBorder = true;
194
+ }
195
+ }
189
196
 
190
197
  const isMessageTypeDeleted = message.type === 'deleted';
191
198
 
@@ -200,18 +207,18 @@ const MessageContentWithContext = <
200
207
  );
201
208
  }
202
209
 
203
- const backgroundColor =
204
- onlyEmojis && !message.quoted_message
205
- ? transparent
206
- : otherAttachments.length
207
- ? otherAttachments[0].type === 'giphy'
208
- ? !message.quoted_message
209
- ? transparent
210
- : grey_gainsboro
211
- : blue_alice
212
- : alignment === 'left' || error
213
- ? white
214
- : grey_gainsboro;
210
+ let backgroundColor = grey_gainsboro;
211
+ if (onlyEmojis && !message.quoted_message) {
212
+ backgroundColor = transparent;
213
+ } else if (otherAttachments.length) {
214
+ if (otherAttachments[0].type === 'giphy') {
215
+ backgroundColor = message.quoted_message || isMyMessage ? grey_gainsboro : white;
216
+ } else {
217
+ backgroundColor = blue_alice;
218
+ }
219
+ } else if (alignment === 'left' || error) {
220
+ backgroundColor = white;
221
+ }
215
222
 
216
223
  const repliesCurveColor = isMyMessage && !error ? backgroundColor : grey_whisper;
217
224
 
@@ -47,6 +47,7 @@ exports[`MessageReplies should render message replies 1`] = `
47
47
  </View>
48
48
  <View
49
49
  accessible={true}
50
+ collapsable={false}
50
51
  focusable={true}
51
52
  onClick={[Function]}
52
53
  onResponderGrant={[Function]}
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
2
  import { Text } from 'react-native';
3
3
 
4
- import { render, waitFor } from '@testing-library/react-native';
4
+ import type { ReactTestInstance } from 'react-test-renderer';
5
+
6
+ import { render, waitFor, within } from '@testing-library/react-native';
5
7
 
6
8
  // @ts-ignore
7
9
  import { ASTNode, SingleASTNode } from 'simple-markdown';
@@ -31,40 +33,45 @@ describe('list', () => {
31
33
  </>
32
34
  );
33
35
 
34
- it('renders numbered items', async () => {
36
+ it('renders numbered items', () => {
35
37
  const node = createNode({ amount: 3, ordered: true, start: 1 });
36
- const { getByText } = render(<MockText node={node} output={mockOutput} state={{}} />);
37
-
38
- await waitFor(() => expect(getByText('1. ')).toBeTruthy());
39
- await waitFor(() => expect(getByText('2. ')).toBeTruthy());
40
- await waitFor(() => expect(getByText('3. ')).toBeTruthy());
38
+ const { container } = render(<MockText node={node} output={mockOutput} state={{}} />);
39
+ const textInstances = container.children as ReactTestInstance[];
40
+ textInstances.forEach(async (instance, index) => {
41
+ const text = `${index + node.start}. `; // 1. , 2. ...
42
+ await waitFor(() => expect(within(instance).getByText(text)).toBeTruthy());
43
+ });
41
44
  });
42
45
 
43
- it('renders numbered items from a start index', async () => {
46
+ it('renders numbered items from a start index', () => {
44
47
  const node = createNode({ amount: 3, ordered: true, start: 3 });
45
- const { getByText } = render(<MockText node={node} output={mockOutput} state={{}} />);
46
-
47
- await waitFor(() => expect(getByText('3. ')).toBeTruthy());
48
- await waitFor(() => expect(getByText('4. ')).toBeTruthy());
49
- await waitFor(() => expect(getByText('5. ')).toBeTruthy());
48
+ const { container } = render(<MockText node={node} output={mockOutput} state={{}} />);
49
+ const textInstances = container.children as ReactTestInstance[];
50
+ textInstances.forEach(async (instance, index) => {
51
+ const text = `${index + node.start}. `; // 3. , 4. ...
52
+ await waitFor(() => expect(within(instance).getByText(text)).toBeTruthy());
53
+ });
50
54
  });
51
55
 
52
- it('does not throw an error if an item is empty', async () => {
56
+ it('does not throw an error if an item is empty', () => {
53
57
  const node = {
54
58
  ...createNode({ amount: 3, ordered: true }),
55
59
  items: ['Not empty', null, 'Not empty'],
56
60
  };
57
- const { getByText } = render(<MockText node={node} output={mockOutput} state={{}} />);
58
-
59
- await waitFor(() => expect(getByText('1. ')).toBeTruthy());
60
- await waitFor(() => expect(getByText('2. ')).toBeTruthy());
61
- await waitFor(() => expect(getByText('3. ')).toBeTruthy());
61
+ const { container } = render(<MockText node={node} output={mockOutput} state={{}} />);
62
+ const textInstances = container.children as ReactTestInstance[];
63
+ textInstances.forEach(async (instance, index) => {
64
+ const text = `${index + 1}. `; // 1. , 2. ...
65
+ await waitFor(() => expect(within(instance).getByText(text)).toBeTruthy());
66
+ });
62
67
  });
63
68
 
64
- it('renders an unordered list', async () => {
69
+ it('renders an unordered list', () => {
65
70
  const node = createNode({ amount: 3 });
66
- const { getAllByText } = render(<MockText node={node} output={mockOutput} state={{}} />);
67
-
68
- await waitFor(() => expect(getAllByText('\u2022 ')).toHaveLength(3));
71
+ const { container } = render(<MockText node={node} output={mockOutput} state={{}} />);
72
+ const textInstances = container.children as ReactTestInstance[];
73
+ textInstances.forEach(async (instance) => {
74
+ await waitFor(() => expect(within(instance).getByText('\u2022 ')).toBeTruthy());
75
+ });
69
76
  });
70
77
  });
@@ -6,14 +6,16 @@ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
6
6
  import { AttachButton } from '../AttachButton';
7
7
 
8
8
  describe('AttachButton', () => {
9
+ const getComponent = (props = {}) => (
10
+ <ThemeProvider>
11
+ <AttachButton {...props} />
12
+ </ThemeProvider>
13
+ );
14
+
9
15
  it('should render an enabled AttachButton', async () => {
10
16
  const handleOnPress = jest.fn();
11
17
 
12
- const { getByTestId, queryByTestId, toJSON } = render(
13
- <ThemeProvider>
14
- <AttachButton handleOnPress={handleOnPress} />
15
- </ThemeProvider>,
16
- );
18
+ const { getByTestId, queryByTestId, toJSON } = render(getComponent({ handleOnPress }));
17
19
 
18
20
  await waitFor(() => {
19
21
  expect(queryByTestId('attach-button')).toBeTruthy();
@@ -35,9 +37,7 @@ describe('AttachButton', () => {
35
37
  const handleOnPress = jest.fn();
36
38
 
37
39
  const { getByTestId, queryByTestId, toJSON } = render(
38
- <ThemeProvider>
39
- <AttachButton disabled handleOnPress={handleOnPress} />
40
- </ThemeProvider>,
40
+ getComponent({ disabled: true, handleOnPress }),
41
41
  );
42
42
 
43
43
  await waitFor(() => {
@@ -7,15 +7,19 @@ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
7
7
  import { SendButton } from '../SendButton';
8
8
 
9
9
  describe('SendButton', () => {
10
+ const getComponent = ({ editing, ...rest } = {}) => (
11
+ <ThemeProvider>
12
+ <MessagesProvider value={{ editing }}>
13
+ <SendButton {...rest} />
14
+ </MessagesProvider>
15
+ </ThemeProvider>
16
+ );
17
+
10
18
  it('should render a non-editing enabled SendButton', async () => {
11
19
  const sendMessage = jest.fn();
12
20
 
13
21
  const { getByTestId, queryByTestId, toJSON } = render(
14
- <ThemeProvider>
15
- <MessagesProvider value={{ editing: false }}>
16
- <SendButton sendMessage={sendMessage} />
17
- </MessagesProvider>
18
- </ThemeProvider>,
22
+ getComponent({ editing: false, sendMessage }),
19
23
  );
20
24
 
21
25
  await waitFor(() => {
@@ -38,11 +42,7 @@ describe('SendButton', () => {
38
42
  const sendMessage = jest.fn();
39
43
 
40
44
  const { getByTestId, queryByTestId, toJSON } = render(
41
- <ThemeProvider>
42
- <MessagesProvider value={{ editing: false }}>
43
- <SendButton disabled sendMessage={sendMessage} />
44
- </MessagesProvider>
45
- </ThemeProvider>,
45
+ getComponent({ disabled: true, editing: false, sendMessage }),
46
46
  );
47
47
 
48
48
  await waitFor(() => {
@@ -65,11 +65,7 @@ describe('SendButton', () => {
65
65
  const sendMessage = jest.fn();
66
66
 
67
67
  const { getByTestId, queryByTestId, toJSON } = render(
68
- <ThemeProvider>
69
- <MessagesProvider value={{ editing: true }}>
70
- <SendButton sendMessage={sendMessage} />
71
- </MessagesProvider>
72
- </ThemeProvider>,
68
+ getComponent({ editing: true, sendMessage }),
73
69
  );
74
70
 
75
71
  await waitFor(() => {
@@ -92,11 +88,7 @@ describe('SendButton', () => {
92
88
  const sendMessage = jest.fn();
93
89
 
94
90
  const { getByTestId, queryByTestId, toJSON } = render(
95
- <ThemeProvider>
96
- <MessagesProvider value={{ editing: true }}>
97
- <SendButton disabled sendMessage={sendMessage} />
98
- </MessagesProvider>
99
- </ThemeProvider>,
91
+ getComponent({ disabled: true, editing: true, sendMessage }),
100
92
  );
101
93
 
102
94
  await waitFor(() => {
@@ -3,6 +3,9 @@
3
3
  exports[`AttachButton should render a disabled AttachButton 1`] = `
4
4
  <RNGestureHandlerButton
5
5
  collapsable={false}
6
+ exclusive={true}
7
+ handlerTag={2}
8
+ handlerType="NativeViewGestureHandler"
6
9
  hitSlop={
7
10
  Object {
8
11
  "bottom": 15,
@@ -20,6 +23,7 @@ exports[`AttachButton should render a disabled AttachButton 1`] = `
20
23
  >
21
24
  <View
22
25
  accessible={true}
26
+ collapsable={false}
23
27
  hitSlop={
24
28
  Object {
25
29
  "bottom": 15,
@@ -83,6 +87,9 @@ exports[`AttachButton should render a disabled AttachButton 1`] = `
83
87
  exports[`AttachButton should render an enabled AttachButton 1`] = `
84
88
  <RNGestureHandlerButton
85
89
  collapsable={false}
90
+ exclusive={true}
91
+ handlerTag={1}
92
+ handlerType="NativeViewGestureHandler"
86
93
  hitSlop={
87
94
  Object {
88
95
  "bottom": 15,
@@ -100,6 +107,7 @@ exports[`AttachButton should render an enabled AttachButton 1`] = `
100
107
  >
101
108
  <View
102
109
  accessible={true}
110
+ collapsable={false}
103
111
  hitSlop={
104
112
  Object {
105
113
  "bottom": 15,