@@ -38,6 +38,16 @@ let mountCount = 0;
3838// across instances.
3939let cssVarsApplied = false ;
4040
41+ export const getImmediateVisibleViewportHeight = (
42+ baselineHeight : number ,
43+ viewportHeight : number ,
44+ savedKeyboardHeight : number ,
45+ varsAlreadyApplied : boolean
46+ ) : number => {
47+ if ( varsAlreadyApplied ) return viewportHeight ;
48+ return savedKeyboardHeight > 0 ? baselineHeight - savedKeyboardHeight : viewportHeight ;
49+ } ;
50+
4151function isEditableElement ( element : Element | null ) : boolean {
4252 if ( ! ( element instanceof HTMLElement ) ) return false ;
4353
@@ -131,11 +141,17 @@ export function useKeyboardHeight() {
131141 // immediate and stability-timer setCSSVars calls land on the same pixel
132142 // value — eliminating the second layout change that causes visible
133143 // timeline stutter during the keyboard animation.
134- if ( ! cssVarsApplied ) {
135- const estimatedViewportHeight =
136- sharedSavedHeight > 0 ? baselineHeight - sharedSavedHeight : viewport . height ;
137- setCSSVars ( estimatedViewportHeight ) ;
138- }
144+ // Keep the CSS height pinned to the live viewport on every keyboard-mode
145+ // resize. The React state still waits for a stable value, but the layout
146+ // should not lag behind when iOS swaps between text and emoji keyboards.
147+ setCSSVars (
148+ getImmediateVisibleViewportHeight (
149+ baselineHeight ,
150+ viewport . height ,
151+ sharedSavedHeight ,
152+ cssVarsApplied
153+ )
154+ ) ;
139155
140156 // Cancel any document scroll iOS may have applied as scroll-prediction.
141157 if ( window . scrollY !== 0 ) {
0 commit comments