|
|
@ -1,9 +1,10 @@ |
|
|
"use client"; |
|
|
"use client"; |
|
|
|
|
|
|
|
|
import { useEffect } from "react"; |
|
|
import { useEffect } from "react"; |
|
|
|
|
|
import { viewPaddingsBridge } from "@/lib/view-paddings"; |
|
|
|
|
|
|
|
|
let activeSheetCount = 0; |
|
|
let activeSheetCount = 0; |
|
|
let activeKeyboardInputCount = 0; |
|
|
|
|
|
|
|
|
let hasFocusedKeyboardInput = false; |
|
|
let bodyHadDropdownClass = false; |
|
|
let bodyHadDropdownClass = false; |
|
|
let initialBodyOverflow = ""; |
|
|
let initialBodyOverflow = ""; |
|
|
let initialHtmlOverflow = ""; |
|
|
let initialHtmlOverflow = ""; |
|
|
@ -26,7 +27,7 @@ export function useSheetScrollLock(isOpen: boolean) { |
|
|
activeSheetCount += 1; |
|
|
activeSheetCount += 1; |
|
|
|
|
|
|
|
|
document.body.classList.add("dropdown-open"); |
|
|
document.body.classList.add("dropdown-open"); |
|
|
document.body.classList.add("question-input-open"); |
|
|
|
|
|
|
|
|
document.body.classList.add("question-sheet-open"); |
|
|
document.body.style.overflow = "hidden"; |
|
|
document.body.style.overflow = "hidden"; |
|
|
document.documentElement.style.overflow = "hidden"; |
|
|
document.documentElement.style.overflow = "hidden"; |
|
|
if (lockedAppShell) { |
|
|
if (lockedAppShell) { |
|
|
@ -47,9 +48,7 @@ export function useSheetScrollLock(isOpen: boolean) { |
|
|
if (!bodyHadDropdownClass) { |
|
|
if (!bodyHadDropdownClass) { |
|
|
document.body.classList.remove("dropdown-open"); |
|
|
document.body.classList.remove("dropdown-open"); |
|
|
} |
|
|
} |
|
|
if (activeKeyboardInputCount === 0) { |
|
|
|
|
|
document.body.classList.remove("question-input-open"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
document.body.classList.remove("question-sheet-open"); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
}, [isOpen]); |
|
|
}, [isOpen]); |
|
|
@ -87,10 +86,10 @@ function isKeyboardInputTarget(target: EventTarget | null): boolean { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function syncQuestionInputOpenClass() { |
|
|
function syncQuestionInputOpenClass() { |
|
|
if (activeSheetCount > 0 || activeKeyboardInputCount > 0) { |
|
|
|
|
|
document.body.classList.add("question-input-open"); |
|
|
|
|
|
|
|
|
if (hasFocusedKeyboardInput) { |
|
|
|
|
|
document.body.classList.add("question-keyboard-open"); |
|
|
} else { |
|
|
} else { |
|
|
document.body.classList.remove("question-input-open"); |
|
|
|
|
|
|
|
|
document.body.classList.remove("question-keyboard-open"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -102,24 +101,52 @@ export function useQuestionInputFocusSync() { |
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
const handleFocusIn = (event: FocusEvent) => { |
|
|
const handleFocusIn = (event: FocusEvent) => { |
|
|
if (!isKeyboardInputTarget(event.target)) return; |
|
|
if (!isKeyboardInputTarget(event.target)) return; |
|
|
activeKeyboardInputCount += 1; |
|
|
|
|
|
|
|
|
hasFocusedKeyboardInput = true; |
|
|
syncQuestionInputOpenClass(); |
|
|
syncQuestionInputOpenClass(); |
|
|
}; |
|
|
}; |
|
|
const handleFocusOut = (event: FocusEvent) => { |
|
|
const handleFocusOut = (event: FocusEvent) => { |
|
|
if (!isKeyboardInputTarget(event.target)) return; |
|
|
if (!isKeyboardInputTarget(event.target)) return; |
|
|
activeKeyboardInputCount = Math.max(0, activeKeyboardInputCount - 1); |
|
|
|
|
|
|
|
|
window.setTimeout(() => { |
|
|
|
|
|
hasFocusedKeyboardInput = isKeyboardInputTarget(document.activeElement); |
|
|
|
|
|
syncQuestionInputOpenClass(); |
|
|
|
|
|
}, 0); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const unsubscribeConfig = viewPaddingsBridge.subscribeConfig((config) => { |
|
|
|
|
|
if (config.keyboardHeight > 0) { |
|
|
|
|
|
hasFocusedKeyboardInput = isKeyboardInputTarget(document.activeElement); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Android Back can hide Flutter's keyboard without dispatching blur.
|
|
|
|
|
|
hasFocusedKeyboardInput = false; |
|
|
|
|
|
} |
|
|
syncQuestionInputOpenClass(); |
|
|
syncQuestionInputOpenClass(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const initialViewportHeight = window.visualViewport?.height ?? 0; |
|
|
|
|
|
const handleViewportResize = () => { |
|
|
|
|
|
const viewportHeight = window.visualViewport?.height ?? 0; |
|
|
|
|
|
if ( |
|
|
|
|
|
initialViewportHeight > 0 && |
|
|
|
|
|
viewportHeight >= initialViewportHeight - 40 |
|
|
|
|
|
) { |
|
|
|
|
|
hasFocusedKeyboardInput = false; |
|
|
|
|
|
syncQuestionInputOpenClass(); |
|
|
|
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
document.addEventListener("focusin", handleFocusIn); |
|
|
document.addEventListener("focusin", handleFocusIn); |
|
|
document.addEventListener("focusout", handleFocusOut); |
|
|
document.addEventListener("focusout", handleFocusOut); |
|
|
|
|
|
window.visualViewport?.addEventListener("resize", handleViewportResize); |
|
|
return () => { |
|
|
return () => { |
|
|
document.removeEventListener("focusin", handleFocusIn); |
|
|
document.removeEventListener("focusin", handleFocusIn); |
|
|
document.removeEventListener("focusout", handleFocusOut); |
|
|
document.removeEventListener("focusout", handleFocusOut); |
|
|
activeKeyboardInputCount = 0; |
|
|
|
|
|
if (activeSheetCount === 0) { |
|
|
|
|
|
document.body.classList.remove("question-input-open"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
window.visualViewport?.removeEventListener( |
|
|
|
|
|
"resize", |
|
|
|
|
|
handleViewportResize, |
|
|
|
|
|
); |
|
|
|
|
|
unsubscribeConfig(); |
|
|
|
|
|
hasFocusedKeyboardInput = false; |
|
|
|
|
|
document.body.classList.remove("question-keyboard-open"); |
|
|
}; |
|
|
}; |
|
|
}, []); |
|
|
}, []); |
|
|
} |
|
|
} |