/** * 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);