From 1dc4e4f9cdc147e7d59e12a751a068634adc79d3 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Tue, 2 Jun 2026 08:44:53 +0200 Subject: [PATCH] fix(chat): voice bubble preview in action menu + popup positioning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - previewNode: add audio case → VoiceNoteBubble renders correctly in blur overlay when long-pressing a voice message (was rendering empty/null) - MessageActionMenu: account for input bar (bottomInset=90) in positioning — menu no longer slides behind input bar on bottom messages; barTop clamped to never overlap the menu; both above/below paths respect usableH Co-Authored-By: Claude Sonnet 4.6 --- .../components/chat/ChatBubble.tsx | 3 +++ .../components/chat/MessageActionMenu.tsx | 27 +++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/apps/rebreak-native/components/chat/ChatBubble.tsx b/apps/rebreak-native/components/chat/ChatBubble.tsx index fd5a15a..fca8e50 100644 --- a/apps/rebreak-native/components/chat/ChatBubble.tsx +++ b/apps/rebreak-native/components/chat/ChatBubble.tsx @@ -290,10 +290,13 @@ export function ChatBubble({ { backgroundColor: bubbleBg }, !msg.isOwn && styles.bubbleOtherBorder, isImageOnly && { padding: 4 }, + isAudioMsg && { paddingHorizontal: 6, paddingTop: 6, paddingBottom: 4 }, ]} > {msg.attachmentUrl && msg.attachmentType === 'image' ? ( + ) : msg.attachmentUrl && msg.attachmentType === 'audio' ? ( + ) : msg.content !== '' ? ( {msg.content} ) : null} diff --git a/apps/rebreak-native/components/chat/MessageActionMenu.tsx b/apps/rebreak-native/components/chat/MessageActionMenu.tsx index 0c09ee7..62f8e90 100644 --- a/apps/rebreak-native/components/chat/MessageActionMenu.tsx +++ b/apps/rebreak-native/components/chat/MessageActionMenu.tsx @@ -92,15 +92,26 @@ export function MessageActionMenu({ const barH = showReactions ? 60 : 0; const estMenuH = actions.length * 52 + 12; - // Menü unter der Bubble, sonst darüber. - const belowSpace = screenH - (anchor.y + anchor.height); - const placeBelow = belowSpace > estMenuH + 40; - const menuTop = placeBelow - ? anchor.y + anchor.height + 10 - : Math.max(topSafe + barH + 10, anchor.y - estMenuH - 10); + // Input-Bar + Safe-Area am unteren Bildschirmrand (Popup darf nie darunter) + const bottomInset = 90; + const usableH = screenH - bottomInset; - // Reaktions-Leiste über der Bubble (geclampt unter die Safe-Area). - const barTop = Math.max(topSafe, anchor.y - barH - 4); + // Menü unter der Bubble wenn genug Platz, sonst darüber — Input-Bar berücksichtigt + const belowSpace = usableH - (anchor.y + anchor.height); + const placeBelow = belowSpace >= estMenuH + 8; + + const menuTopIdeal = placeBelow + ? anchor.y + anchor.height + 8 + : anchor.y - estMenuH - 8; + // Clampen: nie über Safe-Area oben, nie unter Input-Bar unten + const menuTop = Math.min( + Math.max(topSafe + barH + 8, menuTopIdeal), + usableH - estMenuH, + ); + + // Reaktions-Leiste über der Bubble — nie über topSafe, nie das Menü überlappen + const barTopIdeal = Math.max(topSafe, anchor.y - barH - 4); + const barTop = Math.min(barTopIdeal, menuTop - barH - 8); // Horizontale Ausrichtung an der Bubble-Seite. const sideStyle = isOwn