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"
|
||||
|
||||
@@ -583,6 +583,12 @@
|
||||
bottom: var(--oc-keyboard-inset, 0px);
|
||||
transition: bottom 0.25s cubic-bezier(0.38, 0.7, 0.125, 1), opacity 0.2s ease-out;
|
||||
}
|
||||
/* While a panel is playing its enter animation, its bottom anchor snaps
|
||||
instead of transitioning — opening an overlay typically dismisses the
|
||||
keyboard in the same moment, and animating both made the entrance jerky. */
|
||||
:root.oc-capacitor-app .oc-keyboard-inset-surface.oc-keyboard-inset-snap {
|
||||
transition: opacity 0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Full-screen scroll views (e.g. the connect/login screen) live outside the app
|
||||
shell, so shrink them by the keyboard height the same way the shell does. Capping
|
||||
|
||||
Reference in New Issue
Block a user