Add viewport-offset handling so mobile bottom bars stay anchored while virtual keyboards resize the visual viewport. - add a shared viewportOffset utility to compute keyboard-related visual viewport compensation - update dashboard app bootstrap/index logic to apply compensation variables for pinned footer/nav layout - extend mobile keyboard layout coverage with dedicated viewport compensation and bottom-bar tests - document the keyboard/pinned-bar behavior update in dashboard guide Files changed: docs/dashboard-guide.md | 2 +- .../mobile-bottom-bars-keyboard-layout.test.ts | 12 ++- .../viewport-compensation-keyboard.test.ts | 24 ++++++ packages/dashboard/app/index.html | 39 +++++++++- .../app/utils/__tests__/viewportOffset.test.ts | 86 ++++++++++++++++++++++ packages/dashboard/app/utils/viewportOffset.ts | 64 ++++++++++++++++ 6 files changed, 223 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-5702 Fusion-Task-Lineage: be47ad0c-82df-4c38-9577-94c2eee49a0e
65 lines
1.5 KiB
TypeScript
65 lines
1.5 KiB
TypeScript
const NON_TEXT_INPUT_TYPES = new Set([
|
|
"checkbox",
|
|
"radio",
|
|
"button",
|
|
"submit",
|
|
"reset",
|
|
"file",
|
|
"range",
|
|
"color",
|
|
"hidden",
|
|
]);
|
|
|
|
export interface ComputeIcbOffsetsInput {
|
|
innerWidth: number;
|
|
innerHeight: number;
|
|
vvWidth: number;
|
|
vvHeight: number;
|
|
vvOffsetTop: number;
|
|
vvOffsetLeft: number;
|
|
vvScale: number;
|
|
activeElementIsKeyboardFocusable: boolean;
|
|
baselineViewportHeight: number | null;
|
|
}
|
|
|
|
export interface IcbOffsets {
|
|
rightOffset: number;
|
|
bottomOffset: number;
|
|
}
|
|
|
|
export function isKeyboardFocusableInputType(type: string | null | undefined): boolean {
|
|
if (!type) return true;
|
|
return !NON_TEXT_INPUT_TYPES.has(type.toLowerCase());
|
|
}
|
|
|
|
export function computeIcbOffsets(input: ComputeIcbOffsetsInput): IcbOffsets {
|
|
const {
|
|
innerWidth,
|
|
innerHeight,
|
|
vvWidth,
|
|
vvHeight,
|
|
vvOffsetTop,
|
|
vvOffsetLeft,
|
|
vvScale,
|
|
activeElementIsKeyboardFocusable,
|
|
baselineViewportHeight,
|
|
} = input;
|
|
|
|
const rightOffset = Math.max(0, innerWidth - vvOffsetLeft - vvWidth);
|
|
const rawBottomOffset = Math.max(0, innerHeight - vvOffsetTop - vvHeight);
|
|
|
|
if (!activeElementIsKeyboardFocusable || vvScale > 1.01 || baselineViewportHeight == null) {
|
|
return { rightOffset, bottomOffset: rawBottomOffset };
|
|
}
|
|
|
|
const keyboardShrink = Math.max(0, baselineViewportHeight - vvHeight);
|
|
if (keyboardShrink <= 0) {
|
|
return { rightOffset, bottomOffset: rawBottomOffset };
|
|
}
|
|
|
|
return {
|
|
rightOffset,
|
|
bottomOffset: Math.max(0, rawBottomOffset - keyboardShrink),
|
|
};
|
|
}
|