115 lines
7.0 KiB
HTML
115 lines
7.0 KiB
HTML
<div x-data="{
|
|
options: [
|
|
{
|
|
value: 'Aiden Walker',
|
|
label: 'Aiden Walker',
|
|
email: 'aiden.walker@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-1.webp',
|
|
},
|
|
{
|
|
value: 'Alex Martinez',
|
|
label: 'Alex Martinez',
|
|
email: 'alex.martinez@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-6.webp',
|
|
},
|
|
{
|
|
value: 'Ava Collins',
|
|
label: 'Ava Collins',
|
|
email: 'ava.collins@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-8.webp',
|
|
},
|
|
{
|
|
value: 'Bob Johnson',
|
|
label: 'Bob Johnson',
|
|
email: 'bob.johnson@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-2.webp',
|
|
},
|
|
{
|
|
value: 'Emily Rodriguez',
|
|
label: 'Emily Rodriguez',
|
|
email: 'emily.rodriguez@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-5.webp',
|
|
},
|
|
{
|
|
value: 'Emma Thompson',
|
|
label: 'Emma Thompson',
|
|
email: 'emma.thompson@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-4.webp',
|
|
},
|
|
{
|
|
value: 'Ethan Brown',
|
|
label: 'Ethan Brown',
|
|
email: 'ethan.brown@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-9.webp',
|
|
},
|
|
{
|
|
value: 'Isabella Davis',
|
|
label: 'Isabella Davis',
|
|
email: 'isabellea.davis@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-3.webp',
|
|
},
|
|
{
|
|
value: 'Noah Brooks',
|
|
label: 'Noah Brooks',
|
|
email: 'noah.brooks@example.com',
|
|
img: 'https://res.cloudinary.com/ds8pgw1pf/image/upload/penguinui/component-assets/avatars/avatar-7.webp',
|
|
},
|
|
],
|
|
isOpen: false,
|
|
openedWithKeyboard: false,
|
|
selectedOption: null,
|
|
setSelectedOption(option) {
|
|
this.selectedOption = option
|
|
this.isOpen = false
|
|
this.openedWithKeyboard = false
|
|
this.$refs.hiddenTextField.value = option.value
|
|
},
|
|
highlightFirstMatchingOption(pressedKey) {
|
|
const option = this.options.find((item) =>
|
|
item.label.toLowerCase().startsWith(pressedKey.toLowerCase()),
|
|
)
|
|
if (option) {
|
|
const index = this.options.indexOf(option)
|
|
const allOptions = document.querySelectorAll('.combobox-option')
|
|
if (allOptions[index]) {
|
|
allOptions[index].focus()
|
|
}
|
|
}
|
|
},
|
|
}" class="w-full max-w-xs flex flex-col gap-1" x-on:keydown="highlightFirstMatchingOption($event.key)" x-on:keydown.esc.window="isOpen = false, openedWithKeyboard = false">
|
|
<label for="user" class="w-fit pl-0.5 text-sm text-on-surface dark:text-on-surface-dark">Share with</label>
|
|
<div class="relative">
|
|
|
|
<!-- trigger button -->
|
|
<button type="button" role="combobox" class="inline-flex w-full items-center justify-between gap-2 whitespace-nowrap border-outline bg-surface-alt px-4 py-2 text-sm font-medium capitalize tracking-wide text-on-surface transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-outline-dark dark:bg-surface-dark-alt/50 dark:text-on-surface-dark dark:focus-visible:outline-primary-dark rounded-radius border" aria-haspopup="listbox" aria-controls="usersList" x-on:click="isOpen = ! isOpen" x-on:keydown.down.prevent="openedWithKeyboard = true" x-on:keydown.enter.prevent="openedWithKeyboard = true" x-on:keydown.space.prevent="openedWithKeyboard = true" x-bind:aria-label="selectedOption ? selectedOption.value : 'Please Select'" x-bind:aria-expanded="isOpen || openedWithKeyboard">
|
|
<span class="text-sm font-normal" x-text="selectedOption ? selectedOption.value : 'Please Select'"></span>
|
|
<!-- Chevron -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
|
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- hidden input to grab the selected value -->
|
|
<input id="user" name="user" type="text" x-ref="hiddenTextField" hidden/>
|
|
<ul x-cloak x-show="isOpen || openedWithKeyboard" id="usersList" class="absolute z-10 left-0 top-11 flex max-h-44 w-full flex-col overflow-hidden overflow-y-auto border-outline bg-surface-alt py-1.5 dark:border-outline-dark dark:bg-surface-dark-alt rounded-radius border" role="listbox" aria-label="users list" x-on:click.outside="isOpen = false, openedWithKeyboard = false" x-on:keydown.down.prevent="$focus.wrap().next()" x-on:keydown.up.prevent="$focus.wrap().previous()" x-transition x-trap="openedWithKeyboard">
|
|
<template x-for="(item, index) in options" x-bind:key="item.value">
|
|
<li class="combobox-option inline-flex justify-between items-center gap-6 bg-surface-alt px-4 py-2 text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/5 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong" role="option" x-on:click="setSelectedOption(item)" x-on:keydown.enter="setSelectedOption(item)" x-bind:id="'option-' + index" tabindex="0" >
|
|
<div class="flex items-center gap-2">
|
|
<img class="size-8 rounded-full" x-bind:src="item.img" alt="" aria-hidden="true"/>
|
|
<!-- Label -->
|
|
<div class="flex flex-col">
|
|
<span x-bind:class="selectedOption == item ? 'font-bold' : null" x-text="item.label"></span>
|
|
<span class="text-xs"x-text="item.email"></span>
|
|
<!-- Screen reader 'selected' indicator -->
|
|
<span class="sr-only" x-text="selectedOption == item ? 'selected' : null"></span>
|
|
</div>
|
|
</div>
|
|
<!-- Checkmark -->
|
|
<svg x-cloak x-show="selectedOption == item" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="size-4" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
|
|
</svg>
|
|
</li>
|
|
</template>
|
|
</ul>
|
|
</div>
|
|
</div> |