Use visualViewport height to shrink chat container when mobile keyboard opens
This commit is contained in:
+18
-7
@@ -32,6 +32,8 @@ export default function Chat() {
|
||||
|
||||
const [input, setInput] = useState('');
|
||||
const [sending, setSending] = useState(false);
|
||||
const HEADER_HEIGHT = 56; // h-14 = 3.5rem = 56px
|
||||
const [containerHeight, setContainerHeight] = useState(window.innerHeight - HEADER_HEIGHT);
|
||||
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -77,19 +79,25 @@ export default function Chat() {
|
||||
}
|
||||
}, [messages, scrollToBottom]);
|
||||
|
||||
// When mobile keyboard opens/closes, scroll to bottom if user was there
|
||||
// Track visual viewport height so the container shrinks when the keyboard opens
|
||||
useEffect(() => {
|
||||
const vv = window.visualViewport;
|
||||
if (!vv) return;
|
||||
|
||||
const handleResize = () => {
|
||||
const update = () => {
|
||||
setContainerHeight(vv.height - HEADER_HEIGHT);
|
||||
// Prevent browser from scrolling the page behind fixed elements
|
||||
window.scrollTo(0, 0);
|
||||
if (isAtBottom.current) {
|
||||
requestAnimationFrame(() => scrollToBottom('instant'));
|
||||
}
|
||||
};
|
||||
|
||||
vv.addEventListener('resize', handleResize);
|
||||
return () => vv.removeEventListener('resize', handleResize);
|
||||
vv.addEventListener('resize', update);
|
||||
vv.addEventListener('scroll', () => window.scrollTo(0, 0));
|
||||
return () => {
|
||||
vv.removeEventListener('resize', update);
|
||||
};
|
||||
}, [scrollToBottom]);
|
||||
|
||||
async function handleSend(e: React.FormEvent) {
|
||||
@@ -122,9 +130,12 @@ export default function Chat() {
|
||||
return (
|
||||
<PageLayout noPadding>
|
||||
{/* Fixed container pinned below the navbar.
|
||||
Fixed positioning keeps it anchored to the viewport
|
||||
so the mobile keyboard can't push it off-screen. */}
|
||||
<div className="fixed inset-x-0 top-14 bottom-0 flex flex-col">
|
||||
Height is driven by visualViewport so it shrinks when the
|
||||
mobile keyboard opens, keeping input visible. */}
|
||||
<div
|
||||
className="fixed inset-x-0 top-14 flex flex-col"
|
||||
style={{ height: containerHeight }}
|
||||
>
|
||||
{/* Chat header */}
|
||||
<div className="flex shrink-0 items-center gap-3 border-b border-border bg-background px-4 py-3">
|
||||
<Link to="/friends">
|
||||
|
||||
Reference in New Issue
Block a user