Skip to content

Commit fe20c9d

Browse files
committed
feat: improve reaction list in message customization
1 parent 06b9eed commit fe20c9d

File tree

7 files changed

+132
-49
lines changed

7 files changed

+132
-49
lines changed

package/src/components/Channel/Channel.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ import { MessageStatus as MessageStatusDefault } from '../Message/MessageSimple/
158158
import { MessageSwipeContent as MessageSwipeContentDefault } from '../Message/MessageSimple/MessageSwipeContent';
159159
import { MessageTimestamp as MessageTimestampDefault } from '../Message/MessageSimple/MessageTimestamp';
160160
import { ReactionListBottom as ReactionListBottomDefault } from '../Message/MessageSimple/ReactionList/ReactionListBottom';
161+
import { ReactionListClustered as ReactionListClusteredDefault } from '../Message/MessageSimple/ReactionList/ReactionListClustered';
162+
import { ReactionListCountItem as ReactionListCountItemDefault } from '../Message/MessageSimple/ReactionList/ReactionListItem';
163+
import { ReactionListItem as ReactionListItemDefault } from '../Message/MessageSimple/ReactionList/ReactionListItem';
164+
import { ReactionListItemWrapper as ReactionListItemWrapperDefault } from '../Message/MessageSimple/ReactionList/ReactionListItemWrapper';
161165
import { ReactionListTop as ReactionListTopDefault } from '../Message/MessageSimple/ReactionList/ReactionListTop';
162166
import { StreamingMessageView as DefaultStreamingMessageView } from '../Message/MessageSimple/StreamingMessageView';
163167
import { AttachmentUploadPreviewList as AttachmentUploadPreviewDefault } from '../MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList';
@@ -393,6 +397,10 @@ export type ChannelPropsWithContext = Pick<ChannelContextValue, 'channel'> &
393397
| 'reactionListPosition'
394398
| 'reactionListType'
395399
| 'ReactionListTop'
400+
| 'ReactionListClustered'
401+
| 'ReactionListItem'
402+
| 'ReactionListItemWrapper'
403+
| 'ReactionListCountItem'
396404
| 'Reply'
397405
| 'shouldShowUnreadUnderlay'
398406
| 'ScrollToBottomButton'
@@ -722,6 +730,10 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
722730
reactionListPosition = 'top',
723731
reactionListType = 'clustered',
724732
ReactionListTop = ReactionListTopDefault,
733+
ReactionListClustered = ReactionListClusteredDefault,
734+
ReactionListItem = ReactionListItemDefault,
735+
ReactionListItemWrapper = ReactionListItemWrapperDefault,
736+
ReactionListCountItem = ReactionListCountItemDefault,
725737
Reply = ReplyDefault,
726738
ScrollToBottomButton = ScrollToBottomButtonDefault,
727739
selectReaction,
@@ -1978,6 +1990,10 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
19781990
reactionListPosition,
19791991
reactionListType,
19801992
ReactionListTop,
1993+
ReactionListClustered,
1994+
ReactionListItem,
1995+
ReactionListItemWrapper,
1996+
ReactionListCountItem,
19811997
removeMessage,
19821998
Reply,
19831999
retrySendMessage,

