-
Notifications
You must be signed in to change notification settings - Fork 463
Expand file tree
/
Copy pathSelectDropdownPreselected.vue
More file actions
113 lines (106 loc) · 3.17 KB
/
SelectDropdownPreselected.vue
File metadata and controls
113 lines (106 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<template>
<label class="font-medium typography-label-sm" :for="id">Product</label>
<div ref="referenceRef" class="relative">
<div
:id="id"
ref="selectTriggerRef"
role="combobox"
:aria-controls="listboxId"
:aria-expanded="isOpen"
aria-label="Select one option"
:aria-activedescendant="selectedOption ? `${listboxId}-${selectedOption.value}` : undefined"
class="mt-0.5 flex items-center gap-8 relative font-normal typography-text-base ring-1 ring-neutral-300 ring-inset rounded-xl py-2 px-4 hover:ring-primary-700 active:ring-primary-700 active:ring-2 focus:ring-primary-700 focus:ring-2 focus-visible:outline focus-visible:outline-offset cursor-pointer"
tabindex="0"
@keydown.space="toggle()"
@click="toggle()"
>
<template v-if="selectedOption">{{ selectedOption.label }}</template>
<span v-else class="text-neutral-500">Choose from the list</span>
<SfIconExpandMore
class="ml-auto text-neutral-500 transition-transform ease-in-out duration-300"
:class="{ 'rotate-180': isOpen }"
/>
</div>
<ul
v-show="isOpen"
:id="listboxId"
ref="floatingRef"
role="listbox"
aria-label="Select one option"
class="w-full py-2 rounded-xl shadow-md border border-neutral-100 bg-white z-10"
:style="dropdownStyle"
>
<SfListItem
v-for="option in options"
:id="`${listboxId}-${option.value}`"
:key="option.value"
role="option"
tabindex="0"
:aria-selected="option.value === selectedOption?.value"
class="block"
:class="{ 'font-medium': option.value === selectedOption?.value }"
@click="selectOption(option)"
@keydown.enter="selectOption(option)"
@keydown.space="selectOption(option)"
>
{{ option.label }}
<template #suffix>
<SfIconCheck v-if="option.value === selectedOption?.value" class="text-primary-700" />
</template>
</SfListItem>
</ul>
</div>
</template>
<script lang="ts" setup>
import { ref, type Ref, useId } from 'vue';
import { unrefElement } from '@vueuse/core';
import {
useDropdown,
useDisclosure,
SfIconExpandMore,
SfListItem,
SfIconCheck,
useTrapFocus,
} from '@storefront-ui/vue';
type SelectOption = {
label: string;
value: string;
};
const options: SelectOption[] = [
{
label: 'Startup',
value: 'startup',
},
{
label: 'Business',
value: 'business',
},
{
label: 'Enterprise',
value: 'enterprise',
},
];
const { close, toggle, isOpen } = useDisclosure({ initialValue: false });
const selectedOption = ref<SelectOption>(options[0]);
const id = useId();
const listboxId = `select-dropdown-${id}`;
const selectTriggerRef = ref<HTMLDivElement>();
const {
referenceRef,
floatingRef,
style: dropdownStyle,
} = useDropdown({
isOpen,
onClose: close,
});
useTrapFocus(floatingRef as Ref<HTMLUListElement>, {
arrowKeysUpDown: true,
activeState: isOpen,
initialFocusContainerFallback: true,
});
const selectOption = (option: SelectOption) => {
selectedOption.value = option;
close();
unrefElement(selectTriggerRef as Ref<HTMLDivElement>)?.focus();
};
</script>