@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.
@@ -0,0 +1,204 @@
1
+ import debounce from "lodash/debounce";
2
+ import { ref, nextTick } from "vue";
3
+ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, config = { searchable: false, trackBy: "name" }) {
4
+ const active = ref(false);
5
+ const searchQuery = ref("");
6
+ async function toggleDropdown($event) {
7
+ active.value = !active.value;
8
+ if ($event instanceof KeyboardEvent && active.value && $event.key === "ArrowDown") {
9
+ await nextTick(() => {
10
+ dropdownOptionsRef.value[0].focus();
11
+ });
12
+ }
13
+ }
14
+ function openDropdown() {
15
+ active.value = true;
16
+ }
17
+ function closeDropdown() {
18
+ active.value = false;
19
+ }
20
+ function onClickOutsideHandler() {
21
+ if (!active.value)
22
+ return;
23
+ closeDropdown();
24
+ }
25
+ function keydownActionsOnTrigger(event) {
26
+ if (event.ctrlKey || event.metaKey || event.shiftKey)
27
+ return;
28
+ if (event.key !== "Tab") {
29
+ event.preventDefault();
30
+ }
31
+ switch (event.key) {
32
+ case "Tab":
33
+ if (!active.value)
34
+ return;
35
+ closeDropdown();
36
+ break;
37
+ case "ArrowDown":
38
+ if (active.value && event.key === "ArrowDown") {
39
+ nextTick(() => {
40
+ dropdownOptionsRef.value[0].focus();
41
+ openDropdown();
42
+ });
43
+ }
44
+ break;
45
+ case "ArrowUp":
46
+ openDropdown();
47
+ if (config.searchable) {
48
+ nextTick(() => {
49
+ dropdownOptionsRef.value[0].focus();
50
+ });
51
+ }
52
+ break;
53
+ case " ":
54
+ if (active.value) {
55
+ closeDropdown();
56
+ nextTick(() => {
57
+ dropdownTriggerRef.value.focus();
58
+ });
59
+ } else {
60
+ openDropdown();
61
+ }
62
+ break;
63
+ case "Enter":
64
+ if (active.value) {
65
+ closeDropdown();
66
+ nextTick(() => {
67
+ dropdownTriggerRef.value.focus();
68
+ });
69
+ } else {
70
+ searchQuery.value = "";
71
+ openDropdown();
72
+ }
73
+ break;
74
+ case "Escape":
75
+ closeDropdown();
76
+ dropdownTriggerRef.value.focus();
77
+ break;
78
+ case "Home":
79
+ openDropdown();
80
+ nextTick(() => {
81
+ dropdownOptionsRef.value[0].focus();
82
+ });
83
+ break;
84
+ case "End":
85
+ openDropdown();
86
+ nextTick(() => {
87
+ dropdownOptionsRef.value[options.length - 1].focus();
88
+ });
89
+ break;
90
+ default:
91
+ handleDropdownSearch(event);
92
+ break;
93
+ }
94
+ }
95
+ function handleKeydown(event, index) {
96
+ if (event.ctrlKey || event.metaKey || event.shiftKey)
97
+ return;
98
+ if (event.altKey && event.key === "ArrowUp") {
99
+ closeDropdown();
100
+ dropdownTriggerRef.value.focus();
101
+ return index;
102
+ }
103
+ switch (event.key) {
104
+ case "Enter":
105
+ nextTick(() => {
106
+ closeDropdown();
107
+ dropdownTriggerRef.value.focus();
108
+ return index;
109
+ });
110
+ break;
111
+ case " ":
112
+ nextTick(() => {
113
+ closeDropdown();
114
+ dropdownTriggerRef.value.focus();
115
+ return index;
116
+ });
117
+ break;
118
+ case "Tab":
119
+ nextTick(() => {
120
+ closeDropdown();
121
+ return index;
122
+ });
123
+ break;
124
+ case "Escape":
125
+ nextTick(() => {
126
+ closeDropdown();
127
+ dropdownTriggerRef.value.focus();
128
+ });
129
+ break;
130
+ case "ArrowDown":
131
+ if (index === options.length - 1)
132
+ break;
133
+ nextTick(() => {
134
+ dropdownOptionsRef.value[index + 1].focus();
135
+ });
136
+ return index;
137
+ case "ArrowUp":
138
+ if (index === 0)
139
+ break;
140
+ nextTick(() => {
141
+ dropdownOptionsRef.value[index - 1].focus();
142
+ });
143
+ return index;
144
+ case "Home":
145
+ nextTick(() => {
146
+ dropdownOptionsRef.value[0].focus();
147
+ });
148
+ return index;
149
+ case "End":
150
+ nextTick(() => {
151
+ dropdownOptionsRef.value[options.length - 1].focus();
152
+ });
153
+ return index;
154
+ case "PageDown": {
155
+ const pageDownIndexToJump = index + 10 > options.length ? index + 10 : options.length - 1;
156
+ dropdownOptionsRef.value[pageDownIndexToJump].focus();
157
+ return index;
158
+ }
159
+ case "PageUp": {
160
+ const pageUpIndexToJump = index - 10 < 0 ? index - 10 : 0;
161
+ dropdownOptionsRef.value[pageUpIndexToJump].focus();
162
+ return index;
163
+ }
164
+ default:
165
+ handleDropdownSearch(event);
166
+ break;
167
+ }
168
+ }
169
+ const debouncedFocus = debounce((idx) => {
170
+ dropdownOptionsRef.value[idx].focus();
171
+ }, 500);
172
+ function handleDropdownSearch(inputValue) {
173
+ if (!config.searchable)
174
+ return;
175
+ if (inputValue.key == "Backspace") {
176
+ searchQuery.value = searchQuery.value.slice(0, -1);
177
+ return;
178
+ }
179
+ const pressedKey = inputValue.key || inputValue.data;
180
+ searchQuery.value = `${searchQuery.value}${pressedKey}`;
181
+ const searchIndex = options.findIndex((option) => {
182
+ if (!config.trackBy) {
183
+ return option.includes(searchQuery.value);
184
+ } else {
185
+ return option[config.trackBy].toLowerCase().includes(searchQuery.value.toLowerCase());
186
+ }
187
+ });
188
+ if (searchIndex !== -1) {
189
+ debouncedFocus(searchIndex);
190
+ }
191
+ }
192
+ return {
193
+ active,
194
+ searchQuery,
195
+ toggleDropdown,
196
+ openDropdown,
197
+ closeDropdown,
198
+ onClickOutsideHandler,
199
+ keydownActionsOnTrigger,
200
+ handleKeydown,
201
+ handleDropdownSearch,
202
+ debouncedFocus
203
+ };
204
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apptegy/nuxt-navigation",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -26,26 +26,24 @@
26
26
  "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
27
27
  },
