fix(chat): scope keyboard fallback to Xiaomi Facebook IAB
This commit is contained in:
@@ -2,17 +2,17 @@
|
|||||||
/**
|
/**
|
||||||
* 软键盘避让 hook。
|
* 软键盘避让 hook。
|
||||||
*
|
*
|
||||||
* 目标环境:Facebook IAB / 小米 WebView 等软键盘覆盖页面但 viewport 信号不稳定的浏览器。
|
* 目标环境:小米系设备上的 Facebook IAB 等软键盘覆盖页面但 viewport 信号不稳定的浏览器。
|
||||||
*
|
*
|
||||||
* 策略:
|
* 策略:
|
||||||
* 1. 持续写入 --app-viewport-height,聊天页高度不再只依赖 100dvh。
|
* 1. 持续写入 --app-viewport-height,聊天页高度不再只依赖 100dvh。
|
||||||
* 2. 优先使用 visualViewport 计算键盘高度。
|
* 2. 优先使用 visualViewport 计算键盘高度。
|
||||||
* 3. 输入框聚焦后测量目标元素是否越过可见底部,计算额外抬升。
|
* 3. 输入框聚焦后测量目标元素是否越过可见底部,计算额外抬升。
|
||||||
* 4. Android 应用内浏览器若 viewport 未可靠变化,启用保守 fallback 抬升。
|
* 4. 小米系 Android + Facebook IAB 若 viewport 未可靠变化,启用保守 fallback 抬升。
|
||||||
*/
|
*/
|
||||||
import { type RefObject, useEffect, useRef } from "react";
|
import { type RefObject, useEffect, useRef } from "react";
|
||||||
|
|
||||||
import { BrowserDetector, Logger } from "@/utils";
|
import { BrowserDetector, Logger, PlatformDetector } from "@/utils";
|
||||||
|
|
||||||
const KEYBOARD_VAR = "--keyboard-height";
|
const KEYBOARD_VAR = "--keyboard-height";
|
||||||
const VIEWPORT_VAR = "--app-viewport-height";
|
const VIEWPORT_VAR = "--app-viewport-height";
|
||||||
@@ -57,11 +57,12 @@ export function useKeyboardHeight({
|
|||||||
const metrics = readViewportMetrics();
|
const metrics = readViewportMetrics();
|
||||||
const keyboardHeight = Math.round(metrics.keyboardHeight);
|
const keyboardHeight = Math.round(metrics.keyboardHeight);
|
||||||
const viewportHeight = Math.round(metrics.visibleHeight);
|
const viewportHeight = Math.round(metrics.visibleHeight);
|
||||||
|
const fallbackLift = computeFallbackLift(metrics);
|
||||||
const inputLift = Math.round(
|
const inputLift = Math.round(
|
||||||
activeRef.current
|
activeRef.current
|
||||||
? Math.max(
|
? Math.max(
|
||||||
computeTargetOverlap(targetRef?.current, metrics.visibleBottom),
|
computeTargetOverlap(targetRef?.current, metrics.visibleBottom),
|
||||||
computeFallbackLift(metrics),
|
fallbackLift,
|
||||||
)
|
)
|
||||||
: 0,
|
: 0,
|
||||||
);
|
);
|
||||||
@@ -93,6 +94,7 @@ export function useKeyboardHeight({
|
|||||||
keyboardHeight,
|
keyboardHeight,
|
||||||
viewportHeight,
|
viewportHeight,
|
||||||
inputLift,
|
inputLift,
|
||||||
|
fallbackLift,
|
||||||
visualViewport: metrics.hasVisualViewport,
|
visualViewport: metrics.hasVisualViewport,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -198,7 +200,11 @@ function computeFallbackLift(metrics: ViewportMetrics): number {
|
|||||||
function shouldUseInAppKeyboardFallback(): boolean {
|
function shouldUseInAppKeyboardFallback(): boolean {
|
||||||
if (typeof navigator === "undefined") return false;
|
if (typeof navigator === "undefined") return false;
|
||||||
const ua = navigator.userAgent;
|
const ua = navigator.userAgent;
|
||||||
return /Android/i.test(ua) && BrowserDetector.isInAppBrowser(ua);
|
return (
|
||||||
|
PlatformDetector.isAndroid(ua) &&
|
||||||
|
PlatformDetector.isXiaomiFamilyDevice(ua) &&
|
||||||
|
BrowserDetector.isFacebookInAppBrowser(ua)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clamp(value: number, min: number, max: number): number {
|
function clamp(value: number, min: number, max: number): number {
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ export class PlatformDetector {
|
|||||||
return PlatformDetector.getPlatformInfo(ua).isDesktop;
|
return PlatformDetector.getPlatformInfo(ua).isDesktop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isXiaomiFamilyDevice(ua: string | null = null): boolean {
|
||||||
|
const info = PlatformDetector.getPlatformInfo(ua);
|
||||||
|
const target = `${info.deviceVendor} ${info.deviceModel} ${info.userAgent}`;
|
||||||
|
return /\b(Xiaomi|Redmi|POCO|Mi\s|MIX|MIUI)\b/i.test(target);
|
||||||
|
}
|
||||||
|
|
||||||
private static getUserAgent(ua: string | null = null): string {
|
private static getUserAgent(ua: string | null = null): string {
|
||||||
if (ua) return ua;
|
if (ua) return ua;
|
||||||
if (typeof navigator === "undefined") return "";
|
if (typeof navigator === "undefined") return "";
|
||||||
|
|||||||
Reference in New Issue
Block a user