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 overlayRootRef = React.useRef<HTMLElement | null>(null);
|
||||||
const [entered, setEntered] = React.useState(false);
|
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) {
|
if (typeof document !== 'undefined' && !overlayRootRef.current) {
|
||||||
overlayRootRef.current = ensureOverlayRoot();
|
overlayRootRef.current = ensureOverlayRoot();
|
||||||
@@ -52,10 +58,18 @@ export const MobileOverlayPanel: React.FC<MobileOverlayPanelProps> = ({
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setEntered(false);
|
setEntered(false);
|
||||||
|
setEnterSettled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const id = window.setTimeout(() => setEntered(true), ENTER_DELAY_MS);
|
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]);
|
}, [open]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -86,6 +100,7 @@ export const MobileOverlayPanel: React.FC<MobileOverlayPanelProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
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',
|
'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',
|
entered ? 'opacity-100' : 'opacity-0',
|
||||||
)}
|
)}
|
||||||
role="dialog"
|
role="dialog"
|
||||||
|
|||||||
@@ -583,6 +583,12 @@
|
|||||||
bottom: var(--oc-keyboard-inset, 0px);
|
bottom: var(--oc-keyboard-inset, 0px);
|
||||||
transition: bottom 0.25s cubic-bezier(0.38, 0.7, 0.125, 1), opacity 0.2s ease-out;
|
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
|
/* 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
|
shell, so shrink them by the keyboard height the same way the shell does. Capping
|
||||||
|
|||||||
Reference in New Issue
Block a user