1/** 2 * @class CheckboxSelectController 3 * @extends Controller 4 * @description 5 * Applies visual styling to checkbox select groups. Highlights selected 6 * options with a blue border and background, and provides select all / 7 * deselect all functionality. 8 * 9 * Features: 10 * - Visual feedback for checked/unchecked options 11 * - Automatic styling on initial load 12 * - Updates styling when selection changes 13 * - Select All / Deselect All support 14 * 15 * @example <caption>Styled checkbox select group</caption> 16 * <div data-controller="checkbox-select"> 17 * <label> 18 * <input type="checkbox" name="user[role_ids][]" value="1" 19 * data-checkbox-select-target="checkbox" 20 * data-action="change->checkbox-select#toggle" 21 * class="sr-only"> 22 * <div data-checkbox-select-target="option" class="border border-warm-400 bg-white p-4 group"> 23 * Admin 24 * </div> 25 * </label> 26 * 27 * <label> 28 * <input type="checkbox" name="user[role_ids][]" value="2" 29 * data-checkbox-select-target="checkbox" 30 * data-action="change->checkbox-select#toggle" 31 * class="sr-only"> 32 * <div data-checkbox-select-target="option" class="border border-warm-400 bg-white p-4 group"> 33 * User 34 * </div> 35 * </label> 36 * 37 * <a href="#" data-action="checkbox-select#selectAll">Select All</a> 38 * <a href="#" data-action="checkbox-select#deselectAll">Deselect All</a> 39 * </div> 40 */ 41import { Controller } from "@hotwired/stimulus"; 42 43/** 44 * CSS classes applied when checkbox option is checked. 45 * @constant {string[]} 46 */ 47const CHECKED_CLASSES = ["is-checked", "border-blue-300", "bg-blue-100", "border-[1.5px]"] 48 49/** 50 * CSS classes applied when checkbox option is unchecked. 51 * @constant {string[]} 52 */ 53const UNCHECKED_CLASSES = ["border-warm-400", "bg-white"] 54 55export default class CheckboxSelectController extends Controller { 56 /** 57 * Stimulus targets for this controller. 58 * @static 59 * @property {string[]} targets 60 * @property {HTMLInputElement[]} checkboxTargets - The checkbox input elements 61 * @property {HTMLElement[]} optionTargets - The wrapper elements that receive styling 62 */ 63 static targets = ["checkbox", "option"]; 64 65 /** 66 * Applies initial styling based on current checked states. 67 * Called automatically when the controller connects to the DOM. 68 * 69 * @method connect 70 * @returns {void} 71 */ 72 connect() { 73 this.updateStyles(); 74 } 75 76 /** 77 * Updates styles for all options based on their checked state. 78 * 79 * @method updateStyles 80 * @private 81 * @returns {void} 82 */ 83 updateStyles() { 84 this.checkboxTargets.forEach((checkbox, index) => { 85 const option = this.optionTargets[index]; 86 if (checkbox.checked) { 87 option.classList.add(...CHECKED_CLASSES) 88 option.classList.remove(...UNCHECKED_CLASSES) 89 } else { 90 option.classList.remove(...CHECKED_CLASSES) 91 option.classList.add(...UNCHECKED_CLASSES) 92 } 93 }); 94 } 95 96 /** 97 * Handles checkbox toggle and updates styles. 98 * 99 * @method toggle 100 * @param {Event} event - The change event from the checkbox input 101 * @returns {void} 102 * 103 * @example 104 * <input type="checkbox" data-action="change->checkbox-select#toggle"> 105 */ 106 toggle(event) { 107 this.updateStyles(); 108 } 109 110 /** 111 * Checks all checkboxes and updates styles. 112 * 113 * @method selectAll 114 * @param {Event} event - The click event 115 * @returns {void} 116 * 117 * @example 118 * <a href="#" data-action="checkbox-select#selectAll">Select All</a> 119 */ 120 selectAll(event) { 121 event.preventDefault(); 122 this.checkboxTargets.forEach((checkbox) => { 123 checkbox.checked = true; 124 }); 125 this.updateStyles(); 126 } 127 128 /** 129 * Unchecks all checkboxes and updates styles. 130 * 131 * @method deselectAll 132 * @param {Event} event - The click event 133 * @returns {void} 134 * 135 * @example 136 * <a href="#" data-action="checkbox-select#deselectAll">Deselect All</a> 137 */ 138 deselectAll(event) { 139 event.preventDefault(); 140 this.checkboxTargets.forEach((checkbox) => { 141 checkbox.checked = false; 142 }); 143 this.updateStyles(); 144 } 145}
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.