chore(chat): add keyboard adaptation diagnostics

This commit is contained in:
2026-06-26 15:34:37 +08:00
parent f0ba1756b6
commit 23330787c0
+75 -6
View File
@@ -73,6 +73,7 @@ export function useKeyboardHeight({
let lastInputLift = -1;
let lastMayBeKeyboardClose = false;
let fallbackWasApplied = false;
let lastEventType = "initial";
const environment = getKeyboardAdaptEnvironment();
log.debug("[keyboard] environment", environment);
@@ -90,11 +91,45 @@ export function useKeyboardHeight({
const metrics = readViewportMetrics();
let activeNow = isKeyboardTargetActive(targetRef?.current, activeRef.current);
const shouldTryRelease =
activeNow &&
lastMayBeKeyboardClose &&
shouldReleaseKeyboardState(metrics, focusedAtRef.current);
if (
activeNow &&
lastMayBeKeyboardClose &&
shouldReleaseKeyboardState(metrics, focusedAtRef.current)
!shouldTryRelease
) {
log.debug("[keyboard] release skipped", {
reason: getReleaseSkipReason(metrics, focusedAtRef.current),
lastEventType,
environment,
active: activeNow,
reactActive: activeRef.current,
fallbackAllowed: fallbackAllowedRef.current,
lastInputLift,
fallbackWasApplied,
focusedForMs: getFocusedDurationMs(focusedAtRef.current),
metrics: formatMetrics(metrics),
});
}
if (shouldTryRelease) {
log.debug("[keyboard] release confirmed", {
lastEventType,
environment,
active: activeNow,
reactActive: activeRef.current,
fallbackAllowed: fallbackAllowedRef.current,
lastInputLift,
fallbackWasApplied,
focusedForMs: getFocusedDurationMs(focusedAtRef.current),
metrics: formatMetrics(metrics),
});
}
if (shouldTryRelease) {
releaseKeyboardState("keyboard-close-detected", metrics);
activeNow = false;
}
@@ -157,14 +192,31 @@ export function useKeyboardHeight({
};
const scheduleRechecks = (event?: Event) => {
lastEventType = event?.type ?? "manual";
const hadInputLift = fallbackWasApplied || lastInputLift > 0;
const possibleKeyboardClose =
event != null && isPossibleKeyboardCloseEvent(event, hadInputLift);
log.debug("[keyboard] schedule rechecks", {
eventType: lastEventType,
possibleKeyboardClose,
hadInputLift,
fallbackWasApplied,
lastInputLift,
active: activeRef.current,
fallbackAllowed: fallbackAllowedRef.current,
focusedForMs: getFocusedDurationMs(focusedAtRef.current),
});
if (
event &&
isPossibleKeyboardCloseEvent(
event,
fallbackWasApplied || lastInputLift > 0,
)
possibleKeyboardClose
) {
lastMayBeKeyboardClose = true;
log.debug("[keyboard] possible close detected", {
eventType: lastEventType,
hadInputLift,
fallbackWasApplied,
lastInputLift,
focusedForMs: getFocusedDurationMs(focusedAtRef.current),
});
}
timeoutIds.forEach((id) => window.clearTimeout(id));
timeoutIds = RECHECK_DELAYS_MS.map((delay) =>
@@ -302,6 +354,23 @@ function shouldReleaseKeyboardState(
return !hasDetectedKeyboard(metrics);
}
function getFocusedDurationMs(focusedAt: number): number | null {
if (focusedAt <= 0) return null;
return Math.round(performance.now() - focusedAt);
}
function getReleaseSkipReason(
metrics: ViewportMetrics,
focusedAt: number,
): string {
if (focusedAt <= 0) return "not-focused-by-hook";
if (performance.now() - focusedAt < FALLBACK_CLOSE_GRACE_MS) {
return "within-close-grace-window";
}
if (hasDetectedKeyboard(metrics)) return "keyboard-still-detected";
return "unknown";
}
function hasDetectedKeyboard(metrics: ViewportMetrics): boolean {
return (
metrics.keyboardHeight > 80 ||