@@ -33,192 +33,196 @@ export type MessageBubbleProps = Pick<
3333 > &
3434 Pick < ReactionListTopProps , 'messageContentWidth' > ;
3535
36- export const MessageBubble = ( {
37- reactionListPosition,
38- messageContentWidth,
39- setMessageContentWidth,
40- MessageContent,
41- ReactionListTop,
42- backgroundColor,
43- isVeryLastMessage,
44- messageGroupedSingleOrBottom,
45- noBorder,
46- } : MessageBubbleProps ) => {
47- const {
48- theme : {
49- messageSimple : { contentWrapper } ,
50- } ,
51- } = useTheme ( ) ;
52-
53- return (
54- < View style = { [ styles . contentWrapper , contentWrapper ] } >
55- < MessageContent
56- backgroundColor = { backgroundColor }
57- isVeryLastMessage = { isVeryLastMessage }
58- messageGroupedSingleOrBottom = { messageGroupedSingleOrBottom }
59- noBorder = { noBorder }
60- setMessageContentWidth = { setMessageContentWidth }
61- />
62- { reactionListPosition === 'top' && ReactionListTop ? (
63- < ReactionListTop messageContentWidth = { messageContentWidth } />
64- ) : null }
65- </ View >
66- ) ;
67- } ;
36+ export const MessageBubble = React . memo (
37+ ( {
38+ reactionListPosition,
39+ messageContentWidth,
40+ setMessageContentWidth,
41+ MessageContent,
42+ ReactionListTop,
43+ backgroundColor,
44+ isVeryLastMessage,
45+ messageGroupedSingleOrBottom,
46+ noBorder,
47+ } : MessageBubbleProps ) => {
48+ const {
49+ theme : {
50+ messageSimple : { contentWrapper } ,
51+ } ,
52+ } = useTheme ( ) ;
53+
54+ return (
55+ < View style = { [ styles . contentWrapper , contentWrapper ] } >
56+ < MessageContent
57+ backgroundColor = { backgroundColor }
58+ isVeryLastMessage = { isVeryLastMessage }
59+ messageGroupedSingleOrBottom = { messageGroupedSingleOrBottom }
60+ noBorder = { noBorder }
61+ setMessageContentWidth = { setMessageContentWidth }
62+ />
63+ { reactionListPosition === 'top' && ReactionListTop ? (
64+ < ReactionListTop messageContentWidth = { messageContentWidth } />
65+ ) : null }
66+ </ View >
67+ ) ;
68+ } ,
69+ ) ;
6870
6971const AnimatedWrapper = Animated . createAnimatedComponent ( View ) ;
7072
71- export const SwipableMessageBubble = (
72- props : MessageBubbleProps &
73- Pick < MessagesContextValue , 'MessageSwipeContent' > &
74- Pick <
75- MessageSimplePropsWithContext ,
76- 'shouldRenderSwipeableWrapper' | 'messageSwipeToReplyHitSlop'
77- > & { onSwipe : ( ) => void } ,
78- ) => {
79- const {
80- MessageSwipeContent,
81- shouldRenderSwipeableWrapper,
82- messageSwipeToReplyHitSlop,
83- onSwipe,
84- ...messageBubbleProps
85- } = props ;
86-
87- const {
88- theme : {
89- messageSimple : { contentWrapper, swipeContentContainer } ,
90- } ,
91- } = useTheme ( ) ;
92-
93- const translateX = useSharedValue ( 0 ) ;
94- const touchStart = useSharedValue < { x : number ; y : number } | null > ( null ) ;
95- const isSwiping = useSharedValue < boolean > ( false ) ;
96- const [ shouldRenderAnimatedWrapper , setShouldRenderAnimatedWrapper ] = useState < boolean > (
97- shouldRenderSwipeableWrapper ,
98- ) ;
99-
100- const SWIPABLE_THRESHOLD = 25 ;
101-
102- const triggerHaptic = NativeHandlers . triggerHaptic ;
103-
104- const swipeGesture = useMemo (
105- ( ) =>
106- Gesture . Pan ( )
107- . hitSlop ( messageSwipeToReplyHitSlop )
108- . onBegin ( ( event ) => {
109- touchStart . value = { x : event . x , y : event . y } ;
110- } )
111- . onTouchesMove ( ( event , state ) => {
112- if ( ! touchStart . value || ! event . changedTouches . length ) {
113- state . fail ( ) ;
114- return ;
115- }
116-
117- const xDiff = Math . abs ( event . changedTouches [ 0 ] . x - touchStart . value . x ) ;
118- const yDiff = Math . abs ( event . changedTouches [ 0 ] . y - touchStart . value . y ) ;
119- const isHorizontalPanning = xDiff > yDiff ;
120-
121- if ( isHorizontalPanning ) {
122- state . activate ( ) ;
123- isSwiping . value = true ;
124- if ( ! shouldRenderSwipeableWrapper ) {
125- runOnJS ( setShouldRenderAnimatedWrapper ) ( isSwiping . value ) ;
126- }
127- } else {
128- state . fail ( ) ;
129- }
130- } )
131- . onStart ( ( ) => {
132- translateX . value = 0 ;
133- } )
134- . onChange ( ( { translationX } ) => {
135- if ( translationX > 0 ) {
136- translateX . value = translationX ;
137- }
138- } )
139- . onEnd ( ( ) => {
140- if ( translateX . value >= SWIPABLE_THRESHOLD ) {
141- runOnJS ( onSwipe ) ( ) ;
142- if ( triggerHaptic ) {
143- runOnJS ( triggerHaptic ) ( 'impactMedium' ) ;
73+ export const SwipableMessageBubble = React . memo (
74+ (
75+ props : MessageBubbleProps &
76+ Pick < MessagesContextValue , 'MessageSwipeContent' > &
77+ Pick <
78+ MessageSimplePropsWithContext ,
79+ 'shouldRenderSwipeableWrapper' | 'messageSwipeToReplyHitSlop'
80+ > & { onSwipe : ( ) => void } ,
81+ ) => {
82+ const {
83+ MessageSwipeContent,
84+ shouldRenderSwipeableWrapper,
85+ messageSwipeToReplyHitSlop,
86+ onSwipe,
87+ ...messageBubbleProps
88+ } = props ;
89+
90+ const {
91+ theme : {
92+ messageSimple : { contentWrapper, swipeContentContainer } ,
93+ } ,
94+ } = useTheme ( ) ;
95+
96+ const translateX = useSharedValue ( 0 ) ;
97+ const touchStart = useSharedValue < { x : number ; y : number } | null > ( null ) ;
98+ const isSwiping = useSharedValue < boolean > ( false ) ;
99+ const [ shouldRenderAnimatedWrapper , setShouldRenderAnimatedWrapper ] = useState < boolean > (
100+ shouldRenderSwipeableWrapper ,
101+ ) ;
102+
103+ const SWIPABLE_THRESHOLD = 25 ;
104+
105+ const triggerHaptic = NativeHandlers . triggerHaptic ;
106+
107+ const swipeGesture = useMemo (
108+ ( ) =>
109+ Gesture . Pan ( )
110+ . hitSlop ( messageSwipeToReplyHitSlop )
111+ . onBegin ( ( event ) => {
112+ touchStart . value = { x : event . x , y : event . y } ;
113+ } )
114+ . onTouchesMove ( ( event , state ) => {
115+ if ( ! touchStart . value || ! event . changedTouches . length ) {
116+ state . fail ( ) ;
117+ return ;
144118 }
145- }
146- isSwiping . value = false ;
147- translateX . value = withSpring (
148- 0 ,
149- {
150- dampingRatio : 1 ,
151- duration : 500 ,
152- overshootClamping : true ,
153- stiffness : 1 ,
154- } ,
155- ( ) => {
119+
120+ const xDiff = Math . abs ( event . changedTouches [ 0 ] . x - touchStart . value . x ) ;
121+ const yDiff = Math . abs ( event . changedTouches [ 0 ] . y - touchStart . value . y ) ;
122+ const isHorizontalPanning = xDiff > yDiff ;
123+
124+ if ( isHorizontalPanning ) {
125+ state . activate ( ) ;
126+ isSwiping . value = true ;
156127 if ( ! shouldRenderSwipeableWrapper ) {
157128 runOnJS ( setShouldRenderAnimatedWrapper ) ( isSwiping . value ) ;
158129 }
159- } ,
160- ) ;
161- } ) ,
162- [
163- isSwiping ,
164- messageSwipeToReplyHitSlop ,
165- onSwipe ,
166- touchStart ,
167- translateX ,
168- triggerHaptic ,
169- shouldRenderSwipeableWrapper ,
170- ] ,
171- ) ;
172-
173- const messageBubbleAnimatedStyle = useAnimatedStyle (
174- ( ) => ( {
175- transform : [ { translateX : translateX . value } ] ,
176- } ) ,
177- [ ] ,
178- ) ;
179-
180- const swipeContentAnimatedStyle = useAnimatedStyle (
181- ( ) => ( {
182- opacity : interpolate ( translateX . value , [ 0 , SWIPABLE_THRESHOLD ] , [ 0 , 1 ] ) ,
183- transform : [
184- {
185- translateX : interpolate (
186- translateX . value ,
187- [ 0 , SWIPABLE_THRESHOLD ] ,
188- [ - SWIPABLE_THRESHOLD , 0 ] ,
189- Extrapolation . CLAMP ,
190- ) ,
191- } ,
130+ } else {
131+ state . fail ( ) ;
132+ }
133+ } )
134+ . onStart ( ( ) => {
135+ translateX . value = 0 ;
136+ } )
137+ . onChange ( ( { translationX } ) => {
138+ if ( translationX > 0 ) {
139+ translateX . value = translationX ;
140+ }
141+ } )
142+ . onEnd ( ( ) => {
143+ if ( translateX . value >= SWIPABLE_THRESHOLD ) {
144+ runOnJS ( onSwipe ) ( ) ;
145+ if ( triggerHaptic ) {
146+ runOnJS ( triggerHaptic ) ( 'impactMedium' ) ;
147+ }
148+ }
149+ isSwiping . value = false ;
150+ translateX . value = withSpring (
151+ 0 ,
152+ {
153+ dampingRatio : 1 ,
154+ duration : 500 ,
155+ overshootClamping : true ,
156+ stiffness : 1 ,
157+ } ,
158+ ( ) => {
159+ if ( ! shouldRenderSwipeableWrapper ) {
160+ runOnJS ( setShouldRenderAnimatedWrapper ) ( isSwiping . value ) ;
161+ }
162+ } ,
163+ ) ;
164+ } ) ,
165+ [
166+ isSwiping ,
167+ messageSwipeToReplyHitSlop ,
168+ onSwipe ,
169+ touchStart ,
170+ translateX ,
171+ triggerHaptic ,
172+ shouldRenderSwipeableWrapper ,
192173 ] ,
193- } ) ,
194- [ ] ,
195- ) ;
196-
197- return (
198- < GestureDetector gesture = { swipeGesture } >
199- < View hitSlop = { messageSwipeToReplyHitSlop } style = { [ styles . contentWrapper , contentWrapper ] } >
200- { shouldRenderAnimatedWrapper ? (
201- < >
202- < AnimatedWrapper
203- style = { [
204- styles . swipeContentContainer ,
205- swipeContentAnimatedStyle ,
206- swipeContentContainer ,
207- ] }
208- >
209- { MessageSwipeContent ? < MessageSwipeContent /> : null }
210- </ AnimatedWrapper >
211- < AnimatedWrapper pointerEvents = 'box-none' style = { messageBubbleAnimatedStyle } >
212- < MessageBubble { ...messageBubbleProps } />
213- </ AnimatedWrapper >
214- </ >
215- ) : (
216- < MessageBubble { ...messageBubbleProps } />
217- ) }
218- </ View >
219- </ GestureDetector >
220- ) ;
221- } ;
174+ ) ;
175+
176+ const messageBubbleAnimatedStyle = useAnimatedStyle (
177+ ( ) => ( {
178+ transform : [ { translateX : translateX . value } ] ,
179+ } ) ,
180+ [ ] ,
181+ ) ;
182+
183+ const swipeContentAnimatedStyle = useAnimatedStyle (
184+ ( ) => ( {
185+ opacity : interpolate ( translateX . value , [ 0 , SWIPABLE_THRESHOLD ] , [ 0 , 1 ] ) ,
186+ transform : [
187+ {
188+ translateX : interpolate (
189+ translateX . value ,
190+ [ 0 , SWIPABLE_THRESHOLD ] ,
191+ [ - SWIPABLE_THRESHOLD , 0 ] ,
192+ Extrapolation . CLAMP ,
193+ ) ,
194+ } ,
195+ ] ,
196+ } ) ,
197+ [ ] ,
198+ ) ;
199+
200+ return (
201+ < GestureDetector gesture = { swipeGesture } >
202+ < View hitSlop = { messageSwipeToReplyHitSlop } style = { [ styles . contentWrapper , contentWrapper ] } >
203+ { shouldRenderAnimatedWrapper ? (
204+ < >
205+ < AnimatedWrapper
206+ style = { [
207+ styles . swipeContentContainer ,
208+ swipeContentAnimatedStyle ,
209+ swipeContentContainer ,
210+ ] }
211+ >
212+ { MessageSwipeContent ? < MessageSwipeContent /> : null }
213+ </ AnimatedWrapper >
214+ < AnimatedWrapper pointerEvents = 'box-none' style = { messageBubbleAnimatedStyle } >
215+ < MessageBubble { ...messageBubbleProps } />
216+ </ AnimatedWrapper >
217+ </ >
218+ ) : (
219+ < MessageBubble { ...messageBubbleProps } />
220+ ) }
221+ </ View >
222+ </ GestureDetector >
223+ ) ;
224+ } ,
225+ ) ;
222226
223227const styles = StyleSheet . create ( {
224228 contentWrapper : {
0 commit comments