prime8dev

prime8dev
git clone https://git.prime8.dev/prime8dev.git
Log | Files | Refs | README | LICENSE

commit 04bfb55d386b04013e063f2d9f2e76ef417f8c73
parent 49fc72b24e0abea8f6dfd1c8756b118150562963
Author: Damian Myrda <damian@prime8.dev>
Date:   Fri, 23 Oct 2026 07:24:19 +0000

web shell: stop auto-grabbing focus; empty prompt hands digits/tab to tab switching

Diffstat:
Minternal/web/scripts/modules/shell.js | 29+++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/internal/web/scripts/modules/shell.js b/internal/web/scripts/modules/shell.js @@ -688,6 +688,18 @@ export function initShell() { } } + // An empty prompt doesn't own the page shortcuts: digits and tab give + // focus back and switch tabs, so the terminal never eats navigation. + // Once something is typed they're plain input and completion again. + if (input.value === "" && !busy && !e.ctrlKey && !e.metaKey && !e.altKey && + (/^[1-9]$/.test(e.key) || e.key === "Tab")) { + e.preventDefault(); + e.stopPropagation(); + input.blur(); + document.dispatchEvent(new KeyboardEvent("keydown", { key: e.key, shiftKey: e.shiftKey, bubbles: true, cancelable: true })); + return; + } + switch (e.key) { case "Enter": { e.preventDefault(); @@ -777,10 +789,10 @@ export function initShell() { if (!load(LOGIN_KEY)) store(LOGIN_KEY, String(Date.now())); render(); - // A terminal is focused whenever nothing else wants the keyboard: on load, - // on every switch back to about, when the window regains focus, and on a - // click anywhere that isn't a link, a control or a text selection. Touch - // screens are skipped, since focus pops the on-screen keyboard. + // The prompt takes focus only when asked: typing a letter (above) or a + // click inside the terminal. It is never grabbed on load, on a tab switch + // or on window focus, so the page shortcuts keep the keyboard by default. + // Touch screens are skipped, since focus pops the on-screen keyboard. const finePointer = window.matchMedia("(pointer: fine)").matches; const focusPrompt = () => { if (!section.isConnected || live.hidden || !finePointer) return; @@ -796,16 +808,13 @@ export function initShell() { } shellHandlers.click = (e) => { if (!section.isConnected || e.button !== 0) return; + if (!section.contains(e.target)) return; if (e.target.closest?.("a, button, input, textarea, select, label, summary, [tabindex], #help-overlay")) return; if (String(window.getSelection?.() || "")) return; if (window.isLightboxOpen?.()) return; focusPrompt(); }; - shellHandlers.winFocus = () => setTimeout(focusPrompt, 0); - shellHandlers.revealed = focusPrompt; + shellHandlers.winFocus = null; + shellHandlers.revealed = null; document.addEventListener("click", shellHandlers.click); - window.addEventListener("focus", shellHandlers.winFocus); - document.addEventListener("reveal:done", shellHandlers.revealed); - - focusPrompt(); }