Files
cozsweet-frontend-nextjs/src/app/chat/hooks/chat-keyboard-geometry.ts
T

106 lines
2.8 KiB
TypeScript

export const CHAT_KEYBOARD_VISIBLE_THRESHOLD_PX = 80;
export const CHAT_KEYBOARD_ZOOM_THRESHOLD = 1.05;
export const CHAT_KEYBOARD_TARGET_GAP_PX = 16;
export const CHAT_KEYBOARD_FALLBACK_WIDTH_RATIO = 0.84;
export const CHAT_KEYBOARD_FALLBACK_HEIGHT_RATIO = 0.43;
export const CHAT_KEYBOARD_FALLBACK_MIN_PX = 240;
export const CHAT_KEYBOARD_FALLBACK_MAX_PX = 340;
const CHAT_KEYBOARD_MAX_INSET_RATIO = 0.55;
export interface ChatKeyboardViewportBaseline {
layoutHeight: number;
layoutWidth: number;
visualHeight: number;
}
export type ChatKeyboardFallbackViewport = Pick<
ChatKeyboardViewportBaseline,
"layoutHeight" | "layoutWidth"
>;
export interface ChatKeyboardViewportSnapshot {
layoutHeight: number;
visualHeight: number;
visualScale: number;
virtualKeyboardHeight: number;
}
export type ChatKeyboardInsetSource =
| "content-resize"
| "visual-viewport"
| "virtual-keyboard"
| "none";
export interface ChatKeyboardInsetResolution {
keyboardVisible: boolean;
bottomInset: number;
source: ChatKeyboardInsetSource;
}
export function resolveChatKeyboardInset(
baseline: ChatKeyboardViewportBaseline,
snapshot: ChatKeyboardViewportSnapshot,
): ChatKeyboardInsetResolution {
const contentResize = baseline.layoutHeight - snapshot.layoutHeight;
if (contentResize > CHAT_KEYBOARD_VISIBLE_THRESHOLD_PX) {
return {
keyboardVisible: true,
bottomInset: 0,
source: "content-resize",
};
}
const virtualKeyboardHeight = Math.max(0, snapshot.virtualKeyboardHeight);
const visualViewportHeight =
snapshot.visualScale <= CHAT_KEYBOARD_ZOOM_THRESHOLD
? Math.max(0, baseline.visualHeight - snapshot.visualHeight)
: 0;
const occludedHeight = Math.max(
virtualKeyboardHeight,
visualViewportHeight,
);
if (occludedHeight <= CHAT_KEYBOARD_VISIBLE_THRESHOLD_PX) {
return {
keyboardVisible: false,
bottomInset: 0,
source: "none",
};
}
const maxInset = Math.round(
baseline.layoutHeight * CHAT_KEYBOARD_MAX_INSET_RATIO,
);
return {
keyboardVisible: true,
bottomInset: Math.min(
maxInset,
Math.round(occludedHeight + CHAT_KEYBOARD_TARGET_GAP_PX),
),
source:
virtualKeyboardHeight >= visualViewportHeight
? "virtual-keyboard"
: "visual-viewport",
};
}
export function resolveChatKeyboardFallbackInset(
viewport: ChatKeyboardFallbackViewport,
): number {
const widthEstimate =
viewport.layoutWidth * CHAT_KEYBOARD_FALLBACK_WIDTH_RATIO;
const heightLimit =
viewport.layoutHeight * CHAT_KEYBOARD_FALLBACK_HEIGHT_RATIO;
const estimatedKeyboardHeight = Math.min(
CHAT_KEYBOARD_FALLBACK_MAX_PX,
Math.max(
CHAT_KEYBOARD_FALLBACK_MIN_PX,
Math.round(Math.min(widthEstimate, heightLimit)),
),
);
return estimatedKeyboardHeight + CHAT_KEYBOARD_TARGET_GAP_PX;
}