1/** 2 * RadioSelectTile - general-purpose tile group of selectable radio options. 3 * 4 * Configure with setTiles() after connection. Each tile descriptor: 5 * { value: string, icon: string (SVG HTML), label: string, sublabel?: string, badge?: string (HTML) } 6 * 7 * Fires `selection-changed` (bubbles, composed) on tile click. 8 * detail: { value: string } 9 * 10 * Methods: 11 * setTiles(tiles) configure and render tiles 12 * reset() clear selection 13 * getValue() return selected value, or '' 14 * 15 * Usage: 16 * <radio-select-tile id="my-selector"></radio-select-tile> 17 * el.setTiles([{ value: 'a', icon: '<svg>...</svg>', label: 'Option A', sublabel: 'Details' }]); 18 * el.addEventListener('selection-changed', e => console.log(e.detail.value)); 19 */ 20 21import { WebComponent } from '/js/Components/Base/WebComponent.js'; 22 23class RadioSelectTile extends WebComponent { 24 25 constructor() { 26 super(); 27 28 const cssLink = document.createElement('link'); 29 cssLink.rel = 'stylesheet'; 30 cssLink.href = '/css/user/two-factor-modal.css'; 31 this.shadowRoot.appendChild(cssLink); 32 33 const solidLink = document.createElement('link'); 34 solidLink.rel = 'stylesheet'; 35 solidLink.href = '/public/font-proxy.php?set=solid'; 36 this.shadowRoot.appendChild(solidLink); 37 38 this._selected = ''; 39 this._tiles = []; 40 this._group = document.createElement('div'); 41 this._group.className = 'mfa-radio-group'; 42 this.shadowRoot.appendChild(this._group); 43 } 44 45 connectedCallback() { 46 this._group.addEventListener('click', e => { 47 const tile = e.target.closest('.mfa-radio-tile'); 48 if (!tile) return; 49 this._group.querySelectorAll('.mfa-radio-tile').forEach(t => t.classList.remove('selected')); 50 tile.classList.add('selected'); 51 tile.querySelector('input[type="radio"]').checked = true; 52 this._selected = tile.querySelector('input[type="radio"]').value; 53 this.dispatchEvent(new CustomEvent('selection-changed', { 54 bubbles: true, 55 composed: true, 56 detail: { value: this._selected }, 57 })); 58 }); 59 } 60 61 render() {} 62 63 setTiles(tiles) { 64 this._tiles = tiles; 65 this._group.innerHTML = tiles.map(t => ` 66 <label class="mfa-radio-tile"> 67 <input type="radio" name="radio-select-tile" value="${t.value}" /> 68 ${t.icon ? `<div class="mfa-tile-icon">${t.icon}</div>` : ''} 69 <div class="mfa-tile-body"> 70 <div class="mfa-tile-label"> 71 ${t.label} 72 ${t.badge ? `<span class="mfa-badge">${t.badge}</span>` : ''} 73 </div> 74 ${t.sublabel ? `<div class="mfa-tile-sublabel">${t.sublabel}</div>` : ''} 75 </div> 76 </label> 77 `).join(''); 78 } 79 80 reset() { 81 this._selected = ''; 82 this._group.querySelectorAll('input[type="radio"]').forEach(r => r.checked = false); 83 this._group.querySelectorAll('.mfa-radio-tile').forEach(t => t.classList.remove('selected')); 84 } 85 86 getValue() { 87 return this._selected; 88 } 89} 90 91if (!customElements.get('radio-select-tile')) { 92 customElements.define('radio-select-tile', RadioSelectTile); 93}
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.