[WV2] Add search keyboard shortcuts

This commit is contained in:
Emi Matchu 2026-02-06 17:20:10 -08:00
parent 10e2140045
commit b462272dc3
2 changed files with 62 additions and 0 deletions

View file

@ -0,0 +1,61 @@
/**
* Keyboard shortcuts for item search.
*
* - Up/Down arrows move focus between the search field and the item list,
* so keyboard users can quickly browse results without tabbing.
* - Escape exits search mode (clicks the back button).
*/
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
const backButton = document.querySelector(
".item-search-form .back-button",
);
if (!backButton) return;
// Only act when focus is on the search input or a search result.
const section = document.querySelector(".outfit-controls-section");
const searchInput = section?.querySelector(
'.search-form input[type="text"]',
);
const isSearchFocused =
document.activeElement === searchInput ||
document.activeElement?.closest(".search-results-list") != null;
if (!isSearchFocused) return;
e.preventDefault();
backButton.click();
return;
}
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
const section = document.querySelector(".outfit-controls-section");
if (!section) return;
const searchInput = section.querySelector('.search-form input[type="text"]');
if (!searchInput) return;
// Collect all focusable item inputs in the results list.
const itemInputs = [
...section.querySelectorAll(
'.search-results-list item-card input[type="checkbox"]',
),
];
if (itemInputs.length === 0) return;
const allTargets = [searchInput, ...itemInputs];
const currentIndex = allTargets.indexOf(document.activeElement);
if (currentIndex === -1) return;
let nextIndex;
if (e.key === "ArrowDown") {
nextIndex = Math.min(currentIndex + 1, allTargets.length - 1);
} else {
nextIndex = Math.max(currentIndex - 1, 0);
}
if (nextIndex !== currentIndex) {
e.preventDefault();
allTargets[nextIndex].focus();
}
});

View file

@ -18,6 +18,7 @@
= javascript_include_tag "tab-panel", async: true
= javascript_include_tag "outfit-rename-field", async: true
= javascript_include_tag "wardrobe/item-card", async: true
= javascript_include_tag "wardrobe/item-search-keys", async: true
= javascript_include_tag "wardrobe/show", async: true
= csrf_meta_tags
%meta{name: 'outfit-viewer-morph-mode', value: 'full-page'}