refactor(keyboard): remove input restore fallback logic
This commit is contained in:
@@ -28,11 +28,7 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
|||||||
|
|
||||||
useKeyboardHeight({
|
useKeyboardHeight({
|
||||||
targetRef: textareaRef,
|
targetRef: textareaRef,
|
||||||
containerRef: barRef,
|
|
||||||
active: isFocused,
|
active: isFocused,
|
||||||
onKeyboardDismiss: () => {
|
|
||||||
setIsFocused(false);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleInputChange = (value: string) => {
|
const handleInputChange = (value: string) => {
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ export const FOCUS_GAP_PX = 14;
|
|||||||
export const FALLBACK_INPUT_LIFT_PX = 320;
|
export const FALLBACK_INPUT_LIFT_PX = 320;
|
||||||
export const KEYBOARD_VISIBLE_THRESHOLD_PX = 80;
|
export const KEYBOARD_VISIBLE_THRESHOLD_PX = 80;
|
||||||
export const KEYBOARD_VISIBLE_RATIO = 0.82;
|
export const KEYBOARD_VISIBLE_RATIO = 0.82;
|
||||||
export const KEYBOARD_RELEASE_GRACE_MS = 900;
|
|
||||||
export const KEYBOARD_MEASURE_DELAYS_MS = [0, 100, 250, 500];
|
export const KEYBOARD_MEASURE_DELAYS_MS = [0, 100, 250, 500];
|
||||||
export const KEYBOARD_POLL_INTERVAL_MS = 300;
|
export const KEYBOARD_POLL_INTERVAL_MS = 300;
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
* - 非目标 Android Facebook IAB 设备:完全不生效。
|
* - 非目标 Android Facebook IAB 设备:完全不生效。
|
||||||
* - focus 后短期多次测量输入框是否被 visibleViewport 遮挡。
|
* - focus 后短期多次测量输入框是否被 visibleViewport 遮挡。
|
||||||
* - 若 viewport 没有可靠变化,则使用固定 fallback 抬升。
|
* - 若 viewport 没有可靠变化,则使用固定 fallback 抬升。
|
||||||
* - 聚焦期间轻量轮询;一旦检测到 viewport 恢复,主动 blur 并清除抬升。
|
* - 聚焦期间轻量轮询,持续保持输入框避让。
|
||||||
*/
|
*/
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import { Logger } from "@/utils";
|
import { Logger } from "@/utils";
|
||||||
|
|
||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
FOCUS_GAP_PX,
|
FOCUS_GAP_PX,
|
||||||
KEYBOARD_MEASURE_DELAYS_MS,
|
KEYBOARD_MEASURE_DELAYS_MS,
|
||||||
KEYBOARD_POLL_INTERVAL_MS,
|
KEYBOARD_POLL_INTERVAL_MS,
|
||||||
KEYBOARD_RELEASE_GRACE_MS,
|
|
||||||
KEYBOARD_VISIBLE_RATIO,
|
KEYBOARD_VISIBLE_RATIO,
|
||||||
KEYBOARD_VISIBLE_THRESHOLD_PX,
|
KEYBOARD_VISIBLE_THRESHOLD_PX,
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
@@ -33,10 +32,7 @@ import {
|
|||||||
getKeyboardAdaptEnvironment,
|
getKeyboardAdaptEnvironment,
|
||||||
shouldEnableKeyboardAdaptation,
|
shouldEnableKeyboardAdaptation,
|
||||||
} from "./environment";
|
} from "./environment";
|
||||||
import {
|
import { isKeyboardTargetActive } from "./keyboard-target";
|
||||||
blurKeyboardTarget,
|
|
||||||
isKeyboardTargetActive,
|
|
||||||
} from "./keyboard-target";
|
|
||||||
import type { UseKeyboardHeightOptions } from "./types";
|
import type { UseKeyboardHeightOptions } from "./types";
|
||||||
|
|
||||||
const log = new Logger("HooksUseKeyboardHeight");
|
const log = new Logger("HooksUseKeyboardHeight");
|
||||||
@@ -51,16 +47,8 @@ interface KeyboardSnapshot {
|
|||||||
|
|
||||||
export function useKeyboardHeight({
|
export function useKeyboardHeight({
|
||||||
targetRef,
|
targetRef,
|
||||||
containerRef,
|
|
||||||
active = false,
|
active = false,
|
||||||
onKeyboardDismiss,
|
|
||||||
}: UseKeyboardHeightOptions = {}): void {
|
}: UseKeyboardHeightOptions = {}): void {
|
||||||
const onKeyboardDismissRef = useRef(onKeyboardDismiss);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onKeyboardDismissRef.current = onKeyboardDismiss;
|
|
||||||
}, [onKeyboardDismiss]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window === "undefined") return;
|
if (typeof window === "undefined") return;
|
||||||
|
|
||||||
@@ -77,10 +65,7 @@ export function useKeyboardHeight({
|
|||||||
let rafId: number | null = null;
|
let rafId: number | null = null;
|
||||||
let pollId: number | null = null;
|
let pollId: number | null = null;
|
||||||
let timeoutIds: number[] = [];
|
let timeoutIds: number[] = [];
|
||||||
let released = false;
|
|
||||||
let keyboardWasDetected = false;
|
|
||||||
let lastInputLift = -1;
|
let lastInputLift = -1;
|
||||||
const focusedAt = active ? performance.now() : 0;
|
|
||||||
|
|
||||||
log.debug("[keyboard] environment", environment);
|
log.debug("[keyboard] environment", environment);
|
||||||
|
|
||||||
@@ -107,39 +92,18 @@ export function useKeyboardHeight({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const release = (reason: string) => {
|
|
||||||
if (released) return;
|
|
||||||
released = true;
|
|
||||||
clearTimers();
|
|
||||||
applyLift(0, reason);
|
|
||||||
blurKeyboardTarget(targetRef?.current);
|
|
||||||
onKeyboardDismissRef.current?.();
|
|
||||||
log.debug("[keyboard] released", {
|
|
||||||
reason,
|
|
||||||
snapshot: formatSnapshot(readKeyboardSnapshot()),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const measure = (reason: string) => {
|
const measure = (reason: string) => {
|
||||||
rafId = null;
|
rafId = null;
|
||||||
|
|
||||||
const target = targetRef?.current;
|
const target = targetRef?.current;
|
||||||
const activeNow = isKeyboardTargetActive(target, active);
|
const activeNow = isKeyboardTargetActive(target, active);
|
||||||
const snapshot = readKeyboardSnapshot();
|
const snapshot = readKeyboardSnapshot();
|
||||||
if (snapshot.keyboardVisible) keyboardWasDetected = true;
|
|
||||||
|
|
||||||
if (!activeNow) {
|
if (!activeNow) {
|
||||||
release("target-inactive");
|
log.debug("[keyboard] skip inactive target", {
|
||||||
return;
|
reason,
|
||||||
}
|
snapshot: formatSnapshot(snapshot),
|
||||||
|
});
|
||||||
const focusedFor = focusedAt > 0 ? performance.now() - focusedAt : 0;
|
|
||||||
if (
|
|
||||||
keyboardWasDetected &&
|
|
||||||
!snapshot.keyboardVisible &&
|
|
||||||
focusedFor >= KEYBOARD_RELEASE_GRACE_MS
|
|
||||||
) {
|
|
||||||
release("viewport-restored");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,26 +127,7 @@ export function useKeyboardHeight({
|
|||||||
scheduleMeasure("viewport-signal");
|
scheduleMeasure("viewport-signal");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFocusOut = () => {
|
|
||||||
release("focusout");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePointerDown = (event: PointerEvent | TouchEvent) => {
|
|
||||||
const target = targetRef?.current;
|
|
||||||
const container = containerRef?.current;
|
|
||||||
if (event.target instanceof Node && container?.contains(event.target)) {
|
|
||||||
log.debug("[keyboard] keep active for input container tap", {
|
|
||||||
snapshot: formatSnapshot(readKeyboardSnapshot()),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!target || event.target === target) return;
|
|
||||||
if (event.target instanceof Node && target.contains(event.target)) return;
|
|
||||||
release("outside-interaction");
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!active) {
|
if (!active) {
|
||||||
release("react-inactive");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,11 +136,7 @@ export function useKeyboardHeight({
|
|||||||
visualViewport?.addEventListener("scroll", handleViewportSignal);
|
visualViewport?.addEventListener("scroll", handleViewportSignal);
|
||||||
window.addEventListener("resize", handleViewportSignal);
|
window.addEventListener("resize", handleViewportSignal);
|
||||||
window.addEventListener("orientationchange", handleViewportSignal);
|
window.addEventListener("orientationchange", handleViewportSignal);
|
||||||
window.addEventListener("focusout", handleFocusOut);
|
|
||||||
window.addEventListener("blur", handleFocusOut);
|
|
||||||
document.addEventListener("visibilitychange", handleViewportSignal);
|
document.addEventListener("visibilitychange", handleViewportSignal);
|
||||||
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
||||||
document.addEventListener("touchstart", handlePointerDown, true);
|
|
||||||
|
|
||||||
scheduleInitialMeasures();
|
scheduleInitialMeasures();
|
||||||
pollId = window.setInterval(
|
pollId = window.setInterval(
|
||||||
@@ -210,18 +151,10 @@ export function useKeyboardHeight({
|
|||||||
visualViewport?.removeEventListener("scroll", handleViewportSignal);
|
visualViewport?.removeEventListener("scroll", handleViewportSignal);
|
||||||
window.removeEventListener("resize", handleViewportSignal);
|
window.removeEventListener("resize", handleViewportSignal);
|
||||||
window.removeEventListener("orientationchange", handleViewportSignal);
|
window.removeEventListener("orientationchange", handleViewportSignal);
|
||||||
window.removeEventListener("focusout", handleFocusOut);
|
|
||||||
window.removeEventListener("blur", handleFocusOut);
|
|
||||||
document.removeEventListener("visibilitychange", handleViewportSignal);
|
document.removeEventListener("visibilitychange", handleViewportSignal);
|
||||||
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
||||||
document.removeEventListener("touchstart", handlePointerDown, true);
|
|
||||||
resetInputLiftVar();
|
resetInputLiftVar();
|
||||||
};
|
};
|
||||||
}, [
|
}, [active, targetRef]);
|
||||||
active,
|
|
||||||
containerRef,
|
|
||||||
targetRef,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function readKeyboardSnapshot(): KeyboardSnapshot {
|
function readKeyboardSnapshot(): KeyboardSnapshot {
|
||||||
|
|||||||
@@ -4,23 +4,3 @@ export function isKeyboardTargetActive(
|
|||||||
): boolean {
|
): boolean {
|
||||||
return reactActive || (target != null && document.activeElement === target);
|
return reactActive || (target != null && document.activeElement === target);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function blurKeyboardTarget(
|
|
||||||
target: HTMLElement | null | undefined,
|
|
||||||
): void {
|
|
||||||
if (!target || document.activeElement !== target) return;
|
|
||||||
target.blur();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getActiveElementTag(): string | null {
|
|
||||||
const activeElement = document.activeElement;
|
|
||||||
if (!activeElement) return null;
|
|
||||||
|
|
||||||
const id = activeElement.id ? `#${activeElement.id}` : "";
|
|
||||||
const className =
|
|
||||||
typeof activeElement.className === "string" && activeElement.className
|
|
||||||
? `.${activeElement.className.split(/\s+/).filter(Boolean).join(".")}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return `${activeElement.tagName.toLowerCase()}${id}${className}`;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import type { RefObject } from "react";
|
|||||||
|
|
||||||
export interface UseKeyboardHeightOptions {
|
export interface UseKeyboardHeightOptions {
|
||||||
targetRef?: RefObject<HTMLElement | null>;
|
targetRef?: RefObject<HTMLElement | null>;
|
||||||
containerRef?: RefObject<HTMLElement | null>;
|
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
onKeyboardDismiss?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KeyboardAdaptEnvironment {
|
export interface KeyboardAdaptEnvironment {
|
||||||
|
|||||||
Reference in New Issue
Block a user