@props([ 'name', 'id' => null, 'selected' => '', 'options' => [], 'required' => false, 'disabled' => false, 'compact' => false, ]) @php $id = $id ?? $name; $normalized = []; foreach ($options as $row) { if (! is_array($row)) { continue; } $normalized[] = [ 'value' => (string) ($row['value'] ?? ''), 'label' => (string) ($row['label'] ?? ''), 'disabled' => (bool) ($row['disabled'] ?? false), ]; } $selectedStr = (string) $selected; $isCompact = (bool) $compact; @endphp
merge([ 'class' => $isCompact ? 'relative w-max max-w-full overflow-visible' : 'relative min-w-0 overflow-visible', ]) }} x-data="{ open: false, selected: @js($selectedStr), options: @js($normalized), disabled: @js((bool) $disabled), init() { this.$refs.hidden.addEventListener('styled-select:set', (event) => { this.setValue(event.detail ?? ''); }); this.$refs.hidden.addEventListener('styled-select:set-options', (event) => { this.setOptions(event.detail ?? []); }); this.$refs.hidden.addEventListener('styled-select:set-disabled', (event) => { this.setDisabled(event.detail ?? false); }); }, normalizeOptions(rows) { if (!Array.isArray(rows)) { return []; } return rows.map((row) => ({ value: String(row?.value ?? ''), label: String(row?.label ?? ''), disabled: Boolean(row?.disabled ?? false), })); }, setOptions(rows) { this.close(); this.options = this.normalizeOptions(rows); const stillValid = this.options.some((o) => String(o.value) === String(this.selected)); if (!stillValid) { this.selected = ''; this.$nextTick(() => this.emitChange()); } }, setDisabled(value) { this.disabled = Boolean(value); this.close(); this.$refs.hidden.disabled = this.disabled; }, toggle() { if (this.disabled) return; this.open = !this.open; }, close() { this.open = false; }, emitChange() { this.$refs.hidden.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: String(this.selected) }, })); }, choose(opt) { if (opt.disabled) return; this.selected = String(opt.value); this.open = false; this.$nextTick(() => this.emitChange()); }, setValue(value) { const next = String(value ?? ''); const opt = this.options.find((o) => String(o.value) === next); if (opt) { this.choose(opt); return; } this.selected = next; this.close(); this.$nextTick(() => this.emitChange()); }, currentLabel() { const v = String(this.selected); const hit = this.options.find((o) => String(o.value) === v); return hit ? hit.label : '\u2014'; }, isSelected(opt) { return String(this.selected) === String(opt.value); }, }" @keydown.escape.window="close()" @click.outside="close()" >
$isCompact, 'w-full' => ! $isCompact, ]) style="display: none;" >
$isCompact, 'max-h-60 w-full overflow-auto py-1' => ! $isCompact, ]) role="listbox" :id="'{{ $id }}_listbox'" >