stream-chat-react-native-core 9.0.0-beta.2 → 9.0.0-beta.4

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 (36) hide show
  1. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js +7 -23
  2. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  3. package/lib/commonjs/components/Message/MessageItemView/MessageContent.js +2 -8
  4. package/lib/commonjs/components/Message/MessageItemView/MessageContent.js.map +1 -1
  5. package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js +41 -66
  6. package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js.map +1 -1
  7. package/lib/commonjs/icons/index.js +11 -0
  8. package/lib/commonjs/icons/index.js.map +1 -1
  9. package/lib/commonjs/version.json +1 -1
  10. package/lib/module/components/Message/MessageItemView/MessageBubble.js +7 -23
  11. package/lib/module/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  12. package/lib/module/components/Message/MessageItemView/MessageContent.js +2 -8
  13. package/lib/module/components/Message/MessageItemView/MessageContent.js.map +1 -1
  14. package/lib/module/components/Message/MessageItemView/MessageItemView.js +41 -66
  15. package/lib/module/components/Message/MessageItemView/MessageItemView.js.map +1 -1
  16. package/lib/module/icons/index.js +11 -0
  17. package/lib/module/icons/index.js.map +1 -1
  18. package/lib/module/version.json +1 -1
  19. package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts +8 -7
  20. package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts.map +1 -1
  21. package/lib/typescript/components/Message/MessageItemView/MessageContent.d.ts +1 -2
  22. package/lib/typescript/components/Message/MessageItemView/MessageContent.d.ts.map +1 -1
  23. package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts +1 -10
  24. package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts.map +1 -1
  25. package/lib/typescript/icons/index.d.ts +1 -0
  26. package/lib/typescript/icons/index.d.ts.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/Message/MessageItemView/MessageBubble.tsx +103 -129
  29. package/src/components/Message/MessageItemView/MessageContent.tsx +3 -23
  30. package/src/components/Message/MessageItemView/MessageItemView.tsx +59 -85
  31. package/src/components/Message/MessageItemView/__tests__/MessageContent.test.js +2 -13
  32. package/src/components/Message/MessageItemView/__tests__/MessageItemView.test.js +14 -0
  33. package/src/components/Message/MessageItemView/__tests__/ReactionListTop.test.js +0 -3
  34. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +369 -381
  35. package/src/icons/index.ts +1 -0
  36. package/src/version.json +1 -1
@@ -1,12 +1,5 @@
1
1
  import React, { useMemo } from 'react';
2
- import {
3
- AnimatableNumericValue,
4
- ColorValue,
5
- LayoutChangeEvent,
6
- Pressable,
7
- StyleSheet,
8
- View,
9
- } from 'react-native';
2
+ import { AnimatableNumericValue, ColorValue, Pressable, StyleSheet, View } from 'react-native';
10
3
 
11
4
  import { MessageTextContainer } from './MessageTextContainer';
12
5
 
@@ -89,7 +82,6 @@ export type MessageContentPropsWithContext = Pick<
89
82
  | 'StreamingMessageView'
90
83
  > &
91
84
  Pick<TranslationContextValue, 't'> & {
92
- setMessageContentWidth: React.Dispatch<React.SetStateAction<number>>;
93
85
  /**
94
86
  * Background color for the message content
95
87
  */
@@ -147,7 +139,6 @@ const MessageContentWithContext = (props: MessageContentPropsWithContext) => {
147
139
  otherAttachments,
148
140
  preventPress,
149
141
  Reply,
150
- setMessageContentWidth,
151
142
  StreamingMessageView,
152
143
  hidePaddingTop,
153
144
  hidePaddingHorizontal,
@@ -181,14 +172,6 @@ const MessageContentWithContext = (props: MessageContentPropsWithContext) => {
181
172
  },
182
173
  } = useTheme();
183
174
 
184
- const onLayout: (event: LayoutChangeEvent) => void = ({
185
- nativeEvent: {
186
- layout: { width },
187
- },
188
- }) => {
189
- setMessageContentWidth(width);
190
- };
191
-
192
175
  const isAIGenerated = useMemo(
193
176
  () => isMessageAIGenerated(message),
194
177
  [message, isMessageAIGenerated],
@@ -352,7 +335,7 @@ const MessageContentWithContext = (props: MessageContentPropsWithContext) => {
352
335
  }
353
336
  }}