package/src/components/Channel/hooks/useCreateMessagesContext.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ export const useCreateMessagesContext = ({
9191
reactionListPosition,
9292
reactionListType,
9393
ReactionListTop,
94+
ReactionListClustered,
95+
ReactionListItem,
96+
ReactionListItemWrapper,
97+
ReactionListCountItem,
9498
removeMessage,
9599
Reply,
96100
retrySendMessage,
@@ -207,6 +211,10 @@ export const useCreateMessagesContext = ({
207211
reactionListPosition,
208212
reactionListType,
209213
ReactionListTop,
214+
ReactionListClustered,
215+
ReactionListItem,
216+
ReactionListItemWrapper,
217+
ReactionListCountItem,
210218
removeMessage,
211219
Reply,
212220
retrySendMessage,

package/src/components/Message/MessageSimple/ReactionList/ReactionListBottom.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import React, { useMemo } from 'react';
1+
import React, { useCallback, useMemo } from 'react';
22
import { FlatList, StyleSheet, View } from 'react-native';
33

4-
import { ReactionListClustered } from './ReactionListClustered';
5-
import { ReactionListItem, ReactionListItemProps } from './ReactionListItem';
4+
import { ReactionListItemProps } from './ReactionListItem';
65

76
import {
87
MessageContextValue,
@@ -16,22 +15,6 @@ import { useTheme } from '../../../../contexts/themeContext/ThemeContext';
1615

1716
import { primitives } from '../../../../theme';
1817

19-
const renderItem = ({ index, item }: { index: number; item: ReactionListItemProps }) => (
20-
<ReactionListItem
21-
handleReaction={item.handleReaction}
22-
key={index}
23-
onLongPress={item.onLongPress}
24-
onPress={item.onPress}
25-
onPressIn={item.onPressIn}
26-
preventPress={item.preventPress}
27-
reaction={item.reaction}
28-
showReactionsOverlay={item.showReactionsOverlay}
29-
supportedReactions={item.supportedReactions}
30-
selected={item.reaction.own}
31-
showCount={item.showCount}
32-
/>
33-
);
34-
3518
export type ReactionListBottomProps = Partial<
3619
Pick<
3720
MessageContextValue,
@@ -46,7 +29,9 @@ export type ReactionListBottomProps = Partial<
4629
| 'showReactionsOverlay'
4730
>
4831
> &
49-
Partial<Pick<MessagesContextValue, 'supportedReactions'>> & {
32+
Partial<
33+
Pick<MessagesContextValue, 'supportedReactions' | 'ReactionListClustered' | 'ReactionListItem'>
34+
> & {
5035
type?: 'clustered' | 'segmented';
5136
showCount?: boolean;
5237
};
@@ -70,6 +55,8 @@ export const ReactionListBottom = (props: ReactionListBottomProps) => {
7055
supportedReactions: propSupportedReactions,
7156
type,
7257
showCount = true,
58+
ReactionListClustered: propReactionListClustered,
59+
ReactionListItem: propReactionListItem,
7360
} = props;
7461

7562
const {
@@ -84,7 +71,11 @@ export const ReactionListBottom = (props: ReactionListBottomProps) => {
8471
showReactionsOverlay: contextShowReactionsOverlay,
8572
} = useMessageContext();
8673

87-
const { supportedReactions: contextSupportedReactions } = useMessagesContext();
74+
const {
75+
supportedReactions: contextSupportedReactions,
76+
ReactionListClustered: contextReactionListClustered,
77+
ReactionListItem: contextReactionListItem,
78+
} = useMessagesContext();
8879

8980
const alignment = propAlignment || contextAlignment;
9081
const handleReaction = propHandlerReaction || contextHandleReaction;
@@ -96,6 +87,27 @@ export const ReactionListBottom = (props: ReactionListBottomProps) => {
9687
const reactions = propReactions || contextReactions;
9788
const showReactionsOverlay = propShowReactionsOverlay || contextShowReactionsOverlay;
9889
const supportedReactions = propSupportedReactions || contextSupportedReactions;
90+
const ReactionListClustered = propReactionListClustered || contextReactionListClustered;
91+
const ReactionListItem = propReactionListItem || contextReactionListItem;
92+
93+
const renderItem = useCallback(
94+
({ index, item }: { index: number; item: ReactionListItemProps }) => (
95+
<ReactionListItem
96+
handleReaction={item.handleReaction}
97+
key={index}
98+
onLongPress={item.onLongPress}
99+
onPress={item.onPress}
100+
onPressIn={item.onPressIn}
101+
preventPress={item.preventPress}
102+
reaction={item.reaction}
103+
showReactionsOverlay={item.showReactionsOverlay}
104+
supportedReactions={item.supportedReactions}
105+
selected={item.reaction.own}
106+
showCount={item.showCount}
107+
/>
108+
),
109+
[ReactionListItem],
110+
);
99111

100112
const styles = useStyles({ messageAlignment: alignment });
101113
const supportedReactionTypes = supportedReactions?.map(

package/src/components/Message/MessageSimple/ReactionList/ReactionListItemWrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Pressable, PressableProps, StyleProp, StyleSheet, View, ViewStyle } fro
44
import { useTheme } from '../../../../contexts/themeContext/ThemeContext';
55
import { primitives } from '../../../../theme';
66

7-
type ReactionListItemWrapperProps = PressableProps & {
7+
export type ReactionListItemWrapperProps = PressableProps & {
88
selected?: boolean;
99
style?: StyleProp<ViewStyle>;
1010
};

package/src/components/Message/MessageSimple/ReactionList/ReactionListTop.tsx

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import React, { useMemo } from 'react';
22
import { ScrollView, StyleSheet, View } from 'react-native';
33

4-
import { ReactionListClustered } from './ReactionListClustered';
5-
6-
import { ReactionListCountItem, ReactionListItem } from './ReactionListItem';
7-
84
import { useTheme } from '../../../../contexts';
95
import {
106
MessageContextValue,
@@ -29,12 +25,19 @@ export type ReactionListTopProps = Partial<
2925
| 'reactions'
3026
| 'showReactionsOverlay'
3127
| 'handleReaction'
32-
>
33-
> &
34-
Pick<MessagesContextValue, 'supportedReactions' | 'reactionListType'> & {
35-
type?: 'clustered' | 'segmented';
36-
showCount?: boolean;
37-
};
28+
> &
29+
Pick<
30+
MessagesContextValue,
31+
| 'supportedReactions'
32+
| 'reactionListType'
33+
| 'ReactionListClustered'
34+
| 'ReactionListItem'
35+
| 'ReactionListCountItem'
36+
>
37+
> & {
38+
type?: 'clustered' | 'segmented';
39+
showCount?: boolean;
40+
};
3841

3942
/**
4043
* ReactionListTop - A high level component which implements all the logic required for a message reaction list
@@ -53,6 +56,9 @@ export const ReactionListTop = (props: ReactionListTopProps) => {
5356
handleReaction: propHandleReaction,
5457
type,
5558
showCount = true,
59+
ReactionListClustered: propReactionListClustered,
60+
ReactionListItem: propReactionListItem,
61+
ReactionListCountItem: propReactionListCountItem,
5662
} = props;
5763

5864
const {
@@ -67,7 +73,12 @@ export const ReactionListTop = (props: ReactionListTopProps) => {
6773
handleReaction: contextHandleReaction,
6874
} = useMessageContext();
6975

70-
const { supportedReactions: contextSupportedReactions } = useMessagesContext();
76+
const {
77+
supportedReactions: contextSupportedReactions,
78+
ReactionListClustered: contextReactionListClustered,
79+
ReactionListItem: contextReactionListItem,
80+
ReactionListCountItem: contextReactionListCountItem,
81+
} = useMessagesContext();
7182

7283
const alignment = propAlignment || contextAlignment;
7384
const hasReactions = propHasReactions || contextHasReactions;
@@ -79,6 +90,10 @@ export const ReactionListTop = (props: ReactionListTopProps) => {
7990
const showReactionsOverlay = propShowReactionsOverlay || contextShowReactionsOverlay;
8091
const supportedReactions = propSupportedReactions || contextSupportedReactions;
8192
const handleReaction = propHandleReaction || contextHandleReaction;
93+
const ReactionListClustered = propReactionListClustered || contextReactionListClustered;
94+
const ReactionListItem = propReactionListItem || contextReactionListItem;
95+
const ReactionListCountItem = propReactionListCountItem || contextReactionListCountItem;
96+
8297
const styles = useStyles({ alignment });
8398

8499
const supportedReactionTypes = supportedReactions?.map(
@@ -98,7 +113,7 @@ export const ReactionListTop = (props: ReactionListTopProps) => {
98113
if (type === 'clustered') {
99114
return (
100115
<View style={styles.container} accessibilityLabel='Reaction List Top'>
101-
<ReactionListClustered {...props} />
116+
{ReactionListClustered ? <ReactionListClustered {...props} /> : null}
102117
</View>
103118
);
104119
}
@@ -112,21 +127,25 @@ export const ReactionListTop = (props: ReactionListTopProps) => {
112127
showsVerticalScrollIndicator={false}
113128
style={[styles.container, styles.list]}
114129
>
115-
{reactions.slice(0, 4).map((reaction) => (
116-
<ReactionListItem
117-
key={reaction.type}
118-
reaction={reaction}
119-
handleReaction={handleReaction}
120-
onLongPress={onLongPress}
121-
onPress={onPress}
122-
onPressIn={onPressIn}
123-
preventPress={preventPress}
124-
showReactionsOverlay={showReactionsOverlay}
125-
supportedReactions={supportedReactions}
126-
showCount={showCount}
127-
selected={reaction.own}
128-
/>
129-
))}
130+
{reactions
131+
.slice(0, 4)
132+
.map((reaction) =>
133+
ReactionListItem ? (
134+
<ReactionListItem
135+
key={reaction.type}
136+
reaction={reaction}
137+
handleReaction={handleReaction}
138+
onLongPress={onLongPress}
139+
onPress={onPress}
140+
onPressIn={onPressIn}
141+
preventPress={preventPress}
142+
showReactionsOverlay={showReactionsOverlay}
143+
supportedReactions={supportedReactions}
144+
showCount={showCount}
145+
selected={reaction.own}
146+
/>
147+
) : null,
148+
)}
130149
<ReactionListCountItem
131150
count={moreReactionsCount}
132151
onLongPress={onLongPress}

package/src/components/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ export * from './Message/MessageSimple/MessageTextContainer';
106106
export * from './Message/MessageSimple/MessageTimestamp';
107107
export * from './Message/MessageSimple/ReactionList/ReactionListBottom';
108108
export * from './Message/MessageSimple/ReactionList/ReactionListTop';
109+
export * from './Message/MessageSimple/ReactionList/ReactionListClustered';
110+
export * from './Message/MessageSimple/ReactionList/ReactionListItem';
111+
export * from './Message/MessageSimple/ReactionList/ReactionListItemWrapper';
109112
export * from './Message/MessageSimple/utils/renderText';
110113
export * from './Message/utils/messageActions';
111114
export * from '../utils/removeReservedFields';

package/src/contexts/messagesContext/MessagesContext.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ import type { MessageStatusProps } from '../../components/Message/MessageSimple/
4949
import type { MessageTextProps } from '../../components/Message/MessageSimple/MessageTextContainer';
5050
import { MessageTimestampProps } from '../../components/Message/MessageSimple/MessageTimestamp';
5151
import { ReactionListBottomProps } from '../../components/Message/MessageSimple/ReactionList/ReactionListBottom';
52+
import { ReactionListClusteredProps } from '../../components/Message/MessageSimple/ReactionList/ReactionListClustered';
53+
import {
54+
ReactionListItemProps,
55+
ReactionListCountItemProps,
56+
} from '../../components/Message/MessageSimple/ReactionList/ReactionListItem';
57+
import { ReactionListItemWrapperProps } from '../../components/Message/MessageSimple/ReactionList/ReactionListItemWrapper';
5258
import type { ReactionListTopProps } from '../../components/Message/MessageSimple/ReactionList/ReactionListTop';
5359
import type { MarkdownRules } from '../../components/Message/MessageSimple/utils/renderText';
5460
import type { MessageActionsParams } from '../../components/Message/utils/messageActions';
@@ -608,6 +614,25 @@ export type MessagesContextValue = Pick<MessageContextValue, 'isMessageAIGenerat
608614
*/
609615
ReactionListTop?: React.ComponentType<ReactionListTopProps>;
610616

617+
/**
618+
* UI component for ReactionListBottom
619+
* Defaults to: [ReactionList](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Reaction/ReactionList.tsx)
620+
*/
621+
ReactionListClustered: React.ComponentType<ReactionListClusteredProps>;
622+
/**
623+
* UI component for ReactionListSegmented
624+
* Defaults to: [ReactionList](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Reaction/ReactionList.tsx)
625+
*/
626+
ReactionListItem: React.ComponentType<ReactionListItemProps>;
627+
628+
/**
629+
* UI component for ReactionListItemWrapper
630+
* Defaults to: [ReactionListItemWrapper](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Reaction/ReactionListItemWrapper.tsx)
631+
*/
632+
ReactionListItemWrapper: React.ComponentType<ReactionListItemWrapperProps>;
633+
634+
ReactionListCountItem: React.ComponentType<ReactionListCountItemProps>;
635+
611636
/**
612637
* Full override of the reaction function on Message and Message Overlay
613638
*

0 commit comments

Comments
 (0)