@saasmakers/ui 1.4.29 → 1.4.30
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.
|
@@ -15,9 +15,9 @@ export default {
|
|
|
15
15
|
},
|
|
16
16
|
hideNext: { control: 'boolean' },
|
|
17
17
|
hidePrevious: { control: 'boolean' },
|
|
18
|
+
loading: { control: 'boolean' },
|
|
18
19
|
margin: { control: 'number' },
|
|
19
20
|
navigable: { control: 'boolean' },
|
|
20
|
-
loading: { control: 'boolean' },
|
|
21
21
|
size: {
|
|
22
22
|
control: 'select',
|
|
23
23
|
options: ['sm', 'base'] satisfies BaseDividerSize[],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { vOnClickOutside } from '@vueuse/components'
|
|
3
|
+
import { refDebounced } from '@vueuse/core'
|
|
3
4
|
import type { FieldSelect, FieldSelectOption } from '../../types/fields'
|
|
4
5
|
|
|
5
6
|
const props = withDefaults(defineProps<Omit<FieldSelect, 'modelValue'>>(), {
|
|
@@ -18,6 +19,8 @@ const props = withDefaults(defineProps<Omit<FieldSelect, 'modelValue'>>(), {
|
|
|
18
19
|
padding: true,
|
|
19
20
|
placeholder: '',
|
|
20
21
|
required: false,
|
|
22
|
+
searchable: false,
|
|
23
|
+
searchPlaceholder: '',
|
|
21
24
|
size: 'base',
|
|
22
25
|
validation: undefined,
|
|
23
26
|
})
|
|
@@ -30,11 +33,19 @@ const emit = defineEmits<{
|
|
|
30
33
|
|
|
31
34
|
const { getIcon } = useLayerIcons()
|
|
32
35
|
const { fadeIn } = useMotion()
|
|
36
|
+
const { normalizeText } = useLayerUtils()
|
|
37
|
+
const { t } = useI18n()
|
|
33
38
|
const id = useId()
|
|
34
39
|
|
|
35
40
|
const modelValue = defineModel<FieldSelect['modelValue']>({ default: '' })
|
|
36
41
|
|
|
37
42
|
const opened = ref(false)
|
|
43
|
+
const searchRaw = ref('')
|
|
44
|
+
const searchQuery = refDebounced(searchRaw, 250)
|
|
45
|
+
|
|
46
|
+
const searchInput = ref<{
|
|
47
|
+
focus: () => void
|
|
48
|
+
}>()
|
|
38
49
|
|
|
39
50
|
const computedOptions = computed(() => {
|
|
40
51
|
const options: FieldSelectOption[] = []
|
|
@@ -70,6 +81,35 @@ const selectedOption = computed(() => {
|
|
|
70
81
|
})
|
|
71
82
|
})
|
|
72
83
|
|
|
84
|
+
const filteredColumns = computed(() => {
|
|
85
|
+
const searchQueryCleaned = normalizeText(searchQuery.value.trim())
|
|
86
|
+
|
|
87
|
+
if (!props.searchable || !searchQueryCleaned) {
|
|
88
|
+
return computedColumns.value
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return computedColumns.value
|
|
92
|
+
.map(column => ({
|
|
93
|
+
...column,
|
|
94
|
+
options: column.options.filter(option =>
|
|
95
|
+
normalizeText(option.text).includes(searchQueryCleaned),
|
|
96
|
+
),
|
|
97
|
+
}))
|
|
98
|
+
.filter(column => column.options.length > 0)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const hasFilteredResults = computed(() => {
|
|
102
|
+
return filteredColumns.value.some(column => column.options.length > 0)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
watch(opened, (isOpened) => {
|
|
106
|
+
if (isOpened && props.searchable) {
|
|
107
|
+
nextTick(() => {
|
|
108
|
+
searchInput.value?.focus()
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
73
113
|
function onClose() {
|
|
74
114
|
reset()
|
|
75
115
|
}
|
|
@@ -130,6 +170,7 @@ function onOptionKeyDown(event: KeyboardEvent) {
|
|
|
130
170
|
|
|
131
171
|
function reset() {
|
|
132
172
|
opened.value = false
|
|
173
|
+
searchRaw.value = ''
|
|
133
174
|
}
|
|
134
175
|
|
|
135
176
|
function selectOption(event: MouseEvent, value: string) {
|
|
@@ -248,7 +289,30 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
248
289
|
}"
|
|
249
290
|
>
|
|
250
291
|
<div
|
|
251
|
-
v-
|
|
292
|
+
v-if="searchable"
|
|
293
|
+
class="sticky top-0 z-10 border-b border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900"
|
|
294
|
+
@click.stop
|
|
295
|
+
>
|
|
296
|
+
<FieldInput
|
|
297
|
+
ref="searchInput"
|
|
298
|
+
v-model="searchRaw"
|
|
299
|
+
border="none"
|
|
300
|
+
class="px-3"
|
|
301
|
+
:placeholder="searchPlaceholder || t('search')"
|
|
302
|
+
size="sm"
|
|
303
|
+
type="search"
|
|
304
|
+
/>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div
|
|
308
|
+
v-if="searchable && !hasFilteredResults"
|
|
309
|
+
class="px-3 py-2 text-center text-gray-600 dark:text-gray-400"
|
|
310
|
+
>
|
|
311
|
+
{{ t('noResults') }}
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<div
|
|
315
|
+
v-for="(column, columnIndex) in filteredColumns"
|
|
252
316
|
:key="columnIndex"
|
|
253
317
|
>
|
|
254
318
|
<BaseIcon
|
|
@@ -298,3 +362,60 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
298
362
|
/>
|
|
299
363
|
</div>
|
|
300
364
|
</template>
|
|
365
|
+
|
|
366
|
+
<i18n lang="json">
|
|
367
|
+
{
|
|
368
|
+
"de": {
|
|
369
|
+
"noResults": "Keine Ergebnisse",
|
|
370
|
+
"search": "Suchen"
|
|
371
|
+
},
|
|
372
|
+
"en": {
|
|
373
|
+
"noResults": "No results",
|
|
374
|
+
"search": "Search"
|
|
375
|
+
},
|
|
376
|
+
"es": {
|
|
377
|
+
"noResults": "Sin resultados",
|
|
378
|
+
"search": "Buscar"
|
|
379
|
+
},
|
|
380
|
+
"fr": {
|
|
381
|
+
"noResults": "Aucun résultat",
|
|
382
|
+
"search": "Rechercher"
|
|
383
|
+
},
|
|
384
|
+
"it": {
|
|
385
|
+
"noResults": "Nessun risultato",
|
|
386
|
+
"search": "Cerca"
|
|
387
|
+
},
|
|
388
|
+
"ja": {
|
|
389
|
+
"noResults": "結果がありません",
|
|
390
|
+
"search": "検索"
|
|
391
|
+
},
|
|
392
|
+
"ko": {
|
|
393
|
+
"noResults": "결과 없음",
|
|
394
|
+
"search": "검색"
|
|
395
|
+
},
|
|
396
|
+
"nl": {
|
|
397
|
+
"noResults": "Geen resultaten",
|
|
398
|
+
"search": "Zoeken"
|
|
399
|
+
},
|
|
400
|
+
"pl": {
|
|
401
|
+
"noResults": "Brak wyników",
|
|
402
|
+
"search": "Szukaj"
|
|
403
|
+
},
|
|
404
|
+
"pt": {
|
|
405
|
+
"noResults": "Sem resultados",
|
|
406
|
+
"search": "Pesquisar"
|
|
407
|
+
},
|
|
408
|
+
"pt-BR": {
|
|
409
|
+
"noResults": "Nenhum resultado",
|
|
410
|
+
"search": "Pesquisar"
|
|
411
|
+
},
|
|
412
|
+
"id": {
|
|
413
|
+
"noResults": "Tidak ada hasil",
|
|
414
|
+
"search": "Cari"
|
|
415
|
+
},
|
|
416
|
+
"vi": {
|
|
417
|
+
"noResults": "Không có kết quả",
|
|
418
|
+
"search": "Tìm kiếm"
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
</i18n>
|
package/app/types/bases.d.ts
CHANGED
|
@@ -109,9 +109,9 @@ export interface BaseDivider {
|
|
|
109
109
|
borderStyle?: BaseDividerBorderStyle
|
|
110
110
|
hideNext?: boolean
|
|
111
111
|
hidePrevious?: boolean
|
|
112
|
+
loading?: boolean
|
|
112
113
|
margin?: number
|
|
113
114
|
navigable?: boolean
|
|
114
|
-
loading?: boolean
|
|
115
115
|
size?: BaseDividerSize
|
|
116
116
|
title?: string
|
|
117
117
|
}
|
package/app/types/fields.d.ts
CHANGED