impress/app/assets/javascripts/wardrobe/item-card.js

71 lines
2.4 KiB
JavaScript
Raw Normal View History

/**
* ItemCard web component
*
* Progressive enhancement for item cards in both outfit and search views.
* Replaces baseline Show/Hide/Add buttons with click-to-toggle behavior:
*
* Outfit view (radio inputs):
* - 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
* - Space on a checked radio submits the Hide form (radios don't toggle natively)
*
* Search view (checkbox inputs):
* - Clicking an unworn item's label checks the checkbox and submits the Add form
* - Clicking a worn item's label prevents default and submits the Hide form
*/
class ItemCard extends HTMLElement {
connectedCallback() {
this.addEventListener("click", this.#handleClick);
this.addEventListener("keydown", this.#handleKeydown);
this.addEventListener("change", this.#handleChange);
}
#handleClick = (e) => {
const label = e.target.closest(".item-card-label");
if (!label) return;
const input = label.querySelector("input[type=radio], input[type=checkbox]");
if (!input) return;
// If this item is worn, un-wear it by submitting the Hide form
if (this.dataset.isWorn != null) {
e.preventDefault();
const hideButton = this.querySelector(".item-hide-button");
if (hideButton) hideButton.closest("form").requestSubmit();
}
// Otherwise, let the default label click proceed—it checks the input,
// which fires the `change` event handled below
};
#handleKeydown = (e) => {
// Spacebar on an already-checked radio: un-wear the item
if (e.key !== " ") return;
const input = e.target;
if (input.type !== "radio" || !input.checked) return;
if (this.dataset.isWorn == null) return;
e.preventDefault();
const hideButton = this.querySelector(".item-hide-button");
if (hideButton) hideButton.closest("form").requestSubmit();
};
#handleChange = (e) => {
const input = e.target;
if (!input.checked) return;
if (input.type !== "radio" && input.type !== "checkbox") return;
// Submit the Show form to wear this item, or the Add form if not closeted
const showButton = this.querySelector(".item-show-button");
if (showButton) {
showButton.closest("form").requestSubmit();
} else {
const addButton = this.querySelector(".item-add-button");
if (addButton) addButton.closest("form").requestSubmit();
}
};
}
customElements.define("item-card", ItemCard);