Hide Obsidian app header when the softkeyboard is open

Now deals with tablets and foldables better. The previous version didn’t hide the tab list when hiding the header.

JS

export async function invoke(app) {
	const duration = 250;
	document.body.style.setProperty('--headertransduration', `${duration}ms`);
	const capacitorapp = window.Capacitor?.Plugins?.App;
	let viewHeaderHeight = parseInt(window.getComputedStyle(document.body).getPropertyValue('--view-header-height'));
	let tabHeaderHeight = parseInt(window.getComputedStyle(document.body).getPropertyValue('--header-height'));
	let keyboardopen = false;
	let headerhidden = false;

	function adjustScroll(delta) {
	    const editor = app.workspace?.activeLeaf?.view?.editor;
	    if (!editor || app.workspace?.activeLeaf?.view?.file?.extension != 'md') return;

	    const scrollInfo = editor.getScrollInfo();
	    const start = scrollInfo.top;
	    const end = start + delta;
	    const startTime = performance.now();

	    function animate(time) {
	        const elapsed = time - startTime;
	        const progress = Math.min(elapsed / duration, 1);
	        const ease = progress < 0.5 
	            ? 2 * progress * progress 
	            : -1 + (4 - 2 * progress) * progress;

	        editor.scrollTo(scrollInfo.left, start + (end - start) * ease);

	        if (progress < 1) {
	            requestAnimationFrame(animate);
	        }
	    }

	    requestAnimationFrame(animate);
	}

	function hideHeader() {
		if (headerhidden || !document.activeElement.classList.contains('cm-content') || document.activeElement.closest('.metadata-property-value') || document.activeElement.closest('.metadata-property-key')) return;
		document.body.classList.add('hide-view-header');
		document.body.classList.contains('is-tablet') ? adjustScroll(-(viewHeaderHeight + tabHeaderHeight)) : adjustScroll(-viewHeaderHeight);
		headerhidden = true;
	}

	function showHeader() {
		if (!headerhidden) return;
		document.body.classList.remove('hide-view-header');
		document.body.classList.contains('is-tablet') ? adjustScroll(viewHeaderHeight + tabHeaderHeight) : adjustScroll(viewHeaderHeight);
		headerhidden = false;
	}

	function elementDefocused() {
		setTimeout(() => {
			if(!document.activeElement.onblur) document.activeElement.onblur = elementDefocused;
			if (keyboardopen) {
				if (document.activeElement.classList.contains('cm-content')) {
					hideHeader();
				} else if (!document.activeElement.closest('.metadata-property-value') && !document.activeElement.closest('.metadata-property-key')) {
					showHeader();
				}
			}
		}, 100);
	}

	if (capacitorapp?.addListener) {
		window.Capacitor?.Plugins?.Keyboard?.addListener('keyboardWillShow', () => {
			keyboardopen = true;
			hideHeader();
			if(!document.activeElement.onblur) document.activeElement.onblur = elementDefocused;
		});

		window.Capacitor?.Plugins?.Keyboard?.addListener('keyboardWillHide', () => {
			keyboardopen = false;
			showHeader();
		});
	}
}

CSS

body {
	--headertransduration: 0ms;
}

.workspace-leaf-content[data-type="markdown"] .view-header, .workspace-tab-header-container {
	transition: height var(--headertransduration), opacity var(--headertransduration);
}

body.hide-view-header .workspace-leaf-content[data-type="markdown"] .view-header, body.hide-view-header .workspace-tab-header-container {
	border-bottom: 0;
	height: 0;
    opacity: 0;
	overflow: hidden;
}