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 --}}
-
-
-
-
- No options found
-
+
-
-
-
-
-
-
-
-
- {{-- Hidden datalist for options --}}
-
-
- @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
- >
-
+ {{-- 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 --}}
+
+
+
+
+ No options found
+
+
+
+
+
+
+
+
+
+
+
+{{-- Hidden datalist for options --}}
+
+
+@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>
+
+@endif
+
+@error($id)
+
+@enderror