[WV2] Extract species-color-picker component

This commit is contained in:
Emi Matchu 2025-11-02 08:17:06 +00:00
parent 2dc5505147
commit 14298fafa9
5 changed files with 86 additions and 23 deletions

View file

@ -24,24 +24,6 @@ document.addEventListener("turbo:frame-missing", (e) => {
e.preventDefault();
});
class SpeciesColorPicker extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
}
connectedCallback() {
// Listen for changes to auto-submit the form, then tell CSS about it!
this.addEventListener("change", this.#handleChange);
this.#internals.states.add("auto-loading");
}
#handleChange(e) {
this.querySelector("form").requestSubmit();
}
}
class SpeciesFacePicker extends HTMLElement {
connectedCallback() {
@ -109,7 +91,6 @@ class MeasuredContainer extends HTMLElement {
}
}
customElements.define("species-color-picker", SpeciesColorPicker);
customElements.define("species-face-picker", SpeciesFacePicker);
customElements.define("species-face-picker-options", SpeciesFacePickerOptions);
customElements.define("measured-container", MeasuredContainer);

View file

@ -0,0 +1,28 @@
/**
* SpeciesColorPicker web component
*
* Progressive enhancement for species/color picker forms:
* - Auto-submits the form when species or color changes (if JS is enabled)
* - Shows a submit button as fallback (if JS is disabled or slow to load)
* - Uses Custom Element internals API to communicate state to CSS
*/
class SpeciesColorPicker extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
}
connectedCallback() {
// Listen for changes to auto-submit the form, then tell CSS about it!
this.addEventListener("change", this.#handleChange);
this.#internals.states.add("auto-loading");
}
#handleChange(e) {
this.querySelector("form").requestSubmit();
}
}
customElements.define("species-color-picker", SpeciesColorPicker);

View file

@ -59,8 +59,6 @@ body.wardrobe-v2 {
transition: opacity 0.2s;
form {
display: flex;
gap: 0.5rem;
pointer-events: auto;
/* Re-enable clicks on the form itself */
}
@ -97,6 +95,51 @@ body.wardrobe-v2 {
color: white;
}
}
/* Submit button: progressive enhancement pattern */
/* If JS is disabled, the button is always visible */
/* If JS is enabled but slow to load, fade in after 0.75s */
/* Once the web component loads, hide the button completely */
input[type="submit"] {
padding: 0.5rem 1rem;
font-size: 1rem;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 0.375rem;
background: rgba(0, 0, 0, 0.7);
color: white;
cursor: pointer;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
&:hover {
background-color: rgba(0, 0, 0, 0.8);
border-color: rgba(255, 255, 255, 0.5);
}
&:focus {
outline: none;
border-color: rgba(255, 255, 255, 0.8);
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.1);
}
}
/* If JS is enabled, hide the submit button initially with a delay */
@media (scripting: enabled) {
input[type="submit"] {
position: absolute;
margin-left: 0.5em;
opacity: 0;
animation: fade-in 0.25s forwards;
animation-delay: 0.75s;
}
}
/* Once auto-loading is ready, hide the submit button completely */
&:state(auto-loading) {
input[type="submit"] {
display: none;
}
}
}
/* Show picker on hover (real hover only, not simulated touch hover) */
@ -169,4 +212,14 @@ body.wardrobe-v2 {
border-radius: 4px;
color: #333;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View file

@ -131,4 +131,5 @@
- content_for :javascripts do
= javascript_include_tag "idiomorph", async: true
= javascript_include_tag "outfit-viewer", async: true
= javascript_include_tag "species-color-picker", async: true
= javascript_include_tag "items/show", async: true

View file

@ -14,6 +14,7 @@
= javascript_include_tag "application", async: true
= javascript_include_tag "idiomorph", async: true
= javascript_include_tag "outfit-viewer", async: true
= javascript_include_tag "species-color-picker", async: true
= javascript_include_tag "outfits/new_v2", async: true
%body.wardrobe-v2
= turbo_frame_tag "outfit-editor" do
@ -32,13 +33,12 @@
= select_tag :color,
options_from_collection_for_select(@colors, "id", "human_name",
@selected_color&.id),
onchange: "this.form.requestSubmit()",
"aria-label": "Pet color"
= select_tag :species,
options_from_collection_for_select(@species, "id", "human_name",
@selected_species&.id),
onchange: "this.form.requestSubmit()",
"aria-label": "Pet species"
= submit_tag "Go", name: nil
-# Preserve item IDs in the URL
- if params[:objects].present?