354
337
  >
355
- <View onLayout={onLayout} style={wrapper}>
338
+ <View style={wrapper}>
356
339
  <View
357
340
  style={[
358
341
  styles.containerInner,
@@ -551,10 +534,7 @@ const MemoizedMessageContent = React.memo(
551
534
  areEqual,
552
535
  ) as typeof MessageContentWithContext;
553
536
 
554
- export type MessageContentProps = Partial<
555
- Omit<MessageContentPropsWithContext, 'setMessageContentWidth'>
556
- > &
557
- Pick<MessageContentPropsWithContext, 'setMessageContentWidth'>;
537
+ export type MessageContentProps = Partial<MessageContentPropsWithContext>;
558
538
 
559
539
  /**
560
540
  * Child of MessageItemView that displays a message's content
@@ -1,7 +1,7 @@
1
- import React, { forwardRef, useMemo, useState } from 'react';
1
+ import React, { forwardRef, useMemo } from 'react';
2
2
  import { Dimensions, StyleSheet, View, ViewStyle } from 'react-native';
3
3
 
4
- import { MessageBubble, SwipableMessageBubble } from './MessageBubble';
4
+ import { MessageBubble, SwipableMessageWrapper } from './MessageBubble';
5
5
 
6
6
  import {
7
7
  Alignment,
@@ -71,6 +71,7 @@ const useStyles = ({
71
71
  alignItems: 'flex-end',
72
72
  gap: primitives.spacingXs,
73
73
  flexDirection: alignment === 'left' ? 'row' : 'row-reverse',
74
+ width: '100%',
74
75
  ...container,
75
76
  },
76
77
  contentContainer: {
@@ -190,20 +191,10 @@ export type MessageItemViewPropsWithContext = Pick<
190
191
  | 'reactionListPosition'
191
192
  | 'reactionListType'
192
193
  | 'ReactionListTop'
193
- > & {
194
- /**
195
- * Will determine whether the swipeable wrapper is always rendered for each
196
- * message. If set to false, the animated wrapper will be rendered only when
197
- * a swiping gesture is active and not otherwise.
198
- * Since stateful components would lose their state if we remount them while
199
- * an animation is happening, this should always be set to true in those instances.
200
- */
201
- shouldRenderSwipeableWrapper: boolean;
202
- };
194
+ >;
203
195
 
204
196
  const MessageItemViewWithContext = forwardRef<View, MessageItemViewPropsWithContext>(
205
197
  (props, ref) => {
206
- const [messageContentWidth, setMessageContentWidth] = useState(0);
207
198
  const { width } = Dimensions.get('screen');
208
199
  const {
209
200
  alignment,
@@ -230,7 +221,6 @@ const MessageItemViewWithContext = forwardRef<View, MessageItemViewPropsWithCont
230
221
  reactionListPosition,
231
222
  reactionListType,
232
223
  ReactionListTop,
233
- shouldRenderSwipeableWrapper,
234
224
  setQuotedMessage,
235
225
  } = props;
236
226
 
@@ -295,72 +285,63 @@ const MessageItemViewWithContext = forwardRef<View, MessageItemViewPropsWithCont
295
285
  setQuotedMessage(message);
296
286
  });
297
287
 
288
+ const itemViewContent = (
289
+ <View pointerEvents='box-none' style={styles.container} testID='message-item-view-wrapper'>
290
+ {alignment === 'left' ? <MessageAuthor /> : null}
291
+ {isMessageTypeDeleted ? (
292
+ <MessageDeleted date={message.created_at} groupStyle={groupStyle} />
293
+ ) : (
294
+ <View
295
+ style={[
296
+ styles.contentContainer,
297
+ isMyMessage ? styles.rightAlignItems : styles.leftAlignItems,
298
+ isMessageErrorType ? errorContainer : {},
299
+ ]}
300
+ testID='message-components'
301
+ >
302
+ <MessageHeader />
303
+ <MessageBubble
304
+ alignment={alignment}
305
+ backgroundColor={backgroundColor}
306
+ isVeryLastMessage={isVeryLastMessage}
307
+ MessageContent={MessageContent}
308
+ MessageError={MessageError}
309
+ messageGroupedSingleOrBottom={messageGroupedSingleOrBottom}
310
+ noBorder={noBorder}
311
+ reactionListPosition={reactionListPosition}
312
+ ReactionListTop={ReactionListTop}
313
+ reactionListType={reactionListType}
314
+ message={message}
315
+ />
316
+
317
+ <View style={styles.repliesContainer}>
318
+ <MessageReplies />
319
+ </View>
320
+
321
+ {reactionListPosition === 'bottom' && ReactionListBottom ? (
322
+ <ReactionListBottom type={reactionListType} />
323
+ ) : null}
324
+ <MessageFooter date={message.created_at} />
325
+ </View>
326
+ )}
327
+ {MessageSpacer ? <MessageSpacer /> : null}
328
+ </View>
329
+ );
330
+
298
331
  return (
299
332
  <View ref={ref}>
300
- <View pointerEvents='box-none' style={styles.container} testID='message-item-view-wrapper'>
301
- {alignment === 'left' ? <MessageAuthor /> : null}
302
- {isMessageTypeDeleted ? (
303
- <MessageDeleted date={message.created_at} groupStyle={groupStyle} />
304
- ) : (
305
- <View
306
- style={[
307
- styles.contentContainer,
308
- isMyMessage ? styles.rightAlignItems : styles.leftAlignItems,
309
- isMessageErrorType ? errorContainer : {},
310
- ]}
311
- testID='message-components'
312
- >
313
- <MessageHeader />
314
- {enableSwipeToReply ? (
315
- <SwipableMessageBubble
316
- alignment={alignment}
317
- backgroundColor={backgroundColor}
318
- isVeryLastMessage={isVeryLastMessage}
319
- MessageContent={MessageContent}
320
- messageContentWidth={messageContentWidth}
321
- messageGroupedSingleOrBottom={messageGroupedSingleOrBottom}
322
- MessageSwipeContent={MessageSwipeContent}
323
- MessageError={MessageError}
324
- messageSwipeToReplyHitSlop={messageSwipeToReplyHitSlop}
325
- noBorder={noBorder}
326
- onSwipe={onSwipeActionHandler}
327
- reactionListPosition={reactionListPosition}
328
- reactionListType={reactionListType}
329
- ReactionListTop={ReactionListTop}
330
- setMessageContentWidth={setMessageContentWidth}
331
- shouldRenderSwipeableWrapper={shouldRenderSwipeableWrapper}
332
- message={message}
333
- />
334
- ) : (
335
- <MessageBubble
336
- alignment={alignment}
337
- backgroundColor={backgroundColor}
338
- isVeryLastMessage={isVeryLastMessage}
339
- MessageContent={MessageContent}
340
- MessageError={MessageError}
341
- messageContentWidth={messageContentWidth}
342
- messageGroupedSingleOrBottom={messageGroupedSingleOrBottom}
343
- noBorder={noBorder}
344
- reactionListPosition={reactionListPosition}
345
- ReactionListTop={ReactionListTop}
346
- reactionListType={reactionListType}
347
- setMessageContentWidth={setMessageContentWidth}
348
- message={message}
349
- />
350
- )}
351
-
352
- <View style={styles.repliesContainer}>
353
- <MessageReplies />
354
- </View>
355
-
356
- {reactionListPosition === 'bottom' && ReactionListBottom ? (
357
- <ReactionListBottom type={reactionListType} />
358
- ) : null}
359
- <MessageFooter date={message.created_at} />
360
- </View>
361
- )}
362
- {MessageSpacer ? <MessageSpacer /> : null}
363
- </View>
333
+ {enableSwipeToReply && !isMessageTypeDeleted ? (
334
+ <SwipableMessageWrapper
335
+ alignment={alignment}
336
+ MessageSwipeContent={MessageSwipeContent}
337
+ messageSwipeToReplyHitSlop={messageSwipeToReplyHitSlop}
338
+ onSwipe={onSwipeActionHandler}
339
+ >
340
+ {itemViewContent}
341
+ </SwipableMessageWrapper>
342
+ ) : (
343
+ itemViewContent
344
+ )}
364
345
  </View>
365
346
  );
366
347
  },
