1import { Controller } from "@hotwired/stimulus"; 2 3// Shoelace Color Picker Controller 4// 5// Keeps a value display and optional hidden form input in sync with <sl-color-picker>. 6// Also supports optional custom swatch buttons. 7export default class extends Controller { 8 static targets = ["picker", "value", "input", "swatch"]; 9 10 static values = { 11 defaultValue: { type: String, default: "#3b82f6" }, 12 }; 13 14 connect() { 15 this.sync(this.currentColor()); 16 } 17 18 change(event) { 19 const color = event.target.value; 20 this.sync(color); 21 this.dispatchChangeEvent(color); 22 } 23 24 selectSwatch(event) { 25 event.preventDefault(); 26 const color = event.currentTarget.dataset.color; 27 28 if (!color || !this.hasPickerTarget) { 29 return; 30 } 31 32 this.pickerTarget.value = color; 33 this.sync(color); 34 this.dispatchChangeEvent(color); 35 } 36 37 currentColor() { 38 if (this.hasPickerTarget && this.pickerTarget.value) { 39 return this.pickerTarget.value; 40 } 41 42 return this.defaultValueValue; 43 } 44 45 sync(color) { 46 const nextColor = color || this.defaultValueValue; 47 48 if (this.hasPickerTarget && this.pickerTarget.value !== nextColor) { 49 this.pickerTarget.value = nextColor; 50 } 51 52 if (this.hasValueTarget) { 53 this.valueTarget.textContent = nextColor; 54 } 55 56 if (this.hasInputTarget) { 57 this.inputTarget.value = nextColor; 58 } 59 60 this.updateSwatchSelection(nextColor); 61 } 62 63 updateSwatchSelection(selectedColor) { 64 const normalized = (selectedColor || "").toLowerCase(); 65 66 this.swatchTargets.forEach((swatch) => { 67 const swatchColor = (swatch.dataset.color || "").toLowerCase(); 68 const isSelected = swatchColor === normalized; 69 70 swatch.setAttribute("aria-pressed", isSelected ? "true" : "false"); 71 swatch.classList.toggle("ring-neutral-500", isSelected); 72 swatch.classList.toggle("dark:ring-neutral-400", isSelected); 73 swatch.classList.toggle("ring-transparent", !isSelected); 74 }); 75 } 76 77 dispatchChangeEvent(color) { 78 const event = new CustomEvent("color-picker:change", { 79 bubbles: true, 80 detail: { color }, 81 }); 82 83 this.element.dispatchEvent(event); 84 } 85};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.