Disabled select input fixes (#355)

This commit is contained in:
formsdev 2024-03-20 16:26:17 +05:30 committed by GitHub
parent 9761351a26
commit e7c7776bb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 31 additions and 40 deletions

View File

@ -1,23 +1,20 @@
<template> <template>
<div class="v-select relative" :class="[{'w-0': multiple, 'min-w-full':multiple}]" ref="select"> <div class="v-select relative" :class="[{ 'w-0': multiple, 'min-w-full': multiple }]" ref="select">
<span class="inline-block w-full rounded-md"> <span class="inline-block w-full rounded-md">
<button type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" <button type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label"
class="cursor-pointer" class="cursor-pointer" :style="inputStyle"
:style="inputStyle" :class="[theme.SelectInput.input, { 'py-2': !multiple || loading, 'py-1': multiple, '!ring-red-500 !ring-2 !border-transparent': hasError, '!cursor-not-allowed !bg-gray-200': disabled }, inputClass]"
:class="[theme.SelectInput.input,{'py-2': !multiple || loading,'py-1': multiple, '!ring-red-500 !ring-2 !border-transparent': hasError, '!cursor-not-allowed !bg-gray-200': disabled}, inputClass]" @click="toggleDropdown">
@click="toggleDropdown" <div :class="{ 'h-6': !multiple, 'min-h-8': multiple && !loading }">
>
<div :class="{'h-6': !multiple, 'min-h-8': multiple && !loading}">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<Loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" /> <Loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" />
<div v-else-if="modelValue" key="value" class="flex" :class="{'min-h-8': multiple}"> <div v-else-if="modelValue" key="value" class="flex" :class="{ 'min-h-8': multiple }">
<slot name="selected" :option="modelValue" /> <slot name="selected" :option="modelValue" />
</div> </div>
<div v-else key="placeholder"> <div v-else key="placeholder">
<slot name="placeholder"> <slot name="placeholder">
<div class="text-gray-400 dark:text-gray-500 w-full text-left truncate pr-3" <div class="text-gray-400 dark:text-gray-500 w-full text-left truncate pr-3"
:class="{'py-1': multiple && !loading}" :class="{ 'py-1': multiple && !loading }">
>
{{ placeholder }} {{ placeholder }}
</div> </div>
</slot> </slot>
@ -32,27 +29,21 @@
</button> </button>
</span> </span>
<collapsible v-model="isOpen" @click-away="onClickAway" <collapsible v-model="isOpen" @click-away="onClickAway"
class="absolute mt-1 rounded-md bg-white dark:bg-notion-dark-light shadow-xl z-10" class="absolute mt-1 rounded-md bg-white dark:bg-notion-dark-light shadow-xl z-10" :class="dropdownClass">
:class="dropdownClass"
>
<ul tabindex="-1" role="listbox" <ul tabindex="-1" role="listbox"
class="rounded-md text-base leading-6 shadow-xs overflow-auto focus:outline-none sm:text-sm sm:leading-5 relative" class="rounded-md text-base leading-6 shadow-xs overflow-auto focus:outline-none sm:text-sm sm:leading-5 relative"
:class="{'max-h-42 py-1': !isSearchable,'max-h-48 pb-1': isSearchable}" :class="{ 'max-h-42 py-1': !isSearchable, 'max-h-48 pb-1': isSearchable }">
>
<div v-if="isSearchable" class="px-2 pt-2 sticky top-0 bg-white dark-bg-notion-dark-light z-10"> <div v-if="isSearchable" class="px-2 pt-2 sticky top-0 bg-white dark-bg-notion-dark-light z-10">
<text-input v-model="searchTerm" name="search" :color="color" :theme="theme" <text-input v-model="searchTerm" name="search" :color="color" :theme="theme" placeholder="Search..." />
placeholder="Search..."
/>
</div> </div>
<div v-if="loading" class="w-full py-2 flex justify-center"> <div v-if="loading" class="w-full py-2 flex justify-center">
<Loader class="h-6 w-6 text-nt-blue mx-auto" /> <Loader class="h-6 w-6 text-nt-blue mx-auto" />
</div> </div>
<template v-if="filteredOptions.length > 0"> <template v-if="filteredOptions.length > 0">
<li v-for="item in filteredOptions" :key="item[optionKey]" role="option" :style="optionStyle" <li v-for="item in filteredOptions" :key="item[optionKey]" role="option" :style="optionStyle"
:class="{'px-3 pr-9': multiple, 'px-3': !multiple}" :class="{ 'px-3 pr-9': multiple, 'px-3': !multiple }"
class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus-text-white focus-nt-blue" class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus-text-white focus-nt-blue"
@click="select(item)" @click="select(item)">
>
<slot name="option" :option="item" :selected="isSelected(item)" /> <slot name="option" :option="item" :selected="isSelected(item)" />
</li> </li>
</template> </template>
@ -60,10 +51,9 @@
{{ (allowCreation ? 'Type something to add an option' : 'No option available') }}. {{ (allowCreation ? 'Type something to add an option' : 'No option available') }}.
</p> </p>
<li v-if="allowCreation && searchTerm" role="option" :style="optionStyle" <li v-if="allowCreation && searchTerm" role="option" :style="optionStyle"
:class="{'px-3 pr-9': multiple, 'px-3': !multiple}" :class="{ 'px-3 pr-9': multiple, 'px-3': !multiple }"
class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus-text-white focus-nt-blue" class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus-text-white focus-nt-blue"
@click="createOption(searchTerm)" @click="createOption(searchTerm)">
>
Create <b class="px-1 bg-gray-300 rounded group-hover-text-black">{{ searchTerm }}</b> Create <b class="px-1 bg-gray-300 rounded group-hover-text-black">{{ searchTerm }}</b>
</li> </li>
</ul> </ul>
@ -103,7 +93,7 @@ export default {
allowCreation: { type: Boolean, default: false }, allowCreation: { type: Boolean, default: false },
disabled: { type: Boolean, default: false } disabled: { type: Boolean, default: false }
}, },
data () { data() {
return { return {
isOpen: false, isOpen: false,
searchTerm: '', searchTerm: '',
@ -111,23 +101,23 @@ export default {
} }
}, },
computed: { computed: {
optionStyle () { optionStyle() {
return { return {
'--bg-form-color': this.color '--bg-form-color': this.color
} }
}, },
inputStyle () { inputStyle() {
return { return {
'--tw-ring-color': this.color '--tw-ring-color': this.color
} }
}, },
debouncedRemote () { debouncedRemote() {
if (this.remote) { if (this.remote) {
return debounce(this.remote, 300) return debounce(this.remote, 300)
} }
return null return null
}, },
filteredOptions () { filteredOptions() {
if (!this.data) return [] if (!this.data) return []
if (!this.searchable || this.remote || this.searchTerm === '') { if (!this.searchable || this.remote || this.searchTerm === '') {
return this.data return this.data
@ -142,12 +132,12 @@ export default {
return res.item return res.item
}) })
}, },
isSearchable () { isSearchable() {
return this.searchable || this.remote !== null || this.allowCreation return this.searchable || this.remote !== null || this.allowCreation
} }
}, },
watch: { watch: {
searchTerm (val) { searchTerm(val) {
if (!this.debouncedRemote) return if (!this.debouncedRemote) return
if ((this.remote && val) || (val === '' && !this.modelValue) || (val === '' && this.isOpen)) { if ((this.remote && val) || (val === '' && !this.modelValue) || (val === '' && this.isOpen)) {
return this.debouncedRemote(val) return this.debouncedRemote(val)
@ -155,13 +145,13 @@ export default {
} }
}, },
methods: { methods: {
onClickAway (event) { onClickAway(event) {
// Check that event target isn't children of dropdown // Check that event target isn't children of dropdown
if (this.$refs.select && !this.$refs.select.contains(event.target)) { if (this.$refs.select && !this.$refs.select.contains(event.target)) {
this.isOpen = false this.isOpen = false
} }
}, },
isSelected (value) { isSelected(value) {
if (!this.modelValue) return false if (!this.modelValue) return false
if (this.emitKey && value[this.emitKey]) { if (this.emitKey && value[this.emitKey]) {
@ -173,16 +163,17 @@ export default {
} }
return this.modelValue === value return this.modelValue === value
}, },
toggleDropdown () { toggleDropdown() {
if (this.disabled) { if (this.disabled) {
this.isOpen = false this.isOpen = false
} } else {
this.isOpen = !this.isOpen this.isOpen = !this.isOpen
}
if (!this.isOpen) { if (!this.isOpen) {
this.searchTerm = '' this.searchTerm = ''
} }
}, },
select (value) { select(value) {
if (!this.multiple) { if (!this.multiple) {
// Close after select // Close after select
this.toggleDropdown() this.toggleDropdown()
@ -215,7 +206,7 @@ export default {
} }
} }
}, },
createOption (newOption) { createOption(newOption) {
if (newOption) { if (newOption) {
const newItem = { const newItem = {
name: newOption, name: newOption,