Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/SampleApp/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,7 @@ PODS:
- ReactNativeDependencies
- RNFBApp
- Yoga
- RNGestureHandler (3.0.0):
- RNGestureHandler (2.31.2):
- hermes-engine
- RCTRequired
- RCTTypeSafety
Expand Down Expand Up @@ -3322,7 +3322,7 @@ SPEC CHECKSUMS:
RNFastImage: 14580cef91660b889645fb9e87f58a53621db993
RNFBApp: 3b942e786ca88524ba17df665a1a360fb3eee525
RNFBMessaging: b82ba0933288d710f5371f57d3115092abf64903
RNGestureHandler: ae4b9960c2e7d0fb3991255345bf424cca8e09e4
RNGestureHandler: a97cc64efbfcb7a53969a38310a189a3d5246c65
RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168
RNReactNativeHapticFeedback: 9dc72312c12cb53ee240b5b7aae1e167f3d940a6
RNReanimated: 8aac6baab55e39ca4e02afd69f77fb127b26520c
Expand Down
90 changes: 68 additions & 22 deletions package/src/components/Message/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
setOverlayTopH,
useIsOverlayActive,
} from '../../state-store';
import { primitives } from '../../theme';
import { FileTypes } from '../../types/types';
import {
checkMessageEquality,
Expand Down Expand Up @@ -830,8 +831,20 @@ const MessageWithContext = (props: MessagePropsWithContext) => {
}
}, [overlayActive, message]);

const groupKey: 'single' | 'top' | 'middle' | 'bottom' | undefined =
groupStyles?.[0] === 'single' ||
groupStyles?.[0] === 'top' ||
groupStyles?.[0] === 'middle' ||
groupStyles?.[0] === 'bottom'
? groupStyles[0]
: undefined;
const isVeryLastBubble =
messagesContext.enableMessageGroupingByUser &&
channel?.state.messages[channel.state.messages.length - 1]?.id === message.id;
const styles = useStyles({
groupKey,
highlightedMessage: (isTargetedMessage || message.pinned) && !isMessageTypeDeleted,
isVeryLastBubble,
});
const rect = rectRef.current;
const overlayItemsAnchorRect = bubbleRect.current ?? rect;
Expand Down Expand Up @@ -1147,34 +1160,67 @@ export const Message = (props: MessageProps) => {
);
};

