stream-chat-react-native-core 9.0.1-beta.2 → 9.0.1-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/Channel/Channel.js +2 -0
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +3 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js +99 -74
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageOverlayWrapper.js +64 -0
- package/lib/commonjs/components/Message/MessageOverlayWrapper.js.map +1 -0
- package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js +5 -1
- package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useShouldUseOverlayStyles.js +8 -1
- package/lib/commonjs/components/Message/hooks/useShouldUseOverlayStyles.js.map +1 -1
- package/lib/commonjs/components/Message/messageOverlayConstants.js +6 -0
- package/lib/commonjs/components/Message/messageOverlayConstants.js.map +1 -0
- package/lib/commonjs/components/index.js +11 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.js +32 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Channel/Channel.js +2 -0
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +3 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/module/components/Message/Message.js +99 -74
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageOverlayWrapper.js +64 -0
- package/lib/module/components/Message/MessageOverlayWrapper.js.map +1 -0
- package/lib/module/components/Message/hooks/useCreateMessageContext.js +5 -1
- package/lib/module/components/Message/hooks/useCreateMessageContext.js.map +1 -1
- package/lib/module/components/Message/hooks/useShouldUseOverlayStyles.js +8 -1
- package/lib/module/components/Message/hooks/useShouldUseOverlayStyles.js.map +1 -1
- package/lib/module/components/Message/messageOverlayConstants.js +6 -0
- package/lib/module/components/Message/messageOverlayConstants.js.map +1 -0
- package/lib/module/components/index.js +11 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/contexts/messageContext/MessageContext.js +32 -1
- package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Channel/Channel.d.ts +1 -1
- package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts.map +1 -1
- package/lib/typescript/components/Message/Message.d.ts +1 -1
- package/lib/typescript/components/Message/Message.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageOverlayWrapper.d.ts +18 -0
- package/lib/typescript/components/Message/MessageOverlayWrapper.d.ts.map +1 -0
- package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts +1 -1
- package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useShouldUseOverlayStyles.d.ts.map +1 -1
- package/lib/typescript/components/Message/messageOverlayConstants.d.ts +2 -0
- package/lib/typescript/components/Message/messageOverlayConstants.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +1 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts +26 -0
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +5 -0
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/Channel/Channel.tsx +3 -0
- package/src/components/Channel/hooks/useCreateMessagesContext.ts +3 -0
- package/src/components/Message/Message.tsx +109 -77
- package/src/components/Message/MessageItemView/__tests__/Message.test.js +87 -7
- package/src/components/Message/MessageOverlayWrapper.tsx +81 -0
- package/src/components/Message/hooks/__tests__/useShouldUseOverlayStyles.test.tsx +17 -2
- package/src/components/Message/hooks/useCreateMessageContext.ts +5 -0
- package/src/components/Message/hooks/useShouldUseOverlayStyles.ts +15 -2
- package/src/components/Message/messageOverlayConstants.ts +1 -0
- package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +12 -4
- package/src/components/index.ts +1 -0
- package/src/contexts/messageContext/MessageContext.tsx +44 -0
- package/src/contexts/messagesContext/MessagesContext.tsx +5 -0
- package/src/version.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React, { PropsWithChildren, useCallback, useEffect } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Portal } from 'react-native-teleport';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
MessageOverlayTargetProvider,
|
|
8
|
+
useMessageContext,
|
|
9
|
+
useMessageOverlayRuntimeContext,
|
|
10
|
+
} from '../../contexts/messageContext/MessageContext';
|
|
11
|
+
|
|
12
|
+
export type MessageOverlayWrapperProps = PropsWithChildren<{
|
|
13
|
+
/**
|
|
14
|
+
* Stable identifier for this overlay target. Must match `messageOverlayTargetId`
|
|
15
|
+
* when this subtree should be teleported into the overlay.
|
|
16
|
+
*/
|
|
17
|
+
targetId: string;
|
|
18
|
+
/**
|
|
19
|
+
* Optional test id attached to the wrapped target container.
|
|
20
|
+
*/
|
|
21
|
+
testID?: string;
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Wraps the primary message overlay target so the active message can be teleported
|
|
26
|
+
* into the overlay host while a placeholder preserves its original layout space.
|
|
27
|
+
*/
|
|
28
|
+
export const MessageOverlayWrapper = ({
|
|
29
|
+
children,
|
|
30
|
+
targetId,
|
|
31
|
+
testID,
|
|
32
|
+
}: MessageOverlayWrapperProps) => {
|
|
33
|
+
const { registerMessageOverlayTarget, unregisterMessageOverlayTarget } = useMessageContext();
|
|
34
|
+
const { messageOverlayTargetId, overlayActive, overlayTargetRectRef } =
|
|
35
|
+
useMessageOverlayRuntimeContext();
|
|
36
|
+
const isActiveTarget = messageOverlayTargetId === targetId;
|
|
37
|
+
const placeholderLayout = overlayTargetRectRef.current;
|
|
38
|
+
|
|
39
|
+
const handleTargetRef = useCallback(
|
|
40
|
+
(view: View | null) => {
|
|
41
|
+
registerMessageOverlayTarget({
|
|
42
|
+
id: targetId,
|
|
43
|
+
view,
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
[registerMessageOverlayTarget, targetId],
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
useEffect(
|
|
50
|
+
() => () => {
|
|
51
|
+
unregisterMessageOverlayTarget(targetId);
|
|
52
|
+
},
|
|
53
|
+
[targetId, unregisterMessageOverlayTarget],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (!isActiveTarget) {
|
|
57
|
+
return children;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<Portal hostName={overlayActive ? 'message-overlay' : undefined}>
|
|
63
|
+
<View collapsable={false} ref={handleTargetRef} testID={testID}>
|
|
64
|
+
<MessageOverlayTargetProvider value={isActiveTarget}>
|
|
65
|
+
{children}
|
|
66
|
+
</MessageOverlayTargetProvider>
|
|
67
|
+
</View>
|
|
68
|
+
</Portal>
|
|
69
|
+
{overlayActive ? (
|
|
70
|
+
<View
|
|
71
|
+
pointerEvents='none'
|
|
72
|
+
style={{
|
|
73
|
+
height: placeholderLayout?.h ?? 0,
|
|
74
|
+
width: placeholderLayout?.w && placeholderLayout.w > 0 ? placeholderLayout.w : '100%',
|
|
75
|
+
}}
|
|
76
|
+
testID={testID ? `${testID}-placeholder` : 'message-overlay-wrapper-placeholder'}
|
|
77
|
+
/>
|
|
78
|
+
) : null}
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -4,10 +4,12 @@ import { act, cleanup, renderHook } from '@testing-library/react-native';
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
MessageContextValue,
|
|
7
|
+
MessageOverlayRuntimeProvider,
|
|
7
8
|
MessageProvider,
|
|
8
9
|
} from '../../../../contexts/messageContext/MessageContext';
|
|
9
10
|
import { generateMessage } from '../../../../mock-builders/generator/message';
|
|
10
11
|
import { finalizeCloseOverlay, openOverlay, overlayStore } from '../../../../state-store';
|
|
12
|
+
import { DEFAULT_MESSAGE_OVERLAY_TARGET_ID } from '../../messageOverlayConstants';
|
|
11
13
|
|
|
12
14
|
import { useShouldUseOverlayStyles } from '../useShouldUseOverlayStyles';
|
|
13
15
|
|
|
@@ -22,6 +24,7 @@ const createMessageContextValue = (overrides: Partial<MessageContextValue>): Mes
|
|
|
22
24
|
groupStyles: [],
|
|
23
25
|
handleAction: jest.fn(),
|
|
24
26
|
handleToggleReaction: jest.fn(),
|
|
27
|
+
hasAttachmentActions: false,
|
|
25
28
|
hasReactions: false,
|
|
26
29
|
images: [],
|
|
27
30
|
isMessageAIGenerated: jest.fn(),
|
|
@@ -29,6 +32,7 @@ const createMessageContextValue = (overrides: Partial<MessageContextValue>): Mes
|
|
|
29
32
|
lastGroupMessage: false,
|
|
30
33
|
members: {},
|
|
31
34
|
message: generateMessage({ id: 'shared-message-id' }),
|
|
35
|
+
contextMenuAnchorRef: { current: null },
|
|
32
36
|
messageContentOrder: [],
|
|
33
37
|
messageHasOnlySingleAttachment: false,
|
|
34
38
|
messageOverlayId: 'message-overlay-default',
|
|
@@ -38,6 +42,7 @@ const createMessageContextValue = (overrides: Partial<MessageContextValue>): Mes
|
|
|
38
42
|
onPress: jest.fn(),
|
|
39
43
|
onPressIn: null,
|
|
40
44
|
otherAttachments: [],
|
|
45
|
+
registerMessageOverlayTarget: jest.fn(),
|
|
41
46
|
reactions: [],
|
|
42
47
|
readBy: false,
|
|
43
48
|
setQuotedMessage: jest.fn(),
|
|
@@ -46,13 +51,23 @@ const createMessageContextValue = (overrides: Partial<MessageContextValue>): Mes
|
|
|
46
51
|
showReactionsOverlay: jest.fn(),
|
|
47
52
|
showMessageStatus: false,
|
|
48
53
|
threadList: false,
|
|
54
|
+
unregisterMessageOverlayTarget: jest.fn(),
|
|
49
55
|
videos: [],
|
|
50
56
|
...overrides,
|
|
51
57
|
}) as MessageContextValue;
|
|
52
58
|
|
|
53
|
-
const createWrapper = (
|
|
59
|
+
const createWrapper = (
|
|
60
|
+
value: MessageContextValue,
|
|
61
|
+
runtimeValue = {
|
|
62
|
+
overlayTargetRectRef: { current: undefined },
|
|
63
|
+
messageOverlayTargetId: DEFAULT_MESSAGE_OVERLAY_TARGET_ID,
|
|
64
|
+
overlayActive: false,
|
|
65
|
+
},
|
|
66
|
+
) => {
|
|
54
67
|
const Wrapper = ({ children }: PropsWithChildren) => (
|
|
55
|
-
<MessageProvider value={value}>
|
|
68
|
+
<MessageProvider value={value}>
|
|
69
|
+
<MessageOverlayRuntimeProvider value={runtimeValue}>{children}</MessageOverlayRuntimeProvider>
|
|
70
|
+
</MessageProvider>
|
|
56
71
|
);
|
|
57
72
|
|
|
58
73
|
return Wrapper;
|
|
@@ -47,6 +47,8 @@ export const useCreateMessageContext = ({
|
|
|
47
47
|
onThreadSelect,
|
|
48
48
|
otherAttachments,
|
|
49
49
|
preventPress,
|
|
50
|
+
registerMessageOverlayTarget,
|
|
51
|
+
unregisterMessageOverlayTarget,
|
|
50
52
|
reactions,
|
|
51
53
|
readBy,
|
|
52
54
|
showAvatar,
|
|
@@ -102,6 +104,8 @@ export const useCreateMessageContext = ({
|
|
|
102
104
|
onThreadSelect,
|
|
103
105
|
otherAttachments,
|
|
104
106
|
preventPress,
|
|
107
|
+
registerMessageOverlayTarget,
|
|
108
|
+
unregisterMessageOverlayTarget,
|
|
105
109
|
reactions,
|
|
106
110
|
readBy,
|
|
107
111
|
setQuotedMessage,
|
|
@@ -134,6 +138,7 @@ export const useCreateMessageContext = ({
|
|
|
134
138
|
showMessageStatus,
|
|
135
139
|
threadList,
|
|
136
140
|
preventPress,
|
|
141
|
+
unregisterMessageOverlayTarget,
|
|
137
142
|
],
|
|
138
143
|
);
|
|
139
144
|
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useMessageContext,
|
|
3
|
+
useMessageOverlayRuntimeContext,
|
|
4
|
+
useMessageOverlayTargetContext,
|
|
5
|
+
} from '../../../contexts';
|
|
2
6
|
import { useIsOverlayActive } from '../../../state-store';
|
|
7
|
+
import { DEFAULT_MESSAGE_OVERLAY_TARGET_ID } from '../messageOverlayConstants';
|
|
3
8
|
|
|
4
9
|
export const useShouldUseOverlayStyles = () => {
|
|
5
10
|
const { messageOverlayId } = useMessageContext();
|
|
11
|
+
const { messageOverlayTargetId } = useMessageOverlayRuntimeContext();
|
|
12
|
+
const isWithinMessageOverlayTarget = useMessageOverlayTargetContext();
|
|
6
13
|
const { active, closing } = useIsOverlayActive(messageOverlayId);
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
if (!active || closing) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return messageOverlayTargetId === DEFAULT_MESSAGE_OVERLAY_TARGET_ID
|
|
20
|
+
? true
|
|
21
|
+
: isWithinMessageOverlayTarget;
|
|
9
22
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DEFAULT_MESSAGE_OVERLAY_TARGET_ID = '@stream-io/message-root';
|
|
@@ -368,7 +368,9 @@ exports[`Thread should match thread snapshot 1`] = `
|
|
|
368
368
|
>
|
|
369
369
|
<View />
|
|
370
370
|
<View>
|
|
371
|
-
<View
|
|
371
|
+
<View
|
|
372
|
+
collapsable={false}
|
|
373
|
+
>
|
|
372
374
|
<View
|
|
373
375
|
collapsable={false}
|
|
374
376
|
hitSlop={
|
|
@@ -707,7 +709,9 @@ exports[`Thread should match thread snapshot 1`] = `
|
|
|
707
709
|
>
|
|
708
710
|
<View />
|
|
709
711
|
<View>
|
|
710
|
-
<View
|
|
712
|
+
<View
|
|
713
|
+
collapsable={false}
|
|
714
|
+
>
|
|
711
715
|
<View
|
|
712
716
|
collapsable={false}
|
|
713
717
|
hitSlop={
|
|
@@ -1079,7 +1083,9 @@ exports[`Thread should match thread snapshot 1`] = `
|
|
|
1079
1083
|
>
|
|
1080
1084
|
<View />
|
|
1081
1085
|
<View>
|
|
1082
|
-
<View
|
|
1086
|
+
<View
|
|
1087
|
+
collapsable={false}
|
|
1088
|
+
>
|
|
1083
1089
|
<View
|
|
1084
1090
|
collapsable={false}
|
|
1085
1091
|
hitSlop={
|
|
@@ -1408,7 +1414,9 @@ exports[`Thread should match thread snapshot 1`] = `
|
|
|
1408
1414
|
>
|
|
1409
1415
|
<View />
|
|
1410
1416
|
<View>
|
|
1411
|
-
<View
|
|
1417
|
+
<View
|
|
1418
|
+
collapsable={false}
|
|
1419
|
+
>
|
|
1412
1420
|
<View
|
|
1413
1421
|
collapsable={false}
|
|
1414
1422
|
hitSlop={
|
package/src/components/index.ts
CHANGED
|
@@ -87,6 +87,7 @@ export * from './Message/hooks/useStreamingMessage';
|
|
|
87
87
|
export * from './Message/hooks/useMessageDeliveryData';
|
|
88
88
|
export * from './Message/hooks/useMessageReadData';
|
|
89
89
|
export * from './Message/Message';
|
|
90
|
+
export * from './Message/MessageOverlayWrapper';
|
|
90
91
|
export * from './Message/MessageItemView/MessageAuthor';
|
|
91
92
|
export * from './Message/MessageItemView/MessageBounce';
|
|
92
93
|
export * from './Message/MessageItemView/MessageBlocked';
|
|
@@ -9,11 +9,13 @@ import type {
|
|
|
9
9
|
MessagePressableHandlerPayload,
|
|
10
10
|
PressableHandlerPayload,
|
|
11
11
|
} from '../../components/Message/Message';
|
|
12
|
+
import { DEFAULT_MESSAGE_OVERLAY_TARGET_ID } from '../../components/Message/messageOverlayConstants';
|
|
12
13
|
import type { GroupType } from '../../components/MessageList/hooks/useMessageList';
|
|
13
14
|
import type { ChannelContextValue } from '../../contexts/channelContext/ChannelContext';
|
|
14
15
|
import type { MessageContentType } from '../../contexts/messagesContext/MessagesContext';
|
|
15
16
|
import type { DeepPartial } from '../../contexts/themeContext/ThemeContext';
|
|
16
17
|
import type { Theme } from '../../contexts/themeContext/utils/theme';
|
|
18
|
+
import type { Rect } from '../../state-store/message-overlay-store';
|
|
17
19
|
|
|
18
20
|
import type { MessageComposerAPIContextValue } from '../messageComposerContext/MessageComposerAPIContext';
|
|
19
21
|
import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
|
|
@@ -100,6 +102,12 @@ export type MessageContextValue = {
|
|
|
100
102
|
onPressIn: ((payload: PressableHandlerPayload) => void) | null;
|
|
101
103
|
/** The images attached to a message */
|
|
102
104
|
otherAttachments: Attachment[];
|
|
105
|
+
/**
|
|
106
|
+
* Registers the subtree that should be measured and portaled into the message overlay.
|
|
107
|
+
* Custom message renderers typically interact with this via `MessageOverlayWrapper`.
|
|
108
|
+
*/
|
|
109
|
+
registerMessageOverlayTarget: (params: { id: string; view: View | null }) => void;
|
|
110
|
+
unregisterMessageOverlayTarget: (id: string) => void;
|
|
103
111
|
reactions: ReactionSummary[];
|
|
104
112
|
/** Read count of the message */
|
|
105
113
|
readBy: number | boolean;
|
|
@@ -164,3 +172,39 @@ export const useMessageContext = () => {
|
|
|
164
172
|
|
|
165
173
|
return contextValue;
|
|
166
174
|
};
|
|
175
|
+
|
|
176
|
+
type MessageOverlayRuntimeContextValue = {
|
|
177
|
+
overlayTargetRectRef: { current: Rect };
|
|
178
|
+
messageOverlayTargetId: string;
|
|
179
|
+
overlayActive: boolean;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const MessageOverlayRuntimeContext = React.createContext<MessageOverlayRuntimeContextValue>({
|
|
183
|
+
overlayTargetRectRef: { current: undefined },
|
|
184
|
+
messageOverlayTargetId: DEFAULT_MESSAGE_OVERLAY_TARGET_ID,
|
|
185
|
+
overlayActive: false,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
export const MessageOverlayRuntimeProvider = ({
|
|
189
|
+
children,
|
|
190
|
+
value,
|
|
191
|
+
}: PropsWithChildren<{ value: MessageOverlayRuntimeContextValue }>) => (
|
|
192
|
+
<MessageOverlayRuntimeContext.Provider value={value}>
|
|
193
|
+
{children}
|
|
194
|
+
</MessageOverlayRuntimeContext.Provider>
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
export const useMessageOverlayRuntimeContext = () => useContext(MessageOverlayRuntimeContext);
|
|
198
|
+
|
|
199
|
+
const MessageOverlayTargetContext = React.createContext(false);
|
|
200
|
+
|
|
201
|
+
export const MessageOverlayTargetProvider = ({
|
|
202
|
+
children,
|
|
203
|
+
value,
|
|
204
|
+
}: PropsWithChildren<{ value: boolean }>) => (
|
|
205
|
+
<MessageOverlayTargetContext.Provider value={value}>
|
|
206
|
+
{children}
|
|
207
|
+
</MessageOverlayTargetContext.Provider>
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
export const useMessageOverlayTargetContext = () => useContext(MessageOverlayTargetContext);
|
|
@@ -75,6 +75,11 @@ export type MessagesContextValue = Pick<MessageContextValue, 'isMessageAIGenerat
|
|
|
75
75
|
initialScrollToFirstUnreadMessage: boolean;
|
|
76
76
|
/** Order to render the message content */
|
|
77
77
|
messageContentOrder: MessageContentType[];
|
|
78
|
+
/**
|
|
79
|
+
* Overlay target id that should be teleported when a message overlay opens.
|
|
80
|
+
* Custom `MessageOverlayWrapper` usages should pass a matching `targetId`.
|
|
81
|
+
*/
|
|
82
|
+
messageOverlayTargetId?: string;
|
|
78
83
|
removeMessage: (message: { id: string; parent_id?: string }) => Promise<void>;
|
|
79
84
|
/**
|
|
80
85
|
* Override the api request for retry message functionality.
|
package/src/version.json
CHANGED