Files
automaker/apps/ui/src/hooks/use-virtual-keyboard-resize.ts

65 lines
2.2 KiB
TypeScript

import { useState, useEffect, useCallback, useRef } from 'react';
/**
* Hook that detects when the mobile virtual keyboard is open and returns
* the height offset needed to prevent the keyboard from overlapping content.
*
* Uses the Visual Viewport API to detect viewport shrinkage caused by the
* virtual keyboard. When the keyboard is open, the visual viewport height
* is smaller than the layout viewport height.
*
* @returns An object with:
* - `keyboardHeight`: The estimated keyboard height in pixels (0 when closed)
* - `isKeyboardOpen`: Boolean indicating if the keyboard is currently open
*/
export function useVirtualKeyboardResize() {
const [keyboardHeight, setKeyboardHeight] = useState(0);
const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
const initialHeightRef = useRef<number | null>(null);
const handleViewportResize = useCallback(() => {
const vv = window.visualViewport;
if (!vv) return;
// On first call, record the full viewport height (no keyboard)
if (initialHeightRef.current === null) {
initialHeightRef.current = vv.height;
}
// The keyboard height is the difference between the window inner height
// and the visual viewport height. On iOS, window.innerHeight stays the same
// when the keyboard opens, but visualViewport.height shrinks.
const heightDiff = window.innerHeight - vv.height;
// Use a threshold to avoid false positives from browser chrome changes
// (address bar show/hide causes ~50-80px changes on most browsers)
const KEYBOARD_THRESHOLD = 100;
if (heightDiff > KEYBOARD_THRESHOLD) {
setKeyboardHeight(heightDiff);
setIsKeyboardOpen(true);
} else {
setKeyboardHeight(0);
setIsKeyboardOpen(false);
}
}, []);
useEffect(() => {
const vv = window.visualViewport;
if (!vv) return;
vv.addEventListener('resize', handleViewportResize);
vv.addEventListener('scroll', handleViewportResize);
// Initial check
handleViewportResize();
return () => {
vv.removeEventListener('resize', handleViewportResize);
vv.removeEventListener('scroll', handleViewportResize);
};
}, [handleViewportResize]);
return { keyboardHeight, isKeyboardOpen };
}