@@ -504,7 +485,6 @@ export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, re
504
485
  message,
505
486
  onlyEmojis,
506
487
  otherAttachments,
507
- isMessageAIGenerated,
508
488
  setQuotedMessage,
509
489
  lastGroupMessage,
510
490
  members,
@@ -530,11 +510,6 @@ export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, re
530
510
  reactionListType,
531
511
  ReactionListTop,
532
512
  } = useMessagesContext();
533
- const isAIGenerated = useMemo(
534
- () => isMessageAIGenerated(message),
535
- [message, isMessageAIGenerated],
536
- );
537
- const shouldRenderSwipeableWrapper = (message?.attachments || []).length > 0 || isAIGenerated;
538
513
 
539
514
  return (
540
515
  <MemoizedMessageItemView
@@ -565,7 +540,6 @@ export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, re
565
540
  reactionListType,
566
541
  ReactionListTop,
567
542
  setQuotedMessage,
568
- shouldRenderSwipeableWrapper,
569
543
  lastGroupMessage,
570
544
  members,
571
545
  }}
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react';
1
+ import React from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
3
 
4
4
  import { cleanup, render, screen, waitFor } from '@testing-library/react-native';
@@ -17,8 +17,6 @@ import { getTestClientWithUser } from '../../../../mock-builders/mock';
17
17
  import { Channel } from '../../../Channel/Channel';
