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
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { computeIcbOffsets } from "../viewportOffset";
|
|
|
|
describe("computeIcbOffsets", () => {
|
|
it("returns zero offsets for healthy viewport", () => {
|
|
const offsets = computeIcbOffsets({
|
|
innerWidth: 390,
|
|
innerHeight: 844,
|
|
vvWidth: 390,
|
|
vvHeight: 844,
|
|
vvOffsetTop: 0,
|
|
vvOffsetLeft: 0,
|
|
vvScale: 1,
|
|
activeElementIsKeyboardFocusable: false,
|
|
baselineViewportHeight: 844,
|
|
});
|
|
|
|
expect(offsets).toEqual({ rightOffset: 0, bottomOffset: 0 });
|
|
});
|
|
|
|
it("clamps iOS keyboard shrink to keep bottom offset pinned", () => {
|
|
const offsets = computeIcbOffsets({
|
|
innerWidth: 390,
|
|
innerHeight: 844,
|
|
vvWidth: 390,
|
|
vvHeight: 520,
|
|
vvOffsetTop: 0,
|
|
vvOffsetLeft: 0,
|
|
vvScale: 1,
|
|
activeElementIsKeyboardFocusable: true,
|
|
baselineViewportHeight: 844,
|
|
});
|
|
|
|
expect(offsets.bottomOffset).toBe(0);
|
|
});
|
|
|
|
it("preserves pinch-zoom offset compensation", () => {
|
|
const offsets = computeIcbOffsets({
|
|
innerWidth: 390,
|
|
innerHeight: 844,
|
|
vvWidth: 280,
|
|
vvHeight: 600,
|
|
vvOffsetTop: 0,
|
|
vvOffsetLeft: 0,
|
|
vvScale: 1.2,
|
|
activeElementIsKeyboardFocusable: true,
|
|
baselineViewportHeight: 844,
|
|
});
|
|
|
|
expect(offsets.bottomOffset).toBeGreaterThan(0);
|
|
expect(offsets.rightOffset).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("preserves Android ICB-stuck compensation without focus", () => {
|
|
const offsets = computeIcbOffsets({
|
|
innerWidth: 430,
|
|
innerHeight: 932,
|
|
vvWidth: 412,
|
|
vvHeight: 850,
|
|
vvOffsetTop: 0,
|
|
vvOffsetLeft: 0,
|
|
vvScale: 1,
|
|
activeElementIsKeyboardFocusable: false,
|
|
baselineViewportHeight: 932,
|
|
});
|
|
|
|
expect(offsets.bottomOffset).toBe(82);
|
|
expect(offsets.rightOffset).toBe(18);
|
|
});
|
|
|
|
it("does not clamp unfocused viewport shrink as keyboard", () => {
|
|
const offsets = computeIcbOffsets({
|
|
innerWidth: 390,
|
|
innerHeight: 844,
|
|
vvWidth: 390,
|
|
vvHeight: 760,
|
|
vvOffsetTop: 0,
|
|
vvOffsetLeft: 0,
|
|
vvScale: 1,
|
|
activeElementIsKeyboardFocusable: false,
|
|
baselineViewportHeight: 844,
|
|
});
|
|
|
|
expect(offsets.bottomOffset).toBe(84);
|
|
});
|
|
});
|