impress/app/assets/javascripts/wardrobe/zone-item-group.js

69 lines
2.3 KiB
JavaScript
Raw Normal View History

/**
* ZoneItemGroup web component
*
* Progressive enhancement for zone-grouped item cards in the outfit view.
* Replaces baseline Show/Hide buttons with radio-button behavior:
* - Clicking a closeted item's label selects its radio and submits the Show form
* - Clicking a worn item's label submits the Hide form (un-wears it)
* - Arrow keys navigate between items via native radio behavior, triggering
* a `change` event that submits the newly-selected item's Show form
*/
class ZoneItemGroup extends HTMLElement {
connectedCallback() {
this.addEventListener("click", this.#handleClick);
this.addEventListener("keydown", this.#handleKeydown);
this.addEventListener("change", this.#handleChange);
}
#handleClick = (e) => {
// Only handle clicks on labels (the item card click target)
const label = e.target.closest(".item-card-label");
if (!label) return;
const radio = label.querySelector("input[type=radio]");
if (!radio) return;
const card = label.closest(".item-card");
if (!card) return;
// If this item is worn (radio was already checked), un-wear it
if (card.dataset.isWorn != null) {
// Prevent the default label behavior (which would keep radio checked)
e.preventDefault();
const hideButton = card.querySelector(".item-hide-button");
if (hideButton) hideButton.closest("form").requestSubmit();
}
// If closeted, let the default label click proceed—it checks the radio,
// which fires the `change` event handled below
};
#handleKeydown = (e) => {
// Spacebar on an already-checked radio: un-wear the item
if (e.key !== " ") return;
const radio = e.target;
if (radio.type !== "radio" || !radio.checked) return;
const card = radio.closest(".item-card");
if (!card || card.dataset.isWorn == null) return;
e.preventDefault();
const hideButton = card.querySelector(".item-hide-button");
if (hideButton) hideButton.closest("form").requestSubmit();
};
#handleChange = (e) => {
const radio = e.target;
if (radio.type !== "radio" || !radio.checked) return;
const card = radio.closest(".item-card");
if (!card) return;
// Submit the Show form to wear this item
const showButton = card.querySelector(".item-show-button");
if (showButton) showButton.closest("form").requestSubmit();
};
}
customElements.define("zone-item-group", ZoneItemGroup);