@apptegy/nuxt-navigation 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -70
- package/dist/module.json +2 -2
- package/dist/runtime/assets/icons/24/Metadata.svg +4 -0
- package/dist/runtime/components/Nav/Avatar.vue +1 -1
- package/dist/runtime/components/Nav/Header.vue +15 -158
- package/dist/runtime/components/Nav/HelpArticles.vue +14 -17
- package/dist/runtime/components/Nav/Icons/SidebarToggle.vue +6 -0
- package/dist/runtime/components/Nav/Icons/UserDropdownMenu.vue +5 -0
- package/dist/runtime/components/Nav/ImpersonateInfoPanel.vue +14 -14
- package/dist/runtime/components/Nav/OrgSelect.vue +96 -90
- package/dist/runtime/components/Nav/Sidebar.vue +9 -9
- package/dist/runtime/components/Nav/SidebarToggle.vue +32 -0
- package/dist/runtime/components/Nav/UserDropdown/index.vue +147 -0
- package/dist/runtime/composables/useDropdown.d.ts +16 -0
- package/dist/runtime/composables/useDropdown.js +204 -0
- package/package.json +15 -17
- package/dist/runtime/composables/accessibleActions.d.ts +0 -33
- package/dist/runtime/composables/accessibleActions.js +0 -195
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="org-selection">
|
|
3
3
|
<label id="org-dropdown-label" class="sr-only">
|
|
4
|
-
{{
|
|
4
|
+
{{ $t("navigation.orgDropdown") }}
|
|
5
5
|
</label>
|
|
6
6
|
<div
|
|
7
7
|
ref="dropdownTriggerRef"
|
|
@@ -14,48 +14,43 @@
|
|
|
14
14
|
>
|
|
15
15
|
<input
|
|
16
16
|
ref="inputRef"
|
|
17
|
-
is="input"
|
|
18
|
-
class="org-title"
|
|
19
17
|
type="text"
|
|
20
|
-
|
|
21
|
-
:
|
|
22
|
-
|
|
23
|
-
@
|
|
24
|
-
@
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
class="org-title"
|
|
19
|
+
:placeholder="$t('navigation.orgPlaceholder')"
|
|
20
|
+
:value="active ? searchQuery : selectedOrg?.name"
|
|
21
|
+
@keydown="keydownActionsOnTrigger"
|
|
22
|
+
@click.prevent="toggleDropdown"
|
|
23
|
+
@input="handleDropdownSearch"
|
|
24
|
+
>
|
|
25
|
+
<span v-if="selectedOrg?.intranet" class="badge selected">
|
|
26
|
+
<a-icon icon="16:lock-locked" />
|
|
27
|
+
{{ $t("navigation.orgBadge") }}
|
|
29
28
|
</span>
|
|
30
|
-
<!-- <Icon
|
|
31
|
-
style="margin-bottom: 2px"
|
|
32
|
-
:name-or-path="`dropdown${active ? '-up' : ''}`"
|
|
33
|
-
size="tiny"
|
|
34
|
-
reduced
|
|
35
|
-
variant="info"
|
|
36
|
-
/> -->
|
|
37
29
|
</div>
|
|
38
|
-
<div
|
|
30
|
+
<div
|
|
31
|
+
v-show="active"
|
|
32
|
+
id="organizations-options-list"
|
|
33
|
+
class="dropdown"
|
|
34
|
+
role="listbox"
|
|
35
|
+
>
|
|
39
36
|
<div
|
|
40
|
-
v-for="(option
|
|
41
|
-
|
|
37
|
+
v-for="(option) in sortedOrgs"
|
|
38
|
+
:key="option.id"
|
|
42
39
|
ref="optionRef"
|
|
43
|
-
|
|
40
|
+
v-on-click-outside="onClickOutsideHandler"
|
|
44
41
|
role="option"
|
|
45
42
|
class="org-option"
|
|
46
|
-
:class="{ selected: option ===
|
|
47
|
-
:aria-selected="
|
|
43
|
+
:class="{ selected: option.id === modelValue }"
|
|
44
|
+
:aria-selected="option.id === modelValue"
|
|
48
45
|
tabindex="-1"
|
|
49
|
-
@keydown="
|
|
50
|
-
@click="
|
|
46
|
+
@keydown="handleSelectedOrg($event, option.id)"
|
|
47
|
+
@click="handleSelectedOrg($event, option.id)"
|
|
51
48
|
>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<a-icon icon="16:lock-locked"></a-icon>
|
|
58
|
-
{{ $t('navigation.intranet') }}
|
|
49
|
+
<span :class="{ pinned: option.pinned, 'item-flex': true }"
|
|
50
|
+
>{{ option.name }}
|
|
51
|
+
<span v-if="option.intranet" class="badge selected">
|
|
52
|
+
<a-icon icon="16:lock-locked" />
|
|
53
|
+
{{ $t("navigation.orgBadge") }}
|
|
59
54
|
</span>
|
|
60
55
|
</span>
|
|
61
56
|
</div>
|
|
@@ -64,39 +59,50 @@
|
|
|
64
59
|
</template>
|
|
65
60
|
|
|
66
61
|
<script setup lang="ts">
|
|
67
|
-
import { useDropdown } from
|
|
68
|
-
import { vOnClickOutside } from
|
|
69
|
-
import { ref, computed
|
|
62
|
+
import { useDropdown, useNuxtApp } from "#imports";
|
|
63
|
+
import { vOnClickOutside } from "@vueuse/components";
|
|
64
|
+
import { ref, computed } from "vue";
|
|
65
|
+
|
|
70
66
|
const { $t } = useNuxtApp();
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
interface IOrg {
|
|
69
|
+
name: string;
|
|
70
|
+
id: number;
|
|
71
|
+
intranet?: boolean;
|
|
72
|
+
pinned?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface IOrgSelectProps {
|
|
76
|
+
orgs: Array<IOrg>;
|
|
77
|
+
modelValue: number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const emit = defineEmits<{
|
|
81
|
+
'update:model-value': [index: number]
|
|
82
|
+
}>();
|
|
83
|
+
|
|
84
|
+
const dropdownTriggerRef = ref();
|
|
85
|
+
const optionRef = ref();
|
|
86
|
+
const selectedOrg = computed(() => {
|
|
87
|
+
return props.orgs.find(({id}) => id == props.modelValue);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const props = defineProps<IOrgSelectProps>();
|
|
73
91
|
|
|
74
92
|
const {
|
|
75
93
|
active,
|
|
76
|
-
|
|
94
|
+
searchQuery,
|
|
77
95
|
toggleDropdown,
|
|
78
96
|
closeDropdown,
|
|
79
97
|
onClickOutsideHandler,
|
|
80
98
|
keydownActionsOnTrigger,
|
|
81
99
|
handleKeydown,
|
|
82
100
|
handleDropdownSearch,
|
|
83
|
-
} = useDropdown(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
orgs: Array<any>;
|
|
87
|
-
selectedOrg: {};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const props = withDefaults(defineProps<IOrgSelectProps>(), {
|
|
91
|
-
selectedOrg: {
|
|
92
|
-
name: '',
|
|
93
|
-
intranet: false
|
|
94
|
-
}
|
|
101
|
+
} = useDropdown(props.orgs, optionRef, dropdownTriggerRef, {
|
|
102
|
+
searchable: true,
|
|
103
|
+
trackBy: "name",
|
|
95
104
|
});
|
|
96
105
|
|
|
97
|
-
const dropdownTriggerRef = ref();
|
|
98
|
-
const optionRef = ref();
|
|
99
|
-
|
|
100
106
|
const sortedOrgs = computed(() => {
|
|
101
107
|
return [...props.orgs].sort((a, b) => {
|
|
102
108
|
if (a.pinned && !b.pinned) {
|
|
@@ -108,22 +114,15 @@ const sortedOrgs = computed(() => {
|
|
|
108
114
|
}
|
|
109
115
|
});
|
|
110
116
|
});
|
|
111
|
-
const orgDropdownLabel = computed(() => {
|
|
112
|
-
return $t('navigation.orgDropdown') || 'Select Organization'
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
function optionLabel(option) {
|
|
116
|
-
return option?.name || option.label
|
|
117
|
-
}
|
|
118
117
|
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
|
|
119
|
+
if($event.type == 'click') {
|
|
120
|
+
emit("update:model-value", orgId);
|
|
121
|
+
closeDropdown();
|
|
122
|
+
} else if ($event.type == 'keydown') {
|
|
123
|
+
emit("update:model-value", orgId);
|
|
124
|
+
handleKeydown($event as KeyboardEvent, orgId);
|
|
125
|
+
}
|
|
127
126
|
}
|
|
128
127
|
</script>
|
|
129
128
|
|
|
@@ -133,38 +132,44 @@ function handleKeydownAction(orgs: string | any[], idx: number, $event: { key: s
|
|
|
133
132
|
width: 300px;
|
|
134
133
|
max-height: 300px;
|
|
135
134
|
overflow-y: auto;
|
|
136
|
-
background-color: white;
|
|
135
|
+
background-color: var(--primary-white);
|
|
137
136
|
z-index: 50;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
139
|
.org-selection {
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
border-radius: 4px 4px 0 0;
|
|
141
|
+
}
|
|
142
|
+
.org-selection:focus-within {
|
|
143
|
+
outline: 2px var(--purple) solid;
|
|
143
144
|
}
|
|
144
|
-
.org-selection .dropdown-trigger
|
|
145
|
-
|
|
145
|
+
.org-selection .dropdown-trigger {
|
|
146
|
+
width: 300px;
|
|
147
|
+
padding: 0 8px;
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
gap: 8px;
|
|
151
|
+
justify-content: space-between;
|
|
152
|
+
border-radius: 4px 4px 0 0;
|
|
153
|
+
border: 0;
|
|
154
|
+
border-bottom: 1px solid var(--dscl-forms-underline, var(--grey-50));
|
|
155
|
+
background: var(--dscl-forms-bg, var(--grey-10));
|
|
146
156
|
}
|
|
147
157
|
.org-selection .dropdown-trigger .org-title {
|
|
148
158
|
line-height: 16px;
|
|
149
|
-
width:
|
|
159
|
+
width: 100%;
|
|
150
160
|
padding: 12px;
|
|
151
161
|
letter-spacing: 0.4px;
|
|
152
162
|
touch-action: manipulation;
|
|
153
|
-
color:
|
|
163
|
+
color: var(--primary-dark);
|
|
154
164
|
height: 40px;
|
|
155
|
-
display: flex;
|
|
156
|
-
justify-content: space-between;
|
|
157
|
-
align-items: center;
|
|
158
|
-
padding: 8px;
|
|
159
|
-
border-radius: 4px 4px 0 0;
|
|
160
165
|
border: 0;
|
|
161
|
-
|
|
162
|
-
background: var(--dscl-forms-bg,
|
|
166
|
+
padding: 8px;
|
|
167
|
+
background: var(--dscl-forms-bg, var(--grey-10));
|
|
163
168
|
white-space: nowrap;
|
|
164
169
|
cursor: pointer;
|
|
165
170
|
}
|
|
166
|
-
.org-selection .
|
|
167
|
-
|
|
171
|
+
.org-selection .dropdown-trigger .org-title:focus {
|
|
172
|
+
outline: none;
|
|
168
173
|
}
|
|
169
174
|
.org-selection .dropdown .org-option {
|
|
170
175
|
display: block;
|
|
@@ -177,30 +182,31 @@ function handleKeydownAction(orgs: string | any[], idx: number, $event: { key: s
|
|
|
177
182
|
cursor: pointer;
|
|
178
183
|
}
|
|
179
184
|
.org-selection .dropdown .org-option:focus-visible, .org-selection .dropdown .org-option:hover {
|
|
180
|
-
background-color: #
|
|
185
|
+
background-color: #f8f6fc;
|
|
181
186
|
}
|
|
182
187
|
.org-selection .custom-search {
|
|
183
188
|
margin: 8px 16px;
|
|
184
189
|
}
|
|
185
190
|
.org-selection .item-flex {
|
|
186
191
|
display: flex;
|
|
187
|
-
gap:
|
|
192
|
+
gap: 8px;
|
|
188
193
|
align-items: center;
|
|
189
194
|
width: 100%;
|
|
190
195
|
justify-content: space-between;
|
|
191
196
|
}
|
|
192
|
-
.org-selection .
|
|
197
|
+
.org-selection .badge {
|
|
193
198
|
display: inline-flex;
|
|
194
199
|
align-items: center;
|
|
195
200
|
background-color: var(--purple-50);
|
|
196
201
|
padding: 2px 4px;
|
|
197
202
|
color: white;
|
|
198
203
|
border-radius: 4px;
|
|
204
|
+
text-transform: uppercase;
|
|
199
205
|
}
|
|
200
|
-
.org-selection .
|
|
206
|
+
.org-selection .badge svg {
|
|
201
207
|
margin-right: 4px;
|
|
202
208
|
}
|
|
203
|
-
.org-selection .
|
|
209
|
+
.org-selection .badge.selected {
|
|
204
210
|
background-color: var(--grey-50);
|
|
205
211
|
}
|
|
206
212
|
</style>
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
{{ $t('navigation.skipToContent') }}
|
|
15
15
|
</a>
|
|
16
16
|
<div class="navbar--content">
|
|
17
|
+
<slot name="switcher" />
|
|
17
18
|
<ul class="navbar-applications">
|
|
18
19
|
<li v-for="application of applications" :key="application.id">
|
|
19
20
|
<NavSidebarSection
|
|
@@ -38,7 +39,6 @@
|
|
|
38
39
|
<NavImpersonateInfoPanel
|
|
39
40
|
v-if="impersonatedUser.show"
|
|
40
41
|
:impersonated-user="impersonatedUser"
|
|
41
|
-
:navbar-expanded="expanded"
|
|
42
42
|
/>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
@@ -84,9 +84,9 @@ interface ISidebarProps {
|
|
|
84
84
|
expanded?: boolean;
|
|
85
85
|
homepageUrl?: string;
|
|
86
86
|
showHelpArticles?: boolean;
|
|
87
|
-
helpArticleOptions?: Array<
|
|
87
|
+
helpArticleOptions?: Array<unknown>;
|
|
88
88
|
impersonatedUser?: IUser;
|
|
89
|
-
logo
|
|
89
|
+
logo?: ILogo;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
withDefaults(defineProps<ISidebarProps>(), {
|
|
@@ -96,18 +96,18 @@ withDefaults(defineProps<ISidebarProps>(), {
|
|
|
96
96
|
showHelpArticles: true,
|
|
97
97
|
expanded: true,
|
|
98
98
|
helpArticleOptions: () => [],
|
|
99
|
-
impersonatedUser: {
|
|
99
|
+
impersonatedUser: () => ({
|
|
100
100
|
show: false,
|
|
101
101
|
email: "staff3@lms.com",
|
|
102
|
-
phone_number :
|
|
102
|
+
phone_number : '',
|
|
103
103
|
client: "Sales Demo",
|
|
104
|
-
admin_email:
|
|
105
|
-
},
|
|
106
|
-
logo: {
|
|
104
|
+
admin_email: '',
|
|
105
|
+
}),
|
|
106
|
+
logo: () => ({
|
|
107
107
|
alt: 'Thrillshare',
|
|
108
108
|
src: 'logo.svg',
|
|
109
109
|
iconSrc: 'logo.svg',
|
|
110
|
-
}
|
|
110
|
+
})
|
|
111
111
|
})
|
|
112
112
|
</script>
|
|
113
113
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button class="sidebar-toggle" @click="toggleSidebar">
|
|
3
|
+
<NavIconsSidebarToggle />
|
|
4
|
+
<span> {{ $t('navigation.sidebarToggle') }}</span>
|
|
5
|
+
</button>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
const emit = defineEmits(["toggle-sidebar"]);
|
|
10
|
+
|
|
11
|
+
function toggleSidebar() {
|
|
12
|
+
emit("toggle-sidebar");
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<style scoped>
|
|
17
|
+
.sidebar-toggle {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: 4px;
|
|
21
|
+
background: var(--purple-20);
|
|
22
|
+
border: none;
|
|
23
|
+
border-radius: 4px;
|
|
24
|
+
padding: 8px 16px;
|
|
25
|
+
color: var(--purple);
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
}
|
|
28
|
+
.sidebar-toggle:focus {
|
|
29
|
+
outline: none;
|
|
30
|
+
box-shadow: 0 0 0 2px var(--primary-white), 0 0 0 3px var(--purple);
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
import { useDropdown } from "#imports";
|
|
4
|
+
import { vOnClickOutside } from "@vueuse/components";
|
|
5
|
+
|
|
6
|
+
interface IUserDropdown {
|
|
7
|
+
user: {
|
|
8
|
+
name: string;
|
|
9
|
+
avatar?: string;
|
|
10
|
+
};
|
|
11
|
+
userDropdownOptions: Array<{ label: string; url: string; icon: string }>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = defineProps<IUserDropdown>();
|
|
15
|
+
const dropdownTriggerRef = ref<HTMLDivElement>();
|
|
16
|
+
const dropdownOptionsRef = ref<Array<HTMLDivElement>>();
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
active,
|
|
20
|
+
toggleDropdown,
|
|
21
|
+
closeDropdown,
|
|
22
|
+
keydownActionsOnTrigger,
|
|
23
|
+
handleKeydown,
|
|
24
|
+
onClickOutsideHandler,
|
|
25
|
+
} = useDropdown(
|
|
26
|
+
props.userDropdownOptions,
|
|
27
|
+
dropdownOptionsRef,
|
|
28
|
+
dropdownTriggerRef,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
'select-option': [index: number]
|
|
33
|
+
}>();
|
|
34
|
+
|
|
35
|
+
function handleSelectedClick(index: number) {
|
|
36
|
+
emit("select-option", index);
|
|
37
|
+
closeDropdown();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function handleKeydownAction($event: KeyboardEvent, index: number) {
|
|
41
|
+
if ($event.key === "Enter" || $event.key === " ") {
|
|
42
|
+
emit("select-option", index);
|
|
43
|
+
} else {
|
|
44
|
+
handleKeydown($event, index);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<div
|
|
51
|
+
ref="dropdownTriggerRef"
|
|
52
|
+
aria-controls="user-dropdown"
|
|
53
|
+
:aria-expanded="active"
|
|
54
|
+
aria-haspopup="listbox"
|
|
55
|
+
role="combobox"
|
|
56
|
+
tabindex="0"
|
|
57
|
+
class="header__dropdown"
|
|
58
|
+
@keydown="keydownActionsOnTrigger"
|
|
59
|
+
@click.prevent="toggleDropdown"
|
|
60
|
+
>
|
|
61
|
+
<NavAvatar :name="user.name" :src="user.avatar" />
|
|
62
|
+
<NavIconsUserDropdownMenu />
|
|
63
|
+
<span class="sr-only">{{ $t('navigation.userDropdown') }}</span>
|
|
64
|
+
</div>
|
|
65
|
+
<div
|
|
66
|
+
v-show="active"
|
|
67
|
+
id="user-dropdown"
|
|
68
|
+
class="options-dropdown"
|
|
69
|
+
role="listbox"
|
|
70
|
+
>
|
|
71
|
+
<div
|
|
72
|
+
v-for="(option, idx) in userDropdownOptions"
|
|
73
|
+
:key="option.label"
|
|
74
|
+
ref="dropdownOptionsRef"
|
|
75
|
+
v-on-click-outside="onClickOutsideHandler"
|
|
76
|
+
role="option"
|
|
77
|
+
class="option-wrapper"
|
|
78
|
+
tabindex="-1"
|
|
79
|
+
@keydown="handleKeydownAction($event, idx)"
|
|
80
|
+
@click="handleSelectedClick(idx)"
|
|
81
|
+
>
|
|
82
|
+
<NuxtLink class="option" :to="option.url">
|
|
83
|
+
{{ option.label }}
|
|
84
|
+
<a-icon :icon="option.icon" font-size="24px" />
|
|
85
|
+
</NuxtLink>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<style scoped>
|
|
91
|
+
.header__dropdown {
|
|
92
|
+
font-size: 24px;
|
|
93
|
+
min-width: 64px;
|
|
94
|
+
width: 64px;
|
|
95
|
+
max-width: 64px;
|
|
96
|
+
border: none;
|
|
97
|
+
padding: 0;
|
|
98
|
+
outline: none;
|
|
99
|
+
color: var(--purple);
|
|
100
|
+
background: var(--purple-20);
|
|
101
|
+
border-radius: 16px;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
text-align: left;
|
|
104
|
+
position: relative;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
}
|
|
109
|
+
.header__dropdown:focus {
|
|
110
|
+
box-shadow: 0 0 0 2px var(--primary-white), 0 0 0 3px var(--purple);
|
|
111
|
+
}
|
|
112
|
+
.header__dropdown .avatar-container:focus {
|
|
113
|
+
outline: none;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.options-dropdown {
|
|
117
|
+
min-height: 100px;
|
|
118
|
+
position: absolute;
|
|
119
|
+
max-width: 512px;
|
|
120
|
+
right: 65px;
|
|
121
|
+
top: 80px;
|
|
122
|
+
background-color: var(--primary-white);
|
|
123
|
+
border-radius: 4px;
|
|
124
|
+
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
|
|
125
|
+
padding: 8px;
|
|
126
|
+
z-index: 10;
|
|
127
|
+
}
|
|
128
|
+
.options-dropdown .option-wrapper {
|
|
129
|
+
padding: 8px;
|
|
130
|
+
border-radius: 4px;
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
}
|
|
133
|
+
.options-dropdown .option-wrapper .option {
|
|
134
|
+
display: flex;
|
|
135
|
+
gap: 8px;
|
|
136
|
+
justify-content: space-between;
|
|
137
|
+
align-items: center;
|
|
138
|
+
color: var(--primary-dark);
|
|
139
|
+
text-decoration: none;
|
|
140
|
+
}
|
|
141
|
+
.options-dropdown .option-wrapper:focus-visible, .options-dropdown .option-wrapper:hover {
|
|
142
|
+
background-color: var(--purple-20);
|
|
143
|
+
}
|
|
144
|
+
.options-dropdown .option-wrapper:focus-visible .option, .options-dropdown .option-wrapper:hover .option {
|
|
145
|
+
color: var(--purple);
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Ref } from "vue";
|
|
2
|
+
export declare function useDropdown(options: Array<unknown>, dropdownOptionsRef: Ref<Array<HTMLElement>>, dropdownTriggerRef: Ref<HTMLElement>, config?: {
|
|
3
|
+
searchable: boolean;
|
|
4
|
+
trackBy?: string;
|
|
5
|
+
}): {
|
|
6
|
+
active: Ref<boolean>;
|
|
7
|
+
searchQuery: Ref<string>;
|
|
8
|
+
toggleDropdown: ($event: KeyboardEvent | MouseEvent) => Promise<void>;
|
|
9
|
+
openDropdown: () => void;
|
|
10
|
+
closeDropdown: () => void;
|
|
11
|
+
onClickOutsideHandler: () => void;
|
|
12
|
+
keydownActionsOnTrigger: (event: KeyboardEvent) => void;
|
|
13
|
+
handleKeydown: (event: KeyboardEvent, index: number) => number | undefined;
|
|
14
|
+
handleDropdownSearch: (inputValue: KeyboardEvent & InputEvent) => void;
|
|
15
|
+
debouncedFocus: any;
|
|
16
|
+
};
|