Last active
January 11, 2021 14:59
-
-
Save artworkad/f59066a35f3f6e29d4ddd1cfb785caa0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="mt-1 relative" x-data="Components.customSelect({ open: false, value: 0, selected: 0 })" x-init="init()"> | |
<button | |
type="button" | |
x-ref="button" | |
@keydown.arrow-up.stop.prevent="onButtonClick()" | |
@keydown.arrow-down.stop.prevent="onButtonClick()" | |
@click="onButtonClick()" | |
aria-haspopup="listbox" | |
:aria-expanded="open" | |
aria-labelledby="listbox-label" | |
class="bg-gray-50 relative w-full border border-gray-300 rounded-md shadow-sm px-3 py-2 pr-10 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-primary-500 focus:border-primary-500 sm:text-lg" | |
> | |
<span x-text="['Wade Cooper','Arlene Mccoy'][value]" class="block truncate">Wade Cooper</span> | |
</button> | |
<div | |
x-show="open" | |
@click.away="open = false" | |
x-transition:leave="transition ease-in duration-100" | |
x-transition:leave-start="opacity-100" | |
x-transition:leave-end="opacity-0" | |
class="absolute mt-1 w-full rounded-md bg-white shadow-lg z-50" style="display: none;" | |
> | |
<ul | |
@keydown.enter.stop.prevent="onOptionSelect()" | |
@keydown.space.stop.prevent="onOptionSelect()" | |
@keydown.escape="onEscape()" | |
@keydown.arrow-up.prevent="onArrowUp()" | |
@keydown.arrow-down.prevent="onArrowDown()" | |
x-ref="listbox" | |
tabindex="-1" | |
role="listbox" | |
aria-labelledby="listbox-label" | |
:aria-activedescendant="activeDescendant" | |
class="max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-lg" | |
x-max="1" | |
aria-activedescendant="listbox-option-4" | |
> | |
<li | |
x-state:on="Highlighted" | |
x-state:off="Not Highlighted" | |
id="listbox-option-0" | |
role="option" | |
@click="choose(0)" | |
@mouseenter="selected = 0" | |
@mouseleave="selected = null" | |
:class="{ 'text-white bg-primary-600': selected === 0, 'text-gray-900': !(selected === 0) }" | |
class="cursor-default select-none relative py-2 pl-3 pr-9 text-gray-900" | |
> | |
<span | |
x-state:on="Selected" | |
x-state:off="Not Selected" | |
:class="{ 'font-semibold': value === 0, 'font-normal': !(value === 0) }" | |
class="font-normal block truncate" | |
> | |
Wade Cooper | |
</span> | |
</li> | |
<!-- More options... --> | |
</ul> | |
</div> | |
<script> | |
window.Components = { | |
customSelect(options) { | |
return { | |
init() { | |
this.optionCount = this.$refs.listbox.children.length | |
this.$watch('selected', (value) => { | |
if (!this.open) return | |
if (this.selected === null) { | |
this.activeDescendant = '' | |
return | |
} | |
this.activeDescendant = this.$refs.listbox.children[this.selected].id | |
}) | |
}, | |
activeDescendant: null, | |
optionCount: null, | |
open: false, | |
selected: null, | |
value: 0, | |
choose(option) { | |
this.value = option | |
this.open = false | |
}, | |
onButtonClick() { | |
if (this.open) return | |
this.selected = this.value | |
this.open = true | |
this.$nextTick(() => { | |
this.$refs.listbox.focus() | |
this.$refs.listbox.children[this.selected].scrollIntoView({ block: 'nearest' }) | |
}) | |
}, | |
onOptionSelect() { | |
if (this.selected !== null) { | |
this.value = this.selected | |
} | |
this.open = false | |
this.$refs.button.focus() | |
}, | |
onEscape() { | |
this.open = false | |
this.$refs.button.focus() | |
}, | |
onArrowUp() { | |
this.selected = this.selected - 1 < 0 ? this.optionCount - 1 : this.selected - 1 | |
this.$refs.listbox.children[this.selected].scrollIntoView({ block: 'nearest' }) | |
}, | |
onArrowDown() { | |
this.selected = this.selected + 1 > this.optionCount - 1 ? 1 : this.selected + 1 | |
this.$refs.listbox.children[this.selected].scrollIntoView({ block: 'nearest' }) | |
}, | |
...options, | |
} | |
}, | |
} | |
</script> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment