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.
- package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js +7 -23
- package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageContent.js +2 -8
- package/lib/commonjs/components/Message/MessageItemView/MessageContent.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js +41 -66
- package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js.map +1 -1
- package/lib/commonjs/icons/index.js +11 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Message/MessageItemView/MessageBubble.js +7 -23
- package/lib/module/components/Message/MessageItemView/MessageBubble.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageContent.js +2 -8
- package/lib/module/components/Message/MessageItemView/MessageContent.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageItemView.js +41 -66
- package/lib/module/components/Message/MessageItemView/MessageItemView.js.map +1 -1
- package/lib/module/icons/index.js +11 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts +8 -7
- package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageContent.d.ts +1 -2
- package/lib/typescript/components/Message/MessageItemView/MessageContent.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts +1 -10
- package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts.map +1 -1
- package/lib/typescript/icons/index.d.ts +1 -0
- package/lib/typescript/icons/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Message/MessageItemView/MessageBubble.tsx +103 -129
- package/src/components/Message/MessageItemView/MessageContent.tsx +3 -23
- package/src/components/Message/MessageItemView/MessageItemView.tsx +59 -85
- package/src/components/Message/MessageItemView/__tests__/MessageContent.test.js +2 -13
- package/src/components/Message/MessageItemView/__tests__/MessageItemView.test.js +14 -0
- package/src/components/Message/MessageItemView/__tests__/ReactionListTop.test.js +0 -3
- package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +369 -381
- package/src/icons/index.ts +1 -0
- 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
|
|
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
|
|
1
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
2
2
|
import { Dimensions, StyleSheet, View, ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import { 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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
|
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}
|
|
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: [] },
|