28
28
  "dependencies": {
29
- "@nuxt/kit": "^3.12.3"
29
+ "@nuxt/kit": "^3.12.4",
30
+ "@vueuse/components": "11.0.1",
31
+ "lodash": "^4.17.21"
30
32
  },
31
33
  "devDependencies": {
32
- "@iconify/vue": "^4.1.2",
33
- "@nuxt/devtools": "^1.3.9",
34
- "@nuxt/eslint-config": "^0.3.13",
35
- "@apptegy/icons": "2.10.0",
36
- "@nuxt/module-builder": "^0.8.1",
37
- "@nuxt/schema": "^3.12.3",
38
- "@nuxt/test-utils": "^3.13.1",
39
- "@types/node": "^20.14.10",
40
- "@vueuse/components": "10.11.0",
34
+ "@nuxt/devtools": "^1.3.14",
35
+ "@nuxt/eslint-config": "^0.5.1",
36
+ "@nuxt/module-builder": "^0.8.3",
37
+ "@nuxt/schema": "^3.12.4",
38
+ "@nuxt/test-utils": "^3.14.1",
39
+ "@types/node": "^20.16.1",
41
40
  "changelogen": "^0.5.5",
42
- "eslint": "^9.7.0",
43
- "lodash": "^4.17.21",
44
- "nuxt": "^3.12.3",
41
+ "eslint": "^9.9.0",
42
+ "nuxt": "^3.12.4",
45
43
  "sass": "^1.77.8",
46
- "typescript": "^5.5.3",
44
+ "typescript": "^5.5.4",
47
45
  "vitest": "^1.6.0",
48
- "vue": "^3.4.21",
49
- "vue-tsc": "^2.0.26"
46
+ "vue": "^3.4.38",
47
+ "vue-tsc": "^2.0.29"
50
48
  }