18
18
  import { Chat } from '../../../Chat/Chat';
19
19
  import { Message } from '../../Message';
20
- import { MessageContent } from '../MessageContent';
21
-
22
20
  describe('MessageContent', () => {
23
21
  let channel;
24
22
  let chatClient;
@@ -359,19 +357,10 @@ describe('MessageContent', () => {
359
357
  user,
360
358
  });
361
359
 
362
- // This needs to be mocked like that cause native onLayout on MessageContent would never
363
- // trigger.
364
- const MessageContentWithMockedMessageContentWidth = (props) => {
365
- useEffect(() => {
366
- props.setMessageContentWidth(100);
367
- }, [props]);
368
- return <MessageContent {...props} />;
369
- };
370
-
371
360
  render(
372
361
  <ChannelsStateProvider>
373
362
  <Chat client={chatClient}>
374
- <Channel channel={channel} MessageContent={MessageContentWithMockedMessageContentWidth}>
363
+ <Channel channel={channel}>
375
364
  <Message groupStyles={['bottom']} message={message} reactionsEnabled />
376
365
  </Channel>
377
366
  </Chat>
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import { Text } from 'react-native';
4
+ import { GestureDetector } from 'react-native-gesture-handler';
4
5
 
5
6
  import { cleanup, render, screen, waitFor } from '@testing-library/react-native';
6
7
 
@@ -107,6 +108,19 @@ describe('MessageItemView', () => {
107
108
  });
108
109
  });
109
110
 
111
+ it('wraps the full MessageItemView with swipe-to-reply', async () => {
112
+ const user = generateUser();
113
+ const message = generateMessage({ user });
114
+
115
+ renderMessage({ message });
116
+
117
+ await waitFor(() => {
118
+ const gestureDetector = screen.UNSAFE_getByType(GestureDetector);
119
+
120
+ expect(gestureDetector.findByProps({ testID: 'message-item-view-wrapper' })).toBeTruthy();
121
+ });
122
+ });
123
+
110
124
  it('renders MessageSpacer component if defined', async () => {
111
125
  const user = generateUser();
112
126
  const message = generateMessage({ user });
@@ -51,7 +51,6 @@ describe('ReactionListTop', () => {
51
51
  it('renders the ReactionListTop component', async () => {
52
52
  renderMessage({
53
53
  hasReactions: true,
54
- messageContentWidth: 100,
55
54
  reactions: [{ count: 1, own: true, type: 'love' }],
56
55
  });
57
56
 
@@ -63,7 +62,6 @@ describe('ReactionListTop', () => {
63
62
  it('return null in ReactionListTop component when hasReactions false', async () => {
64
63
  renderMessage({
65
64
  hasReactions: false,
66
- messageContentWidth: 100,
67
65
  reactions: [{ count: 1, own: true, type: 'love' }],
68
66
  });
69
67
 
@@ -76,7 +74,6 @@ describe('ReactionListTop', () => {
76
74
  renderMessage(
77
75
  {
78
76
  hasReactions: false,
79
- messageContentWidth: 100,
80
77
  reactions: [{ count: 1, own: true, type: 'love' }],
81
78
  },
82
79
  { supportedReactions: [] },