fix(mobile): steady overlay entrance while the keyboard dismisses
Opening a bottom-sheet overlay usually dismisses the keyboard in the same moment, so the panel's keyboard-inset bottom anchor was transitioning down underneath the panel's own rise animation — a jerky, offset entrance. The anchor now snaps to its final position for the duration of the enter animation and resumes animating afterwards (so an already-open overlay still lifts smoothly when the keyboard reopens).
This commit is contained in:
@@ -43,6 +43,12 @@ export const MobileOverlayPanel: React.FC<MobileOverlayPanelProps> = ({
|
||||
}) => {
|
||||
const overlayRootRef = React.useRef<HTMLElement | null>(null);
|
||||
const [entered, setEntered] = React.useState(false);
|
||||
// True once the enter transition has finished. While entering, the panel's
|
||||
// keyboard-inset bottom anchor must NOT animate: opening an overlay usually
|
||||
// closes the keyboard at the same moment, and a transitioning `bottom` under
|
||||
// the panel's own rise made the entrance jerky / offset. During the enter the
|
||||
// anchor snaps to its final value and only the rise animates.
|
||||
const [enterSettled, setEnterSettled] = React.useState(false);
|
||||
|
||||
if (typeof document !== 'undefined' && !overlayRootRef.current) {
|
||||
overlayRootRef.current = ensureOverlayRoot();
|
||||
@@ -52,10 +58,18 @@ export const MobileOverlayPanel: React.FC<MobileOverlayPanelProps> = ({
|
||||
React.useEffect(() => {
|
||||
if (!open) {
|
||||
setEntered(false);
|
||||
setEnterSettled(false);
|
||||
return;
|
||||
}
|
||||
const id = window.setTimeout(() => setEntered(true), ENTER_DELAY_MS);
|
||||
return () => window.clearTimeout(id);
|
||||
const settleId = window.setTimeout(
|
||||
() => setEnterSettled(true),
|
||||
ENTER_DELAY_MS + ENTER_DURATION_MS + 50,
|
||||
);
|
||||
return () => {
|
||||
window.clearTimeout(id);
|
||||
window.clearTimeout(settleId);
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -86,6 +100,7 @@ export const MobileOverlayPanel: React.FC<MobileOverlayPanelProps> = ({
|
||||
<div
|
||||
className={cn(
|
||||
'oc-keyboard-inset-surface fixed inset-0 z-[60] flex flex-col bg-[rgb(0_0_0_/_0.45)] transition-opacity duration-200 ease-out',
|
||||
!enterSettled && 'oc-keyboard-inset-snap',
|
||||
entered ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
role="dialog"
|
||||
|
||||
Reference in New Issue
Block a user