Focus fix for tabs and window

This commit is contained in:
Andy Dixon
2026-04-24 15:16:18 +01:00
parent 9577b829a0
commit 5699d17fb6
3 changed files with 44 additions and 17 deletions
+16
View File
@@ -519,6 +519,12 @@
this.splitPanes.refitAll(); this.splitPanes.refitAll();
}, 100), }, 100),
); );
window.addEventListener("focus", () => {
requestAnimationFrame(() => {
this._focusVisibleTerminal();
});
});
} }
// ── Split pane ───────────────────────────────────────────────── // ── Split pane ─────────────────────────────────────────────────
@@ -1214,6 +1220,16 @@
} }
} }
/**
* Focuses the currently visible xterm instance if one is active.
* @private
*/
_focusVisibleTerminal() {
const sessionId = this.state.activeSessionId;
if (!sessionId) return;
this.terminals.focusTerminal(sessionId);
}
/** /**
* Shows a simple text-input prompt modal (replaces window.prompt which * Shows a simple text-input prompt modal (replaces window.prompt which
* is unavailable in WKWebView). * is unavailable in WKWebView).
+25 -17
View File
@@ -984,7 +984,6 @@
* Renders a collapsible form section. * Renders a collapsible form section.
* @param {string} title * @param {string} title
* @param {HTMLElement[]} fields * @param {HTMLElement[]} fields
* @param {boolean} [startCollapsed=false]
* @returns {HTMLElement} * @returns {HTMLElement}
* @private * @private
*/ */
@@ -997,15 +996,14 @@
_renderTOTPSection(profile) { _renderTOTPSection(profile) {
const section = createElement("div", "form-section"); const section = createElement("div", "form-section");
const header = createElement("div", "form-section-header"); const header = createElement("div", "form-section-header");
let collapsed = true; let collapsed = false;
header.innerHTML = ` header.innerHTML = `
<span class="form-section-chevron">▸</span> <span class="form-section-chevron">▾</span>
<span class="form-section-title">TOTP / 2FA</span> <span class="form-section-title">TOTP / 2FA</span>
`; `;
const content = createElement("div", "form-section-content"); const content = createElement("div", "form-section-content");
content.style.display = "none";
const helpText = createElement("div", "form-help", { const helpText = createElement("div", "form-help", {
textContent: textContent:
@@ -1178,13 +1176,17 @@
})(); })();
} }
header.addEventListener("mousedown", (e) => e.preventDefault()); const toggleSection = () => {
header.addEventListener("click", () => {
collapsed = !collapsed; collapsed = !collapsed;
content.style.display = collapsed ? "none" : "block"; content.style.display = collapsed ? "none" : "block";
header.querySelector(".form-section-chevron").textContent = collapsed header.querySelector(".form-section-chevron").textContent = collapsed
? "▸" ? "▸"
: "▾"; : "▾";
};
header.addEventListener("mousedown", (e) => {
if (e.button !== 0) return;
e.preventDefault();
toggleSection();
}); });
section.appendChild(header); section.appendChild(header);
@@ -1202,15 +1204,14 @@
_renderLoginScriptSection(prefix, steps) { _renderLoginScriptSection(prefix, steps) {
const section = createElement("div", "form-section"); const section = createElement("div", "form-section");
const header = createElement("div", "form-section-header"); const header = createElement("div", "form-section-header");
let collapsed = true; let collapsed = false;
header.innerHTML = ` header.innerHTML = `
<span class="form-section-chevron">▸</span> <span class="form-section-chevron">▾</span>
<span class="form-section-title">Login Script</span> <span class="form-section-title">Login Script</span>
`; `;
const content = createElement("div", "form-section-content"); const content = createElement("div", "form-section-content");
content.style.display = "none";
const helpText = createElement("div", "form-help", { const helpText = createElement("div", "form-help", {
textContent: textContent:
@@ -1396,13 +1397,17 @@
addRow.appendChild(addSendBtn); addRow.appendChild(addSendBtn);
content.appendChild(addRow); content.appendChild(addRow);
header.addEventListener("mousedown", (e) => e.preventDefault()); const toggleSection = () => {
header.addEventListener("click", () => {
collapsed = !collapsed; collapsed = !collapsed;
content.style.display = collapsed ? "none" : "block"; content.style.display = collapsed ? "none" : "block";
header.querySelector(".form-section-chevron").textContent = collapsed header.querySelector(".form-section-chevron").textContent = collapsed
? "▸" ? "▸"
: "▾"; : "▾";
};
header.addEventListener("mousedown", (e) => {
if (e.button !== 0) return;
e.preventDefault();
toggleSection();
}); });
section.appendChild(header); section.appendChild(header);
@@ -1410,10 +1415,10 @@
return section; return section;
} }
_renderSection(title, fields, startCollapsed = false) { _renderSection(title, fields) {
const section = createElement("div", "form-section"); const section = createElement("div", "form-section");
const header = createElement("div", "form-section-header"); const header = createElement("div", "form-section-header");
let collapsed = startCollapsed; let collapsed = false;
header.innerHTML = ` header.innerHTML = `
<span class="form-section-chevron">${collapsed ? "▸" : "▾"}</span> <span class="form-section-chevron">${collapsed ? "▸" : "▾"}</span>
@@ -1429,15 +1434,18 @@
} }
} }
// Prevent mousedown from starting a text selection gesture in WKWebView, const toggleSection = () => {
// which would swallow the first click and require a double-click.
header.addEventListener("mousedown", (e) => e.preventDefault());
header.addEventListener("click", () => {
collapsed = !collapsed; collapsed = !collapsed;
content.style.display = collapsed ? "none" : "block"; content.style.display = collapsed ? "none" : "block";
header.querySelector(".form-section-chevron").textContent = collapsed header.querySelector(".form-section-chevron").textContent = collapsed
? "▸" ? "▸"
: "▾"; : "▾";
};
// Handle toggle on mousedown to avoid first-click swallowing in WKWebView.
header.addEventListener("mousedown", (e) => {
if (e.button !== 0) return;
e.preventDefault();
toggleSection();
}); });
section.appendChild(header); section.appendChild(header);
+3
View File
@@ -118,6 +118,9 @@
// Fit the terminal for the newly active session // Fit the terminal for the newly active session
this.app.terminals.fitActive(); this.app.terminals.fitActive();
requestAnimationFrame(() => {
this.app.terminals.focusTerminal(sessionId);
});
} }
/** /**