fix: new session input stays open when clicking device select dropdown

blur handler on the name input was closing the entire new-session UI
when focus moved to the device select. Fixed: check if activeElement
is the sibling select before running cleanup. Same guard added to the
select's blur handler (check if focus returned to input).

Also adds Escape keydown handler on the select to allow cancelling
without returning focus to the input first.

Applied to both showNewSessionInput() and showFabSessionInput().
This commit is contained in:
Brian Krabach
2026-04-04 19:33:05 -07:00
parent 33b2d52af8
commit 7fb803c6b5
2 changed files with 73 additions and 3 deletions
+36 -2
View File
@@ -1976,9 +1976,26 @@ function showNewSessionInput(btn) {
}); });
input.addEventListener('blur', function() { input.addEventListener('blur', function() {
setTimeout(cleanup, 150); setTimeout(function() {
// Don't close if focus moved to the device select dropdown
if (select && document.activeElement === select) return;
cleanup();
}, 150);
}); });
if (select) {
select.addEventListener('blur', function() {
setTimeout(function() {
// Don't close if focus moved back to the name input
if (document.activeElement === input) return;
cleanup();
}, 150);
});
select.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { cleanup(); }
});
}
btn.style.display = 'none'; btn.style.display = 'none';
if (select) btn.parentNode.insertBefore(select, btn); if (select) btn.parentNode.insertBefore(select, btn);
btn.parentNode.insertBefore(input, btn); btn.parentNode.insertBefore(input, btn);
@@ -2022,9 +2039,26 @@ function showFabSessionInput() {
}); });
input.addEventListener('blur', function() { input.addEventListener('blur', function() {
setTimeout(cleanup, 150); setTimeout(function() {
// Don't close if focus moved to the device select dropdown
if (select && document.activeElement === select) return;
cleanup();
}, 150);
}); });
if (select) {
select.addEventListener('blur', function() {
setTimeout(function() {
// Don't close if focus moved back to the name input
if (document.activeElement === input) return;
cleanup();
}, 150);
});
select.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { cleanup(); }
});
}
if (fab) fab.style.display = 'none'; if (fab) fab.style.display = 'none';
document.body.appendChild(overlay); document.body.appendChild(overlay);
input.focus(); input.focus();
+36
View File
@@ -4299,3 +4299,39 @@ test('CSS has new-session-device-select styling', () => {
'style.css must have .new-session-device-select rule', 'style.css must have .new-session-device-select rule',
); );
}); });
// --- Fix: blur handler guards against closing when clicking device select ---
test('showNewSessionInput blur does not close when clicking device select', () => {
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
// Find the blur handler in showNewSessionInput
const fnStart = source.indexOf('function showNewSessionInput');
const fnBody = source.substring(fnStart, fnStart + 2000);
// Must check activeElement before cleanup
assert.ok(fnBody.includes('activeElement'), 'blur handler must check activeElement before cleanup');
});
test('showFabSessionInput blur does not close when clicking device select', () => {
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
const fnStart = source.indexOf('function showFabSessionInput');
const fnBody = source.substring(fnStart, fnStart + 2000);
assert.ok(fnBody.includes('activeElement'), 'FAB blur handler must check activeElement before cleanup');
});
test('showNewSessionInput device select has blur handler that guards against closing when focus returns to input', () => {
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
const fnStart = source.indexOf('function showNewSessionInput');
const fnBody = source.substring(fnStart, fnStart + 2000);
// The select element should also have a blur handler
// We check that there's a blur listener added to the select element
const selectBlurIdx = fnBody.indexOf("select.addEventListener('blur'");
assert.ok(selectBlurIdx !== -1, 'select element must have a blur handler in showNewSessionInput');
});
test('showNewSessionInput device select has keydown handler for Escape', () => {
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
const fnStart = source.indexOf('function showNewSessionInput');
const fnBody = source.substring(fnStart, fnStart + 2000);
const selectKeydownIdx = fnBody.indexOf("select.addEventListener('keydown'");
assert.ok(selectKeydownIdx !== -1, 'select element must have a keydown handler in showNewSessionInput');
});