51
49
  }
@@ -1,33 +0,0 @@
1
- export declare function useDropdown(): {
2
- active: import("vue").Ref<boolean>;
3
- newQuery: import("vue").Ref<string>;
4
- toggleDropdown: ($event: {
5
- key: string;
6
- }, optionRef: {
7
- focus: () => void;
8
- }[]) => Promise<void>;
9
- openDropdown: () => void;
10
- closeDropdown: () => void;
11
- onClickOutsideHandler: () => void;
12
- keydownActionsOnTrigger: (event: {
13
- key: string;
14
- preventDefault: () => void;
15
- }, options: any[], optionRef: {
16
- focus: () => void;
17
- }[], dropdownTriggerRef: {
18
- focus: () => void;
19
- }, searchable: false, inputRef: {
20
- focus: () => void;
21
- }) => void;
22
- handleKeydown: (options: any[], optionIndex: number, event: {
23
- key: string;
24
- }, optionRef: {
25
- focus: () => void;
26
- }[], triggerRef: {
27
- focus: () => void;
28
- }) => number | undefined;
29
- handleDropdownSearch: (val: string, orgs: any[], optionRef: {
30
- focus: () => void;
31
- }[]) => void;
32
- debouncedFocus: any;
33
- };
@@ -1,195 +0,0 @@
1
- import debounce from "lodash/debounce";
2
- import { ref, nextTick } from "vue";
3
- export function useDropdown() {
4
- const active = ref(false);
5
- let newQuery = ref("");
6
- async function toggleDropdown($event, optionRef) {
7
- active.value = !active.value;
8
- if (active.value && $event.key === "ArrowDown") {
9
- await nextTick(() => {
10
- optionRef[0].focus();
11
- });
12
- }
13
- }
14
- function openDropdown() {
15
- active.value = true;
16
- }
17
- function closeDropdown() {
18
- active.value = false;
19
- }
20
- function onClickOutsideHandler() {
21
- if (!active.value)
22
- return;
23
- closeDropdown();
24
- }
25
- function keydownActionsOnTrigger(event, options, optionRef, dropdownTriggerRef, searchable, inputRef) {
26
- if (event.key !== "Tab") {
27
- event.preventDefault();
28
- }
29
- switch (event.key) {
30
- case "Tab":
31
- if (!active.value)
32
- return;
33
- closeDropdown();
34
- break;
35
- case "ArrowDown":
36
- nextTick(() => {
37
- if (active.value && event.key === "ArrowDown") {
38
- optionRef[0].focus();
39
- }
40
- openDropdown();
41
- });
42
- break;
43
- case "ArrowUp":
44
- openDropdown();
45
- nextTick(() => {
46
- if (searchable) {
47
- return;
48
- }
49
- optionRef[0].focus();
50
- });
51
- break;
52
- case " ":
53
- if (active.value) {
54
- closeDropdown();
55
- nextTick(() => {
56
- dropdownTriggerRef.focus();
57
- });
58
- } else {
59
- openDropdown();
60
- }
61
- break;
62
- case "Enter":
63
- if (active.value) {
64
- closeDropdown();
65
- nextTick(() => {
66
- dropdownTriggerRef.focus();
67
- });
68
- } else {
69
- nextTick(() => {
70
- openDropdown();
71
- });
72
- }
73
- break;
74
- case "Escape":
75
- closeDropdown();
76
- dropdownTriggerRef.focus();
77
- break;
78
- case "Home":
79
- openDropdown();
80
- nextTick(() => {
81
- optionRef[0].focus();
82
- });
83
- break;
84
- case "End":
85
- openDropdown();
86
- nextTick(() => {
87
- optionRef[options.length - 1].focus();
88
- });
89
- break;
90
- default:
91
- debounce(handleDropdownSearch(event.key, options, optionRef), 500);
92
- break;
93
- }
94
- }
95
- function handleKeydown(options, optionIndex, event, optionRef, triggerRef) {
96
- if (event.altKey && event.key === "ArrowUp") {
97
- closeDropdown();
98
- triggerRef.focus();
99
- return optionIndex;
100
- }
101
- switch (event.key) {
102
- case "Enter":
103
- nextTick(() => {
104
- closeDropdown();
105
- triggerRef.focus();
106
- return optionIndex;
107
- });
108
- break;
109
- case " ":
110
- nextTick(() => {
111
- closeDropdown();
112
- triggerRef.focus();
113
- return optionIndex;
114
- });
115
- break;
116
- case "Tab":
117
- nextTick(() => {
118
- closeDropdown();
119
- return optionIndex;
120
- });
121
- break;
122
- case "Escape":
123
- nextTick(() => {
124
- closeDropdown();
125
- triggerRef.focus();
126
- });
127
- break;
128
- case "ArrowDown":
129
- if (optionIndex === options.length - 1)
130
- break;
131
- nextTick(() => {
132
- optionRef[optionIndex + 1].focus();
133
- });
134
- return optionIndex;
135
- case "ArrowUp":
136
- if (optionIndex === 0)
137
- break;
138
- nextTick(() => {
139
- optionRef[optionIndex - 1].focus();
140
- });
141
- return optionIndex;
142
- case "Home":
143
- nextTick(() => {
144
- optionRef[0].focus();
145
- });
146
- return optionIndex;
147
- case "End":
148
- nextTick(() => {
149
- optionRef[options.length - 1].focus();
150
- });
151
- return optionIndex;
152
- case "PageDown": {
153
- const pageDownIndexToJump = optionIndex + 10 > options.length ? optionIndex + 10 : options.length - 1;
154
- optionRef[pageDownIndexToJump].focus();
155
- return optionIndex;
156
- }
157
- case "PageUp": {
158
- const pageUpIndexToJump = optionIndex - 10 < 0 ? optionIndex - 10 : 0;
159
- optionRef[pageUpIndexToJump].focus();
160
- return optionIndex;
161
- }
162
- default:
163
- handleDropdownSearch(event.key, options, optionRef);
164
- break;
165
- }
166
- }
167
- const debouncedFocus = debounce((idx, optionRef) => {
168
- optionRef[idx].focus();
169
- }, 500);
170
- function handleDropdownSearch(val, orgs, optionRef) {
171
- if (val == "Backspace") {
172
- newQuery.value = newQuery.value.slice(0, -1);
173
- return;
174
- }
175
- newQuery.value = `${newQuery.value}${val}`;
176
- const searchIndex = orgs.findIndex(
177
- (option) => option.name.toLowerCase().includes(newQuery.value.toLowerCase())
178
- );
179
- if (searchIndex !== -1) {
180
- debouncedFocus(searchIndex, optionRef);
181
- }
182
- }
183
- return {
184
- active,
185
- newQuery,
186
- toggleDropdown,
187
- openDropdown,
188
- closeDropdown,
189
- onClickOutsideHandler,
190
- keydownActionsOnTrigger,
191
- handleKeydown,
192
- handleDropdownSearch,
193
- debouncedFocus
194
- };
195
- }