From 86d2acc07896e37a030f5a3dcda735978e79f77e Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 5 Nov 2025 14:26:23 +0100 Subject: [PATCH 1/6] perf: prevent unmounting `MessageBubble` when STR happens --- .../Message/MessageSimple/MessageBubble.tsx | 59 +++++++------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/package/src/components/Message/MessageSimple/MessageBubble.tsx b/package/src/components/Message/MessageSimple/MessageBubble.tsx index 773cfd818..c053ac4d5 100644 --- a/package/src/components/Message/MessageSimple/MessageBubble.tsx +++ b/package/src/components/Message/MessageSimple/MessageBubble.tsx @@ -3,7 +3,6 @@ import { StyleSheet, View } from 'react-native'; import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import Animated, { - Extrapolation, interpolate, runOnJS, useAnimatedStyle, @@ -138,7 +137,7 @@ export const SwipableMessageBubble = React.memo( .onStart(() => { translateX.value = 0; }) - .onChange(({ translationX }) => { + .onUpdate(({ translationX }) => { if (translationX > 0) { translateX.value = translationX; } @@ -177,51 +176,32 @@ export const SwipableMessageBubble = React.memo( ], ); - const messageBubbleAnimatedStyle = useAnimatedStyle( - () => ({ - transform: [{ translateX: translateX.value }], - }), - [], - ); - const swipeContentAnimatedStyle = useAnimatedStyle( () => ({ opacity: interpolate(translateX.value, [0, SWIPABLE_THRESHOLD], [0, 1]), - transform: [ - { - translateX: interpolate( - translateX.value, - [0, SWIPABLE_THRESHOLD], - [-SWIPABLE_THRESHOLD, 0], - Extrapolation.CLAMP, - ), - }, - ], + width: translateX.value, }), [], ); return ( - + {shouldRenderAnimatedWrapper ? ( - <> - - {MessageSwipeContent ? : null} - - - - - - ) : ( - - )} + + {MessageSwipeContent ? : null} + + ) : null} + ); @@ -232,8 +212,11 @@ const styles = StyleSheet.create({ contentWrapper: { alignItems: 'center', flexDirection: 'row', + width: 200, }, swipeContentContainer: { - position: 'absolute', + flexShrink: 0, + overflow: 'hidden', + position: 'relative', }, }); From eccab673c931f7d7da30aee4d31f6f46f59195d8 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Fri, 7 Nov 2025 09:46:39 +0100 Subject: [PATCH 2/6] fix: failing snapshot --- .../__snapshots__/Thread.test.js.snap | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap index 436bb023d..ff0886b6b 100644 --- a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +++ b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap @@ -378,8 +378,12 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, + { + "width": 0, + }, ] } > @@ -389,6 +393,7 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, ] @@ -747,8 +752,12 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, + { + "width": 0, + }, ] } > @@ -758,6 +767,7 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, ] @@ -1154,8 +1164,12 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, + { + "width": 0, + }, ] } > @@ -1165,6 +1179,7 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, ] @@ -1527,8 +1542,12 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, + { + "width": 0, + }, ] } > @@ -1538,6 +1557,7 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", + "width": 200, }, {}, ] From ae7385704f28699782539f7ff0de0c0ee0da8c95 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Mon, 17 Nov 2025 08:54:01 +0100 Subject: [PATCH 3/6] fix: broken message bubble component --- .../Message/MessageSimple/MessageBubble.tsx | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/package/src/components/Message/MessageSimple/MessageBubble.tsx b/package/src/components/Message/MessageSimple/MessageBubble.tsx index c053ac4d5..5079f13b6 100644 --- a/package/src/components/Message/MessageSimple/MessageBubble.tsx +++ b/package/src/components/Message/MessageSimple/MessageBubble.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react'; +import React, { SetStateAction, useMemo, useState } from 'react'; import { StyleSheet, View } from 'react-native'; import { Gesture, GestureDetector } from 'react-native-gesture-handler'; @@ -16,6 +16,7 @@ import { ReactionListTopProps } from './ReactionList/ReactionListTop'; import { MessagesContextValue, useTheme } from '../../../contexts'; +import { useStableCallback } from '../../../hooks'; import { NativeHandlers } from '../../../native'; export type MessageBubbleProps = Pick< @@ -104,6 +105,14 @@ export const SwipableMessageBubble = React.memo( const triggerHaptic = NativeHandlers.triggerHaptic; + const setMessageContentWidth = useStableCallback((valueOrCallback: SetStateAction) => { + if (typeof valueOrCallback === 'number') { + props.setMessageContentWidth(Math.round(valueOrCallback)); + return; + } + props.setMessageContentWidth(valueOrCallback); + }); + const swipeGesture = useMemo( () => Gesture.Pan() @@ -188,7 +197,11 @@ export const SwipableMessageBubble = React.memo( 0 ? { width: props.messageContentWidth } : {}, + ]} > {shouldRenderAnimatedWrapper ? ( : null} ) : null} - + ); @@ -212,7 +225,7 @@ const styles = StyleSheet.create({ contentWrapper: { alignItems: 'center', flexDirection: 'row', - width: 200, + // width: 200, }, swipeContentContainer: { flexShrink: 0, From 387497099819c9abfa7cbc39823eeca37b957e48 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 18 Nov 2025 11:00:06 +0100 Subject: [PATCH 4/6] fix: rounding errors and unnecessary width enforcing --- .../Message/MessageSimple/MessageBubble.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/package/src/components/Message/MessageSimple/MessageBubble.tsx b/package/src/components/Message/MessageSimple/MessageBubble.tsx index 5079f13b6..4cc502de6 100644 --- a/package/src/components/Message/MessageSimple/MessageBubble.tsx +++ b/package/src/components/Message/MessageSimple/MessageBubble.tsx @@ -107,7 +107,7 @@ export const SwipableMessageBubble = React.memo( const setMessageContentWidth = useStableCallback((valueOrCallback: SetStateAction) => { if (typeof valueOrCallback === 'number') { - props.setMessageContentWidth(Math.round(valueOrCallback)); + props.setMessageContentWidth(Math.ceil(valueOrCallback)); return; } props.setMessageContentWidth(valueOrCallback); @@ -175,13 +175,13 @@ export const SwipableMessageBubble = React.memo( ); }), [ - isSwiping, messageSwipeToReplyHitSlop, - onSwipe, touchStart, + isSwiping, + shouldRenderSwipeableWrapper, translateX, + onSwipe, triggerHaptic, - shouldRenderSwipeableWrapper, ], ); @@ -200,7 +200,9 @@ export const SwipableMessageBubble = React.memo( style={[ styles.contentWrapper, contentWrapper, - props.messageContentWidth > 0 ? { width: props.messageContentWidth } : {}, + props.messageContentWidth > 0 && shouldRenderAnimatedWrapper + ? { width: props.messageContentWidth } + : {}, ]} > {shouldRenderAnimatedWrapper ? ( From 0261ac9d80f73610f16c11dd9796238322131e92 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 18 Nov 2025 11:04:21 +0100 Subject: [PATCH 5/6] fix: update snapshot again --- .../__snapshots__/Thread.test.js.snap | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap index ff0886b6b..af67127f3 100644 --- a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +++ b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap @@ -378,12 +378,9 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, - { - "width": 0, - }, + {}, ] } > @@ -393,7 +390,6 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, ] @@ -752,12 +748,9 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, - { - "width": 0, - }, + {}, ] } > @@ -767,7 +760,6 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, ] @@ -1164,12 +1156,9 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, - { - "width": 0, - }, + {}, ] } > @@ -1179,7 +1168,6 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, ] @@ -1542,12 +1530,9 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, - { - "width": 0, - }, + {}, ] } > @@ -1557,7 +1542,6 @@ exports[`Thread should match thread snapshot 1`] = ` { "alignItems": "center", "flexDirection": "row", - "width": 200, }, {}, ] From 5aca3e3b2f34fa1e0d612c90419c412dc6605142 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Fri, 21 Nov 2025 14:01:33 +0100 Subject: [PATCH 6/6] chore: remove redundant changes --- package/src/components/Message/MessageSimple/MessageBubble.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package/src/components/Message/MessageSimple/MessageBubble.tsx b/package/src/components/Message/MessageSimple/MessageBubble.tsx index 4cc502de6..d53cee18b 100644 --- a/package/src/components/Message/MessageSimple/MessageBubble.tsx +++ b/package/src/components/Message/MessageSimple/MessageBubble.tsx @@ -146,7 +146,7 @@ export const SwipableMessageBubble = React.memo( .onStart(() => { translateX.value = 0; }) - .onUpdate(({ translationX }) => { + .onChange(({ translationX }) => { if (translationX > 0) { translateX.value = translationX; } @@ -227,7 +227,6 @@ const styles = StyleSheet.create({ contentWrapper: { alignItems: 'center', flexDirection: 'row', - // width: 200, }, swipeContentContainer: { flexShrink: 0,