fix(view): follow the keyboard through the navbar hiding behind it
Same two misses as the calendar's: the four-frame watch stopped before Obsidian hid its navbar - a second move of the ground, after the keyboard's own - and a trigger that arrived while a watch was running was dropped rather than restarting it. The watch now needs twelve steady frames, restarts on every trigger, and listens to Obsidian's Capacitor keyboard events too.
This commit is contained in:
+25
-6
@@ -13,9 +13,18 @@ export const VIEW_TYPE_PANEL = "beaver-panel";
|
||||
// sits under every view, including the one filling the screen.
|
||||
const BOTTOM_BARS = [".status-bar", ".mobile-navbar", ".mobile-toolbar"];
|
||||
|
||||
// The keyboard and the navbar both animate. Rather than guess how long that
|
||||
// takes, the inset is re-measured every frame until the reading holds still.
|
||||
const STEADY_FRAMES = 4;
|
||||
// The keyboard and the navbar both animate, and Obsidian hides the navbar
|
||||
// *after* the keyboard is up: the inset is re-measured every frame until the
|
||||
// reading has held still long enough to outlast both moves.
|
||||
const STEADY_FRAMES = 12;
|
||||
|
||||
/** Obsidian's Capacitor keyboard events on mobile; absent on the desktop. */
|
||||
const KEYBOARD_EVENTS = [
|
||||
"keyboardWillShow",
|
||||
"keyboardDidShow",
|
||||
"keyboardWillHide",
|
||||
"keyboardDidHide",
|
||||
] as const;
|
||||
|
||||
interface SavedState {
|
||||
follow?: unknown;
|
||||
@@ -106,6 +115,14 @@ export class PanelView extends ItemView {
|
||||
// out the navbar comes back, so the leaf has to be re-measured after.
|
||||
this.registerDomEvent(this.contentEl, "focusin", () => this.settle());
|
||||
this.registerDomEvent(this.contentEl, "focusout", () => this.settle());
|
||||
// Obsidian's own keyboard events (Capacitor, mobile only) fire before the
|
||||
// animation and again as the navbar returns, which visualViewport alone
|
||||
// does not always report.
|
||||
for (const name of KEYBOARD_EVENTS) {
|
||||
const onKeyboard = () => this.settle();
|
||||
window.addEventListener(name, onKeyboard);
|
||||
this.register(() => window.removeEventListener(name, onKeyboard));
|
||||
}
|
||||
this.follow(this.app.workspace.getActiveFile());
|
||||
this.plugin.views.add(this);
|
||||
this.mountApp();
|
||||
@@ -121,11 +138,13 @@ export class PanelView extends ItemView {
|
||||
* which is the case in a sidedock drawer.
|
||||
*/
|
||||
private settle(): void {
|
||||
if (this.settling !== null) {
|
||||
return;
|
||||
}
|
||||
let last = Number.NaN;
|
||||
let steady = 0;
|
||||
// A fresh trigger restarts the watch rather than being dropped: the navbar
|
||||
// coming back is a second move, after the first one has settled.
|
||||
if (this.settling !== null) {
|
||||
cancelAnimationFrame(this.settling);
|
||||
}
|
||||
const tick = () => {
|
||||
const floor = this.inset();
|
||||
steady = floor === last ? steady + 1 : 0;
|
||||
|
||||
Reference in New Issue
Block a user