@saasmakers/ui 1.4.30 → 1.4.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
+
import type { FieldInput } from '#components'
|
|
2
3
|
import { vOnClickOutside } from '@vueuse/components'
|
|
3
|
-
import { refDebounced } from '@vueuse/core'
|
|
4
4
|
import type { FieldSelect, FieldSelectOption } from '../../types/fields'
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(defineProps<Omit<FieldSelect, 'modelValue'>>(), {
|
|
@@ -41,11 +41,16 @@ const modelValue = defineModel<FieldSelect['modelValue']>({ default: '' })
|
|
|
41
41
|
|
|
42
42
|
const opened = ref(false)
|
|
43
43
|
const searchRaw = ref('')
|
|
44
|
-
const searchQuery = refDebounced(searchRaw, 250)
|
|
45
44
|
|
|
46
|
-
const searchInput = ref<
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const searchInput = ref<InstanceType<typeof FieldInput>>()
|
|
46
|
+
|
|
47
|
+
const computedColumns = computed(() => {
|
|
48
|
+
if (props.columns.length > 0) {
|
|
49
|
+
return props.columns
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return [{ options: computedOptions.value }]
|
|
53
|
+
})
|
|
49
54
|
|
|
50
55
|
const computedOptions = computed(() => {
|
|
51
56
|
const options: FieldSelectOption[] = []
|
|
@@ -67,33 +72,22 @@ const computedOptions = computed(() => {
|
|
|
67
72
|
return options
|
|
68
73
|
})
|
|
69
74
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
return props.columns
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return [{ options: computedOptions.value }]
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const selectedOption = computed(() => {
|
|
79
|
-
return computedOptions.value.find((option) => {
|
|
80
|
-
return option.value === modelValue.value
|
|
81
|
-
})
|
|
75
|
+
const searchQueryCleaned = computed(() => {
|
|
76
|
+
return normalizeText(searchRaw.value.trim())
|
|
82
77
|
})
|
|
83
78
|
|
|
84
79
|
const filteredColumns = computed(() => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (!props.searchable || !searchQueryCleaned) {
|
|
80
|
+
if (!props.searchable || !searchQueryCleaned.value) {
|
|
88
81
|
return computedColumns.value
|
|
89
82
|
}
|
|
90
83
|
|
|
91
84
|
return computedColumns.value
|
|
92
85
|
.map(column => ({
|
|
93
86
|
...column,
|
|
94
|
-
options: column.options.filter(option =>
|
|
95
|
-
normalizeText(option.text).includes(searchQueryCleaned)
|
|
96
|
-
|
|
87
|
+
options: column.options.filter((option) => {
|
|
88
|
+
return normalizeText(option.text).includes(searchQueryCleaned.value)
|
|
89
|
+
|| normalizeText(option.value).includes(searchQueryCleaned.value)
|
|
90
|
+
}),
|
|
97
91
|
}))
|
|
98
92
|
.filter(column => column.options.length > 0)
|
|
99
93
|
})
|
|
@@ -102,6 +96,16 @@ const hasFilteredResults = computed(() => {
|
|
|
102
96
|
return filteredColumns.value.some(column => column.options.length > 0)
|
|
103
97
|
})
|
|
104
98
|
|
|
99
|
+
const selectedOption = computed(() => {
|
|
100
|
+
return computedOptions.value.find((option) => {
|
|
101
|
+
return option.value === modelValue.value
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const showNoResults = computed(() => {
|
|
106
|
+
return props.searchable && !!searchQueryCleaned.value && !hasFilteredResults.value
|
|
107
|
+
})
|
|
108
|
+
|
|
105
109
|
watch(opened, (isOpened) => {
|
|
106
110
|
if (isOpened && props.searchable) {
|
|
107
111
|
nextTick(() => {
|
|
@@ -168,6 +172,12 @@ function onOptionKeyDown(event: KeyboardEvent) {
|
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
174
|
|
|
175
|
+
function onSearchKeyup(event: KeyboardEvent) {
|
|
176
|
+
if (event.key === 'Escape') {
|
|
177
|
+
reset()
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
171
181
|
function reset() {
|
|
172
182
|
opened.value = false
|
|
173
183
|
searchRaw.value = ''
|
|
@@ -296,16 +306,18 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
296
306
|
<FieldInput
|
|
297
307
|
ref="searchInput"
|
|
298
308
|
v-model="searchRaw"
|
|
309
|
+
:autocomplete="false"
|
|
310
|
+
background="white"
|
|
299
311
|
border="none"
|
|
300
312
|
class="px-3"
|
|
301
313
|
:placeholder="searchPlaceholder || t('search')"
|
|
302
|
-
size="
|
|
303
|
-
|
|
314
|
+
:size="size"
|
|
315
|
+
@keyup="onSearchKeyup"
|
|
304
316
|
/>
|
|
305
317
|
</div>
|
|
306
318
|
|
|
307
319
|
<div
|
|
308
|
-
v-if="
|
|
320
|
+
v-if="showNoResults"
|
|
309
321
|
class="px-3 py-2 text-center text-gray-600 dark:text-gray-400"
|
|
310
322
|
>
|
|
311
323
|
{{ t('noResults') }}
|