aloha-vue 1.2.282 → 1.2.284
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/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/AMenu2/AMenu2.js +23 -6
- package/src/AMenu2/AMenuBreadcrumbs/AMenuBreadcrumbs.js +48 -42
- package/src/AMenu2/AMenuPanelLink/AMenuPanelLink.js +1 -3
- package/src/AMenu2/AMenuPanelLink/compositionAPI/TabindexAPI.js +9 -17
- package/src/AMenu2/compositionAPI/KeydownAPI.js +144 -7
- package/src/AMenu2/compositionAPI/PanelsAPI.js +7 -5
- package/src/AMenu2/compositionAPI/ResizeAPI.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
---
|
|
8
8
|
# Versions
|
|
9
9
|
|
|
10
|
+
## 1.2.284
|
|
11
|
+
|
|
12
|
+
- Improved `focus` management for the `AMenu2` component, ensuring better accessibility when the menu is closed.
|
|
13
|
+
|
|
14
|
+
## 1.2.283
|
|
15
|
+
|
|
16
|
+
- Fixed the `HTML` structure of the component to improve accessibility and ensure compliance with accessibility standards.
|
|
17
|
+
|
|
10
18
|
## 1.2.282
|
|
11
19
|
|
|
12
20
|
- Fixed the `ATable` component to ensure the `aria-labelledby` attribute is not used when the table has no header, improving accessibility compliance.
|
package/package.json
CHANGED
package/src/AMenu2/AMenu2.js
CHANGED
|
@@ -231,11 +231,19 @@ export default {
|
|
|
231
231
|
} = ToggleAPI(props);
|
|
232
232
|
|
|
233
233
|
const {
|
|
234
|
+
isDesktopSubMenuVisibleWhenMenuClosed,
|
|
234
235
|
menuRef,
|
|
235
|
-
|
|
236
|
-
|
|
236
|
+
removeListenerForKeydownDesktop,
|
|
237
|
+
removeListenerForKeydownMobile,
|
|
238
|
+
setListenerForKeydownDesktop,
|
|
239
|
+
setListenerForKeydownMobile,
|
|
237
240
|
} = KeydownAPI(props, {
|
|
238
241
|
closeMenu,
|
|
242
|
+
dataProParent,
|
|
243
|
+
isMenuOpen,
|
|
244
|
+
isSubMenuOpen,
|
|
245
|
+
panelParentsOpen,
|
|
246
|
+
togglePanel,
|
|
239
247
|
});
|
|
240
248
|
|
|
241
249
|
const {
|
|
@@ -262,7 +270,7 @@ export default {
|
|
|
262
270
|
isMenuInitialized,
|
|
263
271
|
isMobileWidth,
|
|
264
272
|
} = ResizeAPI(props, {
|
|
265
|
-
|
|
273
|
+
removeListenerForKeydownMobile,
|
|
266
274
|
toggleMenu,
|
|
267
275
|
});
|
|
268
276
|
|
|
@@ -335,9 +343,9 @@ export default {
|
|
|
335
343
|
closeAllPanels();
|
|
336
344
|
if (newValue) {
|
|
337
345
|
destroyPopover();
|
|
338
|
-
|
|
346
|
+
setListenerForKeydownMobile();
|
|
339
347
|
} else {
|
|
340
|
-
|
|
348
|
+
removeListenerForKeydownMobile();
|
|
341
349
|
}
|
|
342
350
|
});
|
|
343
351
|
|
|
@@ -347,6 +355,14 @@ export default {
|
|
|
347
355
|
deep: true,
|
|
348
356
|
});
|
|
349
357
|
|
|
358
|
+
watch(isDesktopSubMenuVisibleWhenMenuClosed, newValue => {
|
|
359
|
+
if (newValue) {
|
|
360
|
+
setListenerForKeydownDesktop();
|
|
361
|
+
} else {
|
|
362
|
+
removeListenerForKeydownDesktop();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
350
366
|
provide("activeRoutesIds", computed(() => activeRoutesIds.value));
|
|
351
367
|
provide("clickMenuLink", clickMenuLink);
|
|
352
368
|
provide("isLinkTruncated", computed(() => isLinkTruncated.value));
|
|
@@ -363,7 +379,8 @@ export default {
|
|
|
363
379
|
removeBodyClasses();
|
|
364
380
|
destroyEventBusUpdateViewOnResize();
|
|
365
381
|
destroyPopover();
|
|
366
|
-
|
|
382
|
+
removeListenerForKeydownDesktop();
|
|
383
|
+
removeListenerForKeydownMobile();
|
|
367
384
|
});
|
|
368
385
|
|
|
369
386
|
return {
|
|
@@ -98,50 +98,56 @@ export default {
|
|
|
98
98
|
"a_menu_2__breadcrumb__ul a_menu_2__breadcrumb__ul_truncated",
|
|
99
99
|
],
|
|
100
100
|
}, [
|
|
101
|
-
this.breadcrumbsItemsDropdown.length > 0
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
this.breadcrumbsItemsDropdown.length > 0 ?
|
|
102
|
+
h("li", {
|
|
103
|
+
class: "a_menu_2__breadcrumbs__item",
|
|
104
|
+
}, [
|
|
105
|
+
h(ADropdown, {
|
|
106
|
+
buttonClass: "a_btn a_btn_secondary a_btn_small a_menu_2__breadcrumb__ul_truncated__btn",
|
|
107
|
+
buttonIconLeft: "ThreeDots",
|
|
108
|
+
buttonTextScreenReader: "_A_MENU_2_BREADCRUMB_SHOW_BTN_",
|
|
109
|
+
buttonTitle: "_A_MENU_2_BREADCRUMB_SHOW_BTN_",
|
|
110
|
+
dropdownClass: "a_menu_2__breadcrumb__ul_truncated__dropdown",
|
|
111
|
+
hasCaret: false,
|
|
112
|
+
inBody: true,
|
|
113
|
+
...this.breadcrumbsTruncatedDropdownProps,
|
|
114
|
+
}, {
|
|
115
|
+
dropdown: () => [
|
|
116
|
+
this.breadcrumbsItemsDropdown.map(breadcrumbsItem => {
|
|
117
|
+
const ATTR = breadcrumbsItem.panelParentId ?
|
|
118
|
+
{
|
|
119
|
+
tag: "a",
|
|
120
|
+
class: [
|
|
121
|
+
"a_menu_2__breadcrumbs__link",
|
|
122
|
+
this.breadcrumbsLinkClass,
|
|
123
|
+
],
|
|
124
|
+
role: "button",
|
|
125
|
+
tabindex: 0,
|
|
126
|
+
onClick: () => this.goBack({ parentId: breadcrumbsItem.panelParentId }),
|
|
127
|
+
onKeydown: $event => this.goBackKeydown({ $event, parentId: breadcrumbsItem.panelParentId }),
|
|
128
|
+
} :
|
|
129
|
+
{
|
|
130
|
+
class: "a_menu_2__breadcrumbs__link",
|
|
131
|
+
tag: "strong",
|
|
132
|
+
};
|
|
133
|
+
return h("li", {
|
|
134
|
+
key: breadcrumbsItem.panelParentId,
|
|
135
|
+
class: "a_menu_2__breadcrumbs__item",
|
|
136
|
+
}, [
|
|
137
|
+
h(AButton, {
|
|
138
|
+
text: breadcrumbsItem.label,
|
|
139
|
+
title: breadcrumbsItem.label,
|
|
140
|
+
...ATTR,
|
|
141
|
+
}),
|
|
142
|
+
h("span", {
|
|
143
|
+
class: "a_menu_2__breadcrumbs__item__divider",
|
|
144
|
+
}, "/"),
|
|
145
|
+
]);
|
|
137
146
|
}),
|
|
138
|
-
|
|
139
|
-
class: "a_menu_2__breadcrumbs__item__divider",
|
|
140
|
-
}, "/"),
|
|
141
|
-
]);
|
|
147
|
+
],
|
|
142
148
|
}),
|
|
143
|
-
]
|
|
144
|
-
|
|
149
|
+
]) :
|
|
150
|
+
"",
|
|
145
151
|
this.breadcrumbsItemsTruncated.map(breadcrumbsItem => {
|
|
146
152
|
const ATTR = breadcrumbsItem.panelParentId ?
|
|
147
153
|
{
|
|
@@ -4,9 +4,7 @@ import {
|
|
|
4
4
|
toRef,
|
|
5
5
|
} from "vue";
|
|
6
6
|
|
|
7
|
-
export default function TabindexAPI(props
|
|
8
|
-
isLinkOpen = computed(() => false),
|
|
9
|
-
}) {
|
|
7
|
+
export default function TabindexAPI(props) {
|
|
10
8
|
const isLinkInSearchPanel = toRef(props, "isLinkInSearchPanel");
|
|
11
9
|
const isPanelOpen = toRef(props, "isPanelOpen");
|
|
12
10
|
|
|
@@ -18,24 +16,18 @@ export default function TabindexAPI(props, {
|
|
|
18
16
|
if (isLinkInSearchPanel.value) {
|
|
19
17
|
return 0;
|
|
20
18
|
}
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
if (isPanelMain.value || isChildPanelOpen.value) {
|
|
26
|
-
if (isLinkOpen.value) {
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
return -1;
|
|
30
|
-
}
|
|
31
|
-
if (isPanelOpen.value) {
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
return -1;
|
|
19
|
+
if (isPanelMain.value) {
|
|
20
|
+
return 0;
|
|
35
21
|
}
|
|
36
22
|
if (isPanelOpen.value) {
|
|
37
23
|
return 0;
|
|
38
24
|
}
|
|
25
|
+
if (!isMenuOpen.value) {
|
|
26
|
+
if (isChildPanelOpen.value) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
39
31
|
return -1;
|
|
40
32
|
});
|
|
41
33
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
computed,
|
|
2
3
|
ref,
|
|
3
4
|
toRef,
|
|
4
5
|
} from "vue";
|
|
@@ -6,13 +7,27 @@ import {
|
|
|
6
7
|
import AMobileAPI from "../../compositionAPI/AMobileAPI";
|
|
7
8
|
|
|
8
9
|
import AKeysCode from "../../const/AKeysCode";
|
|
10
|
+
import AKeyId from "../../const/AKeyId";
|
|
11
|
+
import {
|
|
12
|
+
getElementId,
|
|
13
|
+
} from "../utils/utils";
|
|
9
14
|
import {
|
|
10
15
|
focusableSelector,
|
|
11
16
|
} from "../../const/AFocusableElements";
|
|
17
|
+
import {
|
|
18
|
+
findIndex,
|
|
19
|
+
forEach,
|
|
20
|
+
} from "lodash-es";
|
|
12
21
|
|
|
13
22
|
export default function KeydownAPI(props, {
|
|
14
23
|
closeMenu = () => {},
|
|
24
|
+
dataProParent = computed(() => ({})),
|
|
25
|
+
isMenuOpen = computed(() => false),
|
|
26
|
+
isSubMenuOpen = computed(() => false),
|
|
27
|
+
panelParentsOpen = ref([]),
|
|
28
|
+
togglePanel = () => {},
|
|
15
29
|
}) {
|
|
30
|
+
const menuId = toRef(props, "menuId");
|
|
16
31
|
const useEscapeForMobile = toRef(props, "useEscapeForMobile");
|
|
17
32
|
|
|
18
33
|
const menuRef = ref(undefined);
|
|
@@ -21,6 +36,10 @@ export default function KeydownAPI(props, {
|
|
|
21
36
|
isMobileWidth,
|
|
22
37
|
} = AMobileAPI();
|
|
23
38
|
|
|
39
|
+
const isDesktopSubMenuVisibleWhenMenuClosed = computed(() => {
|
|
40
|
+
return !isMobileWidth.value && !isMenuOpen.value && isSubMenuOpen.value;
|
|
41
|
+
});
|
|
42
|
+
|
|
24
43
|
const trapFocus = EVENT => {
|
|
25
44
|
if (!menuRef.value) {
|
|
26
45
|
return;
|
|
@@ -57,7 +76,7 @@ export default function KeydownAPI(props, {
|
|
|
57
76
|
$event.stopPropagation();
|
|
58
77
|
};
|
|
59
78
|
|
|
60
|
-
const
|
|
79
|
+
const keydownMobile = $event => {
|
|
61
80
|
const EVENT = $event || window.$event;
|
|
62
81
|
if (EVENT.key === "Escape" || EVENT.keyCode === AKeysCode.escape) {
|
|
63
82
|
pressEscape($event);
|
|
@@ -66,20 +85,138 @@ export default function KeydownAPI(props, {
|
|
|
66
85
|
}
|
|
67
86
|
};
|
|
68
87
|
|
|
69
|
-
const
|
|
88
|
+
const setFocusToLinkInPreviousSubPanel = ({ panelIndex, panelId }) => {
|
|
89
|
+
const LINK_HTML_ID = getElementId({
|
|
90
|
+
menuId: menuId.value,
|
|
91
|
+
id: panelId,
|
|
92
|
+
suffix: "link",
|
|
93
|
+
});
|
|
94
|
+
const LINK = document.getElementById(LINK_HTML_ID);
|
|
95
|
+
if (LINK) {
|
|
96
|
+
if (panelIndex > 0) {
|
|
97
|
+
const PANEL_PARENTS_OPEN_NEW = panelParentsOpen.value.slice(0, panelIndex);
|
|
98
|
+
togglePanel({ parentIds: PANEL_PARENTS_OPEN_NEW, withoutFocus: true });
|
|
99
|
+
}
|
|
100
|
+
LINK.focus();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const setFocusToLinkInNextSubPanel = ({ panelIndex }) => {
|
|
105
|
+
const PANEL_ID = panelParentsOpen.value[panelIndex + 1];
|
|
106
|
+
const PANEL_HTML_ID = getElementId({
|
|
107
|
+
menuId: menuId.value,
|
|
108
|
+
id: PANEL_ID,
|
|
109
|
+
suffix: "panel",
|
|
110
|
+
});
|
|
111
|
+
const LINKS = document.querySelectorAll(`#${ PANEL_HTML_ID } a.a_menu_2__link`);
|
|
112
|
+
if (LINKS.length) {
|
|
113
|
+
LINKS[0].focus();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const setFocusToParentLinkInMainPanel = ({ panelId }) => {
|
|
118
|
+
const LINK_ID = getElementId({
|
|
119
|
+
menuId: menuId.value,
|
|
120
|
+
id: panelId,
|
|
121
|
+
suffix: "link",
|
|
122
|
+
});
|
|
123
|
+
const LINK_ELEMENT = document.getElementById(LINK_ID);
|
|
124
|
+
if (LINK_ELEMENT) {
|
|
125
|
+
togglePanel({ parentIds: [], withoutFocus: true });
|
|
126
|
+
LINK_ELEMENT.focus();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const setFocusToNextParentLinkInMainPanel = ({ panelId }) => {
|
|
131
|
+
let linkNextId = panelId;
|
|
132
|
+
const INDEX_ACTIVE_LINK_IN_MAIN_PANEL = findIndex(dataProParent.value.main, [AKeyId, panelId]);
|
|
133
|
+
if (INDEX_ACTIVE_LINK_IN_MAIN_PANEL === -1) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (INDEX_ACTIVE_LINK_IN_MAIN_PANEL !== dataProParent.value.main.length - 1) { // not last link
|
|
137
|
+
linkNextId = dataProParent.value.main?.[INDEX_ACTIVE_LINK_IN_MAIN_PANEL + 1]?.[AKeyId];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const LINK_ID = getElementId({
|
|
141
|
+
menuId: menuId.value,
|
|
142
|
+
id: linkNextId,
|
|
143
|
+
suffix: "link",
|
|
144
|
+
});
|
|
145
|
+
const LINK_ELEMENT = document.getElementById(LINK_ID);
|
|
146
|
+
if (LINK_ELEMENT) {
|
|
147
|
+
togglePanel({ parentIds: [], withoutFocus: true });
|
|
148
|
+
LINK_ELEMENT.focus();
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const setFocus = ({ EVENT, PANEL_ELEMENT, panelIndex, panelId }) => {
|
|
153
|
+
const LINKS = PANEL_ELEMENT.querySelectorAll("a.a_menu_2__link");
|
|
154
|
+
if (EVENT.shiftKey) { // Shift + Tab
|
|
155
|
+
if (document.activeElement === LINKS[0]) {
|
|
156
|
+
if (panelIndex > 0) {
|
|
157
|
+
setFocusToLinkInPreviousSubPanel({ panelIndex, panelId });
|
|
158
|
+
} else {
|
|
159
|
+
setFocusToParentLinkInMainPanel({ panelId });
|
|
160
|
+
}
|
|
161
|
+
EVENT.preventDefault();
|
|
162
|
+
}
|
|
163
|
+
} else { // Tab
|
|
164
|
+
if (document.activeElement === LINKS[LINKS.length - 1]) {
|
|
165
|
+
if (panelIndex < panelParentsOpen.value.length - 1) {
|
|
166
|
+
setFocusToLinkInNextSubPanel({ panelIndex });
|
|
167
|
+
} else if (panelIndex > 0) {
|
|
168
|
+
setFocusToLinkInPreviousSubPanel({ panelIndex, panelId });
|
|
169
|
+
} else {
|
|
170
|
+
setFocusToNextParentLinkInMainPanel({ panelId });
|
|
171
|
+
}
|
|
172
|
+
EVENT.preventDefault();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const keydownDesktop = $event => {
|
|
178
|
+
const EVENT = $event || window.$event;
|
|
179
|
+
if (EVENT.key === "Tab" || EVENT.keyCode === AKeysCode.tab) {
|
|
180
|
+
forEach(panelParentsOpen.value, (panelId, panelIndex) => {
|
|
181
|
+
const PANEL_HTML_ID = getElementId({
|
|
182
|
+
menuId: menuId.value,
|
|
183
|
+
id: panelId,
|
|
184
|
+
suffix: "panel",
|
|
185
|
+
});
|
|
186
|
+
const PANEL_ELEMENT = document.getElementById(PANEL_HTML_ID);
|
|
187
|
+
if (PANEL_ELEMENT && PANEL_ELEMENT.contains(document.activeElement)) {
|
|
188
|
+
setFocus({ EVENT, PANEL_ELEMENT, panelIndex, panelId });
|
|
189
|
+
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const setListenerForKeydownMobile = () => {
|
|
70
197
|
if (isMobileWidth.value) {
|
|
71
|
-
document.addEventListener("keydown",
|
|
198
|
+
document.addEventListener("keydown", keydownMobile);
|
|
72
199
|
}
|
|
73
200
|
};
|
|
74
201
|
|
|
202
|
+
const removeListenerForKeydownMobile = () => {
|
|
203
|
+
document.removeEventListener("keydown", keydownMobile);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const setListenerForKeydownDesktop = () => {
|
|
207
|
+
document.addEventListener("keydown", keydownDesktop);
|
|
208
|
+
};
|
|
75
209
|
|
|
76
|
-
const
|
|
77
|
-
document.removeEventListener("keydown",
|
|
210
|
+
const removeListenerForKeydownDesktop = () => {
|
|
211
|
+
document.removeEventListener("keydown", keydownDesktop);
|
|
78
212
|
};
|
|
79
213
|
|
|
80
214
|
return {
|
|
215
|
+
isDesktopSubMenuVisibleWhenMenuClosed,
|
|
81
216
|
menuRef,
|
|
82
|
-
|
|
83
|
-
|
|
217
|
+
removeListenerForKeydownDesktop,
|
|
218
|
+
removeListenerForKeydownMobile,
|
|
219
|
+
setListenerForKeydownDesktop,
|
|
220
|
+
setListenerForKeydownMobile,
|
|
84
221
|
};
|
|
85
222
|
}
|
|
@@ -38,7 +38,7 @@ export default function PanelsAPI(props, {
|
|
|
38
38
|
resetSearch();
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const togglePanel = ({ parentIds, parentId, isLinkInSearchPanel }) => {
|
|
41
|
+
const togglePanel = ({ parentIds, parentId, isLinkInSearchPanel, withoutFocus }) => {
|
|
42
42
|
if (parentIds) {
|
|
43
43
|
panelParentsOpen.value = parentIds;
|
|
44
44
|
} else {
|
|
@@ -50,10 +50,12 @@ export default function PanelsAPI(props, {
|
|
|
50
50
|
panelParentsOpen.value = PANEL_PARENTS_OPEN;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
if (!withoutFocus) {
|
|
54
|
+
setFocusToFirstLinkInPanel({
|
|
55
|
+
menuId: menuId.value,
|
|
56
|
+
panelId: last(panelParentsOpen.value) || "",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
57
59
|
resetSearch();
|
|
58
60
|
};
|
|
59
61
|
|
|
@@ -8,7 +8,7 @@ import AMobileAPI from "../../compositionAPI/AMobileAPI";
|
|
|
8
8
|
import EventBus from "../../utils/EventBus";
|
|
9
9
|
|
|
10
10
|
export default function ResizeAPI(props, {
|
|
11
|
-
|
|
11
|
+
removeListenerForKeydownMobile = () => {},
|
|
12
12
|
toggleMenu = () => {},
|
|
13
13
|
}) {
|
|
14
14
|
const isMenuOpenInitial = toRef(props, "isMenuOpenInitial");
|
|
@@ -24,7 +24,7 @@ export default function ResizeAPI(props, {
|
|
|
24
24
|
toggleMenu({ isOpen: false });
|
|
25
25
|
} else {
|
|
26
26
|
toggleMenu({ isOpen: isMenuOpenInitial.value });
|
|
27
|
-
|
|
27
|
+
removeListenerForKeydownMobile();
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
|