Switch to composition API, Add custom names (#47)

* Switch to composition API, Add custom names

* Update package.json

* Update DropdownSelect.vue
This commit is contained in:
Adrian O.V
2023-05-03 17:50:39 -04:00
committed by GitHub
parent 1135852f25
commit 5fde3c53b8
3 changed files with 129 additions and 107 deletions

View File

@@ -23,6 +23,12 @@ const value = ref(null)
placeholder="Choose Frequency" placeholder="Choose Frequency"
disabled disabled
/> />
<DropdownSelect
v-model="value"
:options="['Daily', 'Weekly', 'Monthly', 'Tomorrow', 'Yesterday', 'Today', 'Biweekly', 'Tuesday', 'January']"
placeholder="Choose Frequency"
:display-name="(name) => name?.toUpperCase()"
/>
</DemoContainer> </DemoContainer>
```vue ```vue

View File

@@ -51,7 +51,7 @@
:value="option" :value="option"
:name="name" :name="name"
/> />
<label :for="`${name}-${index}`">{{ option }}</label> <label :for="`${name}-${index}`">{{ displayName(option) }}</label>
</div> </div>
</div> </div>
</transition> </transition>
@@ -59,113 +59,129 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed, ref, watch } from 'vue'
props: {
options: { const props = defineProps({
type: Array, options: {
required: true, type: Array,
}, required: true,
name: {
type: String,
required: true,
},
defaultValue: {
type: String,
default: null,
},
placeholder: {
type: String,
default: null,
},
modelValue: {
type: String,
default: null,
},
renderUp: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
}, },
emits: ['input', 'change', 'update:modelValue'], name: {
data() { type: String,
return { required: true,
dropdownVisible: false, },
selectedValue: this.modelValue || this.defaultValue, defaultValue: {
focusedOptionIndex: null, type: String,
default: null,
},
placeholder: {
type: String,
default: null,
},
modelValue: {
type: String,
default: null,
},
renderUp: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
displayName: {
type: Function,
default: (option) => option,
},
})
const emit = defineEmits(['input', 'change', 'update:modelValue'])
const dropdownVisible = ref(false)
const selectedValue = ref(props.modelValue || props.defaultValue)
const focusedOptionIndex = ref(null)
const dropdown = ref(null)
const optionElements = ref(null)
const selectedOption = computed(() => {
return props.displayName(selectedValue.value) || props.placeholder || 'Select an option'
})
const radioValue = computed({
get() {
return props.modelValue || selectedValue.value
},
set(newValue) {
emit('update:modelValue', newValue)
selectedValue.value = newValue
},
})
watch(
() => props.modelValue,
(newValue) => {
selectedValue.value = newValue
}
)
const toggleDropdown = () => {
if (!props.disabled) {
dropdownVisible.value = !dropdownVisible.value
dropdown.value.focus()
}
}
const selectOption = (option, index) => {
radioValue.value = option
emit('change', { option, index })
dropdownVisible.value = false
}
const onFocus = () => {
if (!props.disabled) {
focusedOptionIndex.value = props.options.findIndex((option) => option === selectedValue.value)
dropdownVisible.value = true
}
}
const onBlur = (event) => {
if (!isChildOfDropdown(event.relatedTarget)) {
dropdownVisible.value = false
}
}
const focusPreviousOption = () => {
if (!props.disabled) {
if (!dropdownVisible.value) {
toggleDropdown()
} }
}, focusedOptionIndex.value =
computed: { (focusedOptionIndex.value + props.options.length - 1) % props.options.length
selectedOption() { optionElements.value[focusedOptionIndex.value].focus()
return this.selectedValue || this.placeholder || 'Select an option' }
}, }
radioValue: {
get() { const focusNextOptionOrOpen = () => {
return this.modelValue || this.selectedValue if (!props.disabled) {
}, if (!dropdownVisible.value) {
set(newValue) { toggleDropdown()
this.$emit('update:modelValue', newValue) }
this.selectedValue = newValue focusedOptionIndex.value = (focusedOptionIndex.value + 1) % props.options.length
}, optionElements.value[focusedOptionIndex.value].focus()
}, }
}, }
methods: {
toggleDropdown() { const isChildOfDropdown = (element) => {
if (!this.disabled) { let currentNode = element
this.dropdownVisible = !this.dropdownVisible while (currentNode) {
this.$refs.dropdown.focus() if (currentNode === this.$el) {
} return true
}, }
selectOption(option, index) { currentNode = currentNode.parentNode
this.radioValue = option }
this.$emit('change', { option, index }) return false
this.dropdownVisible = false
},
onFocus() {
if (!this.disabled) {
this.focusedOptionIndex = this.options.findIndex((option) => option === this.selectedValue)
this.dropdownVisible = true
}
},
onBlur(event) {
if (!this.isChildOfDropdown(event.relatedTarget)) {
this.dropdownVisible = false
}
},
focusPreviousOption() {
if (!this.disabled) {
if (!this.dropdownVisible) {
this.toggleDropdown()
}
this.focusedOptionIndex =
(this.focusedOptionIndex + this.options.length - 1) % this.options.length
this.$refs.optionElements[this.focusedOptionIndex].focus()
}
},
focusNextOptionOrOpen() {
if (!this.disabled) {
if (!this.dropdownVisible) {
this.toggleDropdown()
}
this.focusedOptionIndex = (this.focusedOptionIndex + 1) % this.options.length
this.$refs.optionElements[this.focusedOptionIndex].focus()
}
},
isChildOfDropdown(element) {
let currentNode = element
while (currentNode) {
if (currentNode === this.$el) {
return true
}
currentNode = currentNode.parentNode
}
return false
},
},
} }
</script> </script>

View File

@@ -1,7 +1,7 @@
{ {
"name": "omorphia", "name": "omorphia",
"type": "module", "type": "module",
"version": "0.4.12", "version": "0.4.13",
"files": [ "files": [
"dist" "dist"
], ],