From a90236ed6016ab317480e6e649061cb6df365e0a Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 10 Oct 2025 15:40:15 +0200 Subject: [PATCH] feat: enhance datalist component with unified input container and improved option handling --- .../views/components/forms/datalist.blade.php | 196 ++++++++---------- 1 file changed, 90 insertions(+), 106 deletions(-) diff --git a/resources/views/components/forms/datalist.blade.php b/resources/views/components/forms/datalist.blade.php index 8ce19773e..224ff82ab 100644 --- a/resources/views/components/forms/datalist.blade.php +++ b/resources/views/components/forms/datalist.blade.php @@ -19,7 +19,7 @@ selected: @entangle($id).live, options: [], filteredOptions: [], - + init() { this.options = Array.from(this.$refs.datalist.querySelectorAll('option')).map(opt => { // Try to parse as integer, fallback to string @@ -39,7 +39,7 @@ this.selected = []; } }, - + filterOptions() { if (!this.search) { this.filteredOptions = this.options; @@ -50,7 +50,7 @@ opt.text.toLowerCase().includes(searchLower) ); }, - + toggleOption(value) { // Ensure selected is an array if (!Array.isArray(this.selected)) { @@ -64,20 +64,24 @@ } this.search = ''; this.filterOptions(); + // Focus input after selection + this.$refs.searchInput.focus(); }, - - removeOption(value) { + + removeOption(value, event) { // Ensure selected is an array if (!Array.isArray(this.selected)) { this.selected = []; return; } + // Prevent triggering container click + event.stopPropagation(); const index = this.selected.indexOf(value); if (index > -1) { this.selected.splice(index, 1); } }, - + isSelected(value) { // Ensure selected is an array if (!Array.isArray(this.selected)) { @@ -85,113 +89,93 @@ } return this.selected.includes(value); }, - + getSelectedText(value) { const option = this.options.find(opt => opt.value == value); return option ? option.text : value; } - }" - @click.outside="open = false" - class="relative"> + }" @click.outside="open = false" class="relative"> - {{-- Selected Items Display --}} -
+ {{-- Unified Input Container with Tags Inside --}} +
+ + {{-- Selected Tags Inside Input --}} -
- - {{-- Search Input --}} - merge(['class' => $defaultClass]) }} - @required($required) - @readonly($readonly) - @disabled($disabled) - wire:dirty.class="dark:ring-warning ring-warning" - wire:loading.attr="disabled" - @if ($autofocus) x-ref="autofocusInput" @endif - > - - {{-- Dropdown Options --}} -
- - - -
- - {{-- Hidden datalist for options --}} - - {{ $slot }} - -
- @else - {{-- Single Selection Mode (Standard HTML5 Datalist) --}} - merge(['class' => $defaultClass]) }} - @required($required) - @readonly($readonly) - @disabled($disabled) - wire:dirty.class="dark:ring-warning ring-warning" - wire:loading.attr="disabled" - name="{{ $id }}" - @if ($value) value="{{ $value }}" @endif - @if ($placeholder) placeholder="{{ $placeholder }}" @endif - @if ($attributes->whereStartsWith('wire:model')->first()) - {{ $attributes->whereStartsWith('wire:model')->first() }} - @else - wire:model="{{ $id }}" - @endif - @if ($instantSave) - wire:change="{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}" - wire:blur="{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}" - @endif - @if ($autofocus) x-ref="autofocusInput" @endif - > - - {{ $slot }} - + {{-- Search Input (Borderless, Inside Container) --}} + - {{ $message }} - - @enderror + class="flex-1 min-w-[120px] text-sm border-0 outline-none bg-transparent p-0 focus:ring-0 placeholder:text-neutral-400 dark:placeholder:text-neutral-600" + /> + + +{{-- Dropdown Options --}} +
+ + + + +
+ +{{-- Hidden datalist for options --}} + + {{ $slot }} + + +@else +{{-- Single Selection Mode (Standard HTML5 Datalist) --}} +merge(['class' => $defaultClass]) }} @required($required) + @readonly($readonly) @disabled($disabled) wire:dirty.class="dark:ring-warning ring-warning" + wire:loading.attr="disabled" name="{{ $id }}" + @if ($value) value="{{ $value }}" @endif + @if ($placeholder) placeholder="{{ $placeholder }}" @endif + @if ($attributes->whereStartsWith('wire:model')->first()) {{ $attributes->whereStartsWith('wire:model')->first() }} + @else + wire:model="{{ $id }}" @endif + @if ($instantSave) wire:change="{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}" + wire:blur="{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}" @endif + @if ($autofocus) x-ref="autofocusInput" @endif> + + {{ $slot }} + +@endif + +@error($id) + +@enderror