refactor(inset): the bottom-inset arithmetic becomes testable, and is tested

The measurement lived inside the view, where the only way to check it was to
run Obsidian on a phone. It moves to a pure `insetFor(leaf, bars, visible)`
against the numbers a phone reports - including the case the events hid: while
the keyboard is up the navbar is behind it, so the deeper of the two is the
inset and adding them would push the composer twice as far as it must go.
This commit is contained in:
hh committed 2026-09-05 00:49:54 +02:00
1 parent 413d68fc87
commit 70cf985aa1
3 files changed
+128 -20

No files matched your search

+14 -20
View File
@@ -1,6 +1,8 @@
import type { ViewStateResult, WorkspaceLeaf } from "obsidian";
import { ItemView, TFile } from "obsidian";
import { mount, unmount } from "svelte";
import type { Rect } from "./inset";
import { insetFor } from "./inset";
import type BeaverPlugin from "./main";
import { PanelState } from "./state.svelte";
import App from "./ui/app.svelte";
@@ -144,34 +146,26 @@ export class PanelView extends ItemView {
}
// Whatever floats over the bottom of this leaf, measured rather than
// guessed: the desktop status bar, the phone's navbar (which the workspace
// does not subtract from a leaf's height), and the software keyboard, which
// shrinks the visual viewport without resizing the layout at all. Returns
// the inset it wrote, so the settle loop can tell when it stops changing.
// guessed. Returns the inset it wrote, so the settle loop can tell when the
// reading stops changing; the arithmetic itself lives in ``inset.ts``.
private inset(): number {
const box = this.contentEl.getBoundingClientRect();
if (box.height <= 0) {
return Number.NaN;
}
let overlap = 0;
for (const bar of BOTTOM_BARS) {
const node = document.querySelector<HTMLElement>(bar);
if (!node || node.offsetParent === null) {
continue;
}
const b = node.getBoundingClientRect();
if (b.height > 0 && b.left < box.right && b.right > box.left) {
overlap = Math.max(overlap, box.bottom - b.top);
const bars: Rect[] = [];
for (const selector of BOTTOM_BARS) {
const node = document.querySelector<HTMLElement>(selector);
if (node && node.offsetParent !== null) {
bars.push(node.getBoundingClientRect());
}
}
const vv = window.visualViewport;
if (vv) {
// The keyboard eats the bottom of the window; anything of this leaf
// below that line is unreachable until it goes away.
const floor = vv.offsetTop + vv.height;
overlap = Math.max(overlap, box.bottom - floor);
}
const inset = Math.max(0, Math.round(overlap));
const inset = insetFor(
box,
bars,
vv ? { height: vv.height, offsetTop: vv.offsetTop } : null
);
this.contentEl.style.setProperty("--beaver-inset-bottom", `${inset}px`);
return inset;
}