|
17 | 17 | <div class="flex gap-1 items-center" @click.stop> |
18 | 18 | <!-- Select all items --> |
19 | 19 | <button @click="selectAll()" x-show="open" type="button" |
| 20 | + :id="id + '-all'" |
20 | 21 | class="text-[10px] px-2 py-0.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-200 rounded"> |
21 | 22 | <span x-text="$store.labels.getLabel('common','all')">All</span> |
22 | 23 | </button> |
23 | 24 |
|
24 | 25 | <!-- Clear all selections --> |
25 | 26 | <button @click="clearAll()" x-show="open" type="button" |
| 27 | + :id="id + '-none'" |
26 | 28 | class="text-[10px] px-2 py-0.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-200 rounded"> |
27 | 29 | <span x-text="$store.labels.getLabel('common','none')">None</span> |
28 | 30 | </button> |
|
32 | 34 | <!-- Dropdown content, teleported to <body> to avoid overflow clipping --> |
33 | 35 | <template x-teleport="body"> |
34 | 36 | <div x-show="open" |
35 | | - @click.outside="open = false" |
36 | 37 | x-transition |
37 | 38 | class="absolute rounded-md border shadow-lg z-50 |
38 | 39 | dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 |
39 | 40 | bg-white border-slate-300 text-slate-900" |
40 | | - :style="{ top: `${top}px`, left: `${left}px`, minWidth: `${width}px` }"> |
| 41 | + :style="{ top: `${top}px`, left: `${left}px`, minWidth: `${width}px` }" |
| 42 | + :id="id + '-dropdown'"> |
41 | 43 |
|
42 | 44 | <div class="bg-white dark:bg-slate-800 max-h-64 overflow-hidden rounded-md dark:border-slate-600"> |
43 | 45 |
|
44 | 46 | <!-- Search bar --> |
45 | | - <div class="p-2 border-b dark:border-slate-700"> |
46 | | - <input type="text" x-model="search" :placeholder="$store.labels.getLabel('common','search')" |
47 | | - class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-700 dark:border-slate-600"> |
| 47 | + <div class="p-2 border-b dark:border-slate-700 border-slate-300"> |
| 48 | + <input type="text" x-model="search" :placeholder="$store.labels.getLabel('common','search')" :id="id + '-search'" |
| 49 | + class="w-full text-sm border rounded px-2 py-1 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-300 dark:hover:bg-slate-700 |
| 50 | + bg-white border-slate-300 text-slate-900 hover:bg-slate-100"> |
48 | 51 | </div> |
49 | 52 |
|
50 | 53 | <!-- Selectable list of items --> |
|
102 | 105 | this.$el.appendChild(tpl); |
103 | 106 |
|
104 | 107 | // Load dropdown items using the provided loader function |
105 | | - this.items = this.loader(); |
| 108 | + this.items = await this.loader(); |
106 | 109 |
|
107 | 110 | // Set preselected values (if any) |
108 | 111 | if (this.preselected.length) { |
|
114 | 117 |
|
115 | 118 | // Close dropdown when clicking outside of it |
116 | 119 | document.addEventListener('click', e => { |
117 | | - if (this.open && !this.$el.contains(e.target)) this.open = false; |
| 120 | + const dropdown = document.getElementById(this.id + '-dropdown'); |
| 121 | + |
| 122 | + if ( |
| 123 | + this.open && |
| 124 | + !this.$el.contains(e.target) && |
| 125 | + dropdown && |
| 126 | + !dropdown.contains(e.target) |
| 127 | + ) { |
| 128 | + this.open = false; |
| 129 | + } |
118 | 130 | }); |
119 | 131 |
|
120 | 132 | // Listen to external refresh event for dynamic updates |
|
0 commit comments