const useStyles = ({ highlightedMessage }: { highlightedMessage?: boolean }) => {
const useStyles = ({
groupKey,
highlightedMessage,
isVeryLastBubble,
}: {
groupKey: 'single' | 'top' | 'middle' | 'bottom' | undefined;
highlightedMessage?: boolean;
isVeryLastBubble: boolean;
}) => {
const {
theme: {
messageItemView: { wrapper, targetedMessageContainer, blockedMessageContainer },
screenPadding,
semantics,
},
theme: { messageItemView, screenPadding, semantics },
} = useTheme();

return useMemo(() => {
return StyleSheet.create({
wrapper: {
paddingHorizontal: screenPadding,
...(highlightedMessage
? { backgroundColor: semantics.backgroundCoreHighlight, ...targetedMessageContainer }
: {}),
...wrapper,
const groupStylesMap: Record<'single' | 'top' | 'middle' | 'bottom', ViewStyle> = {
single: {
paddingVertical: primitives.spacingXs,
...messageItemView.messageGroupedSingleStyles,
},
top: {
paddingTop: primitives.spacingXs,
paddingBottom: primitives.spacingXxs,
...messageItemView.messageGroupedTopStyles,
},
middle: {
paddingBottom: primitives.spacingXxs,
...messageItemView.messageGroupedMiddleStyles,
},
bottom: {
paddingBottom: primitives.spacingXs,
...messageItemView.messageGroupedBottomStyles,
},
};

let wrapper: ViewStyle = {
paddingHorizontal: screenPadding,
...(highlightedMessage
? {
backgroundColor: semantics.backgroundCoreHighlight,
...messageItemView.targetedMessageContainer,
}
: {}),
...messageItemView.wrapper,
};
if (groupKey) {
wrapper = { ...wrapper, ...groupStylesMap[groupKey] };
}
if (isVeryLastBubble) {
wrapper = {
...wrapper,
marginBottom: primitives.spacingSm,
...messageItemView.lastMessageContainer,
};
}

return StyleSheet.create({
wrapper,
blockedMessageContainer: {
alignItems: 'center',
...blockedMessageContainer,
...messageItemView.blockedMessageContainer,
},
});
}, [
wrapper,
screenPadding,
highlightedMessage,
semantics,
targetedMessageContainer,
blockedMessageContainer,
]);
}, [messageItemView, screenPadding, semantics, highlightedMessage, groupKey, isVeryLastBubble]);
};
121 changes: 5 additions & 116 deletions package/src/components/Message/MessageItemView/MessageItemView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import { Dimensions, StyleSheet, View, ViewStyle } from 'react-native';
import { Dimensions, StyleSheet, View } from 'react-native';

import { SwipableMessageWrapper } from './MessageBubble';

Expand All @@ -22,25 +22,7 @@ import { FileTypes } from '../../../types/types';
import { checkMessageEquality, checkQuotedMessageEquality } from '../../../utils/utils';
import { useMessageData } from '../hooks/useMessageData';

type GroupType = 'single' | 'top' | 'middle' | 'bottom' | undefined;

const useStyles = ({
alignment,
isVeryLastMessage,
messageGroupedSingle,
messageGroupedBottom,
messageGroupedTop,
messageGroupedMiddle,
enableMessageGroupingByUser,
}: {
alignment: Alignment;
isVeryLastMessage: boolean;
messageGroupedSingle: boolean;
messageGroupedBottom: boolean;
messageGroupedTop: boolean;
messageGroupedMiddle: boolean;
enableMessageGroupingByUser: boolean;
}) => {
const useStyles = ({ alignment }: { alignment: Alignment }) => {
const {
theme: {
messageItemView: {
Expand All @@ -53,24 +35,11 @@ const useStyles = ({
repliesContainer,
leftAlignItems,
rightAlignItems,
messageGroupedSingleStyles,
messageGroupedBottomStyles,
messageGroupedTopStyles,
messageGroupedMiddleStyles,
lastMessageContainer,
},
},
} = useTheme();

const groupType: GroupType = useMemo(() => {
if (messageGroupedSingle) return 'single';
if (messageGroupedTop) return 'top';
if (messageGroupedMiddle) return 'middle';
if (messageGroupedBottom) return 'bottom';
return undefined;
}, [messageGroupedSingle, messageGroupedTop, messageGroupedMiddle, messageGroupedBottom]);

const styles = useMemo(
return useMemo(
() =>
StyleSheet.create({
baseContainer: {
Expand Down Expand Up @@ -129,73 +98,6 @@ const useStyles = ({
rightAlignItems,
],
);

const groupStylesMap = useMemo(() => {
return {
single: {
paddingVertical: primitives.spacingXs,
...messageGroupedSingleStyles,
},
top: {
paddingTop: primitives.spacingXs,
paddingBottom: primitives.spacingXxs,
...messageGroupedTopStyles,
},
middle: {
paddingBottom: primitives.spacingXxs,
...messageGroupedMiddleStyles,
},
bottom: {
paddingBottom: primitives.spacingXs,
...messageGroupedBottomStyles,
},
};
}, [
messageGroupedBottomStyles,
messageGroupedMiddleStyles,
messageGroupedSingleStyles,
messageGroupedTopStyles,
]);

const containerStyle = useMemo(() => {
let results: ViewStyle = styles.baseContainer;

if (groupType) {
results = {
...results,
...groupStylesMap[groupType],
};
}

if (isVeryLastMessage && enableMessageGroupingByUser) {
results = {
...results,
marginBottom: primitives.spacingSm,
...lastMessageContainer,
};
}

return results;
}, [
styles.baseContainer,
groupStylesMap,
groupType,
isVeryLastMessage,
enableMessageGroupingByUser,
lastMessageContainer,
]);

return {
container: containerStyle,
bubbleContentContainer: styles.bubbleContentContainer,
bubbleErrorContainer: styles.bubbleErrorContainer,
bubbleReactionListTopContainer: styles.bubbleReactionListTopContainer,
bubbleWrapper: styles.bubbleWrapper,
contentContainer: styles.contentContainer,
repliesContainer: styles.repliesContainer,
leftAlignItems: styles.leftAlignItems,
rightAlignItems: styles.rightAlignItems,
};
};

export type MessageItemViewPropsWithContext = Pick<
Expand Down Expand Up @@ -232,7 +134,6 @@ const MessageItemViewWithContext = (props: MessageItemViewPropsWithContext) => {
channel,
contextMenuAnchorRef,
customMessageSwipeAction,
enableMessageGroupingByUser,
enableSwipeToReply,
groupStyles,
hasAttachmentActions,
Expand Down Expand Up @@ -273,22 +174,10 @@ const MessageItemViewWithContext = (props: MessageItemViewPropsWithContext) => {
isMessageReceivedOrErrorType,
isMessageTypeDeleted,
isVeryLastMessage,
messageGroupedSingle,
messageGroupedBottom,
messageGroupedTop,
messageGroupedSingleOrBottom,
messageGroupedMiddle,
} = useMessageData({});

const styles = useStyles({
alignment,
isVeryLastMessage,
messageGroupedSingle,
messageGroupedBottom,
messageGroupedTop,
messageGroupedMiddle,
enableMessageGroupingByUser,
});
const styles = useStyles({ alignment });

const groupStyle = `${alignment}_${groupStyles?.[0]?.toLowerCase?.()}`;
const hasVisibleQuotedReply = !!message.quoted_message && !hasAttachmentActions;
Expand Down Expand Up @@ -324,7 +213,7 @@ const MessageItemViewWithContext = (props: MessageItemViewPropsWithContext) => {
});

const itemViewContent = (
<View pointerEvents='box-none' style={styles.container} testID='message-item-view-wrapper'>
<View pointerEvents='box-none' style={styles.baseContainer} testID='message-item-view-wrapper'>
{alignment === 'left' ? <MessageAuthor /> : null}
{isMessageTypeDeleted ? (
<MessageDeleted date={message.created_at} groupStyle={groupStyle} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,38 +223,47 @@ describe('MessageItemView', () => {
});
});

it('applies correct styles for when group styles are not single or bottom', async () => {
it('keeps message-item-view-wrapper free of group-positional padding', async () => {
const user = generateUser();
const message = generateMessage({ user });

renderMessage({ groupStyles: ['top'], message });

await waitFor(() => {
expect(screen.getByTestId('message-item-view-wrapper').props.style).toMatchObject({
const innerStyle = screen.getByTestId('message-item-view-wrapper').props.style;
expect(innerStyle).toMatchObject({
alignItems: 'flex-end',
gap: 8,
flexDirection: 'row',
paddingTop: 8,
paddingBottom: 4,
});
expect(innerStyle.paddingTop).toBeUndefined();
expect(innerStyle.paddingBottom).toBeUndefined();
});
});

it('applies correct styles for when group styles are single/bottom and not last message', async () => {
it('hoists the per-group padding delta onto message-wrapper for top messages', async () => {
const user = generateUser();
const message = generateMessage({ user });

renderMessage({ message });
renderMessage({ groupStyles: ['top'], message });

await waitFor(() => {
const data = screen.getByTestId('message-item-view-wrapper').props.style;
expect(screen.getByTestId('message-wrapper').props.style).toEqual(
expect.arrayContaining([expect.objectContaining({ paddingTop: 8 })]),
);
});
});

expect(data).toMatchObject({
alignItems: 'flex-end',
gap: 8,
flexDirection: 'row',
paddingBottom: 8,
});
it('hoists the per-group padding delta onto message-wrapper for bottom messages', async () => {
const user = generateUser();
const message = generateMessage({ user });

renderMessage({ message });

await waitFor(() => {
expect(screen.getByTestId('message-wrapper').props.style).toEqual(
expect.arrayContaining([expect.objectContaining({ paddingBottom: 8 })]),
);
});
});

Expand Down
2 changes: 1 addition & 1 deletion package/src/components/MessageMenu/MessageActionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const useStyles = () => {
StyleSheet.create({
container: {
borderRadius: primitives.radiusLg,
marginTop: 6,
marginTop: 8,
backgroundColor: semantics.backgroundCoreElevation2,
borderWidth: 1,
borderColor: semantics.borderCoreDefault,
Expand Down
Loading