@doyourjob/gravity-ui-page-constructor-addons 2.1.45 → 2.1.47
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/build/cjs/components/Navigation/containers/Footer/GroupLinks/GroupLinks.js +3 -4
- package/build/cjs/components/NewHeader/NewHeader.css +5 -0
- package/build/cjs/components/NewHeader/NewHeader.js +3 -2
- package/build/cjs/components/NewHeader/components/NHLoginButton/NHLoginButton.css +18 -0
- package/build/cjs/components/NewHeader/components/NHLoginButton/NHLoginButton.js +18 -6
- package/build/cjs/components/NewHeader/components/NHMobileNavigation/NHMobileNavigation.css +10 -0
- package/build/cjs/components/NewHeader/components/NHMobileNavigation/NHMobileNavigation.js +8 -3
- package/build/cjs/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.css +6 -0
- package/build/cjs/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.js +2 -1
- package/build/cjs/components/NewHeader/components/NHMobileNavigationPopup/NHMobileNavigationPopup.d.ts +2 -1
- package/build/cjs/components/NewHeader/components/NHMobileNavigationPopup/NHMobileNavigationPopup.js +2 -2
- package/build/cjs/components/NewHeader/components/NHNavigation/NHNavigation.d.ts +4 -1
- package/build/cjs/components/NewHeader/components/NHNavigation/NHNavigation.js +72 -9
- package/build/cjs/components/NewHeader/components/NHNavigationItem/NHNavigationItem.css +5 -0
- package/build/cjs/components/NewHeader/components/NHNavigationItem/NHNavigationItem.d.ts +3 -0
- package/build/cjs/components/NewHeader/components/NHNavigationItem/NHNavigationItem.js +12 -3
- package/build/cjs/components/NewHeader/components/NHNavigationPopup/NHNavigationPopup.css +13 -2
- package/build/cjs/components/NewHeader/components/NHNavigationPopup/NHNavigationPopup.js +58 -6
- package/build/cjs/components/NewHeader/components/NHNavigationPopup/keyboardNavigation.d.ts +4 -0
- package/build/cjs/components/NewHeader/components/NHNavigationPopup/keyboardNavigation.js +43 -0
- package/build/cjs/components/NewHeader/components/NHPopupItem/NHPopupItem.css +5 -0
- package/build/esm/components/Navigation/containers/Footer/GroupLinks/GroupLinks.js +3 -4
- package/build/esm/components/NewHeader/NewHeader.css +5 -0
- package/build/esm/components/NewHeader/NewHeader.js +3 -2
- package/build/esm/components/NewHeader/components/NHLoginButton/NHLoginButton.css +18 -0
- package/build/esm/components/NewHeader/components/NHLoginButton/NHLoginButton.js +19 -7
- package/build/esm/components/NewHeader/components/NHMobileNavigation/NHMobileNavigation.css +10 -0
- package/build/esm/components/NewHeader/components/NHMobileNavigation/NHMobileNavigation.js +9 -4
- package/build/esm/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.css +6 -0
- package/build/esm/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.js +2 -1
- package/build/esm/components/NewHeader/components/NHMobileNavigationPopup/NHMobileNavigationPopup.d.ts +2 -1
- package/build/esm/components/NewHeader/components/NHMobileNavigationPopup/NHMobileNavigationPopup.js +2 -2
- package/build/esm/components/NewHeader/components/NHNavigation/NHNavigation.d.ts +4 -1
- package/build/esm/components/NewHeader/components/NHNavigation/NHNavigation.js +72 -9
- package/build/esm/components/NewHeader/components/NHNavigationItem/NHNavigationItem.css +5 -0
- package/build/esm/components/NewHeader/components/NHNavigationItem/NHNavigationItem.d.ts +3 -0
- package/build/esm/components/NewHeader/components/NHNavigationItem/NHNavigationItem.js +12 -3
- package/build/esm/components/NewHeader/components/NHNavigationPopup/NHNavigationPopup.css +13 -2
- package/build/esm/components/NewHeader/components/NHNavigationPopup/NHNavigationPopup.js +58 -6
- package/build/esm/components/NewHeader/components/NHNavigationPopup/keyboardNavigation.d.ts +4 -0
- package/build/esm/components/NewHeader/components/NHNavigationPopup/keyboardNavigation.js +38 -0
- package/build/esm/components/NewHeader/components/NHPopupItem/NHPopupItem.css +5 -0
- package/package.json +1 -1
|
@@ -7,9 +7,8 @@ const EnrichedLink_1 = require("../../../../EnrichedLink/EnrichedLink");
|
|
|
7
7
|
const b = (0, cn_1.block)('group-links');
|
|
8
8
|
const GroupLinks = ({ columnGroup: { title, items }, className }) => {
|
|
9
9
|
return (react_1.default.createElement("div", { className: b(null, className), key: title },
|
|
10
|
-
react_1.default.createElement("
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
react_1.default.createElement(EnrichedLink_1.EnrichedLink, Object.assign({ className: b('item') }, item))))))));
|
|
10
|
+
title && react_1.default.createElement("h5", { className: b('group-title') }, title),
|
|
11
|
+
react_1.default.createElement("ul", { className: b('group'), "aria-label": title }, items.map((item) => (react_1.default.createElement("li", { key: item.title, className: b('item-wrapper') },
|
|
12
|
+
react_1.default.createElement(EnrichedLink_1.EnrichedLink, Object.assign({ className: b('item') }, item))))))));
|
|
14
13
|
};
|
|
15
14
|
exports.default = GroupLinks;
|
|
@@ -172,6 +172,11 @@ unpredictable css rules order in build */
|
|
|
172
172
|
border-color: rgba(5, 43, 66, 0.25);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
.pc-addons-new-header__button:focus-visible {
|
|
176
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
177
|
+
outline-offset: 2px;
|
|
178
|
+
}
|
|
179
|
+
|
|
175
180
|
@media (max-width: 1081px) {
|
|
176
181
|
.pc-addons-new-header__left {
|
|
177
182
|
margin-right: 0;
|
|
@@ -19,6 +19,7 @@ const NewHeader = ({ data, setupRouteChangeHandler, renderSearch, className, scr
|
|
|
19
19
|
const [isSearchMode, setIsSearchMode] = (0, react_1.useState)(false);
|
|
20
20
|
const [isMobileNavigationOpen, setIsMobileNavigationOpen] = (0, react_1.useState)(false);
|
|
21
21
|
const [pageHasScroll, setPageHasScroll] = (0, react_1.useState)(false);
|
|
22
|
+
const [activeNavigationId, setActiveNavigationId] = (0, react_1.useState)(null);
|
|
22
23
|
const showButtonsContainer = Boolean(buttons);
|
|
23
24
|
const toggleSearch = (0, react_1.useCallback)((isActive) => setIsSearchMode(isActive), []);
|
|
24
25
|
const toggleMobileNavigationPopup = (0, react_1.useCallback)((isOpened) => {
|
|
@@ -58,10 +59,10 @@ const NewHeader = ({ data, setupRouteChangeHandler, renderSearch, className, scr
|
|
|
58
59
|
react_1.default.createElement("div", { className: b('left') },
|
|
59
60
|
logo && react_1.default.createElement(NHLogo_1.NHLogo, { data: logo }),
|
|
60
61
|
left ? (react_1.default.createElement("div", { className: b('navigation') },
|
|
61
|
-
react_1.default.createElement(NHNavigation_1.NHNavigation, { data: left, headerRef: headerRef }))) : null),
|
|
62
|
+
react_1.default.createElement(NHNavigation_1.NHNavigation, { activeNavigationId: activeNavigationId, data: left, headerRef: headerRef, navigationId: "left", setActiveNavigationId: setActiveNavigationId }))) : null),
|
|
62
63
|
react_1.default.createElement("div", { className: b('right') },
|
|
63
64
|
right ? (react_1.default.createElement("div", { className: b('navigation') },
|
|
64
|
-
react_1.default.createElement(NHNavigation_1.NHNavigation, { data: right, headerRef: headerRef }))) : null,
|
|
65
|
+
react_1.default.createElement(NHNavigation_1.NHNavigation, { activeNavigationId: activeNavigationId, data: right, headerRef: headerRef, navigationId: "right", setActiveNavigationId: setActiveNavigationId }))) : null,
|
|
65
66
|
react_1.default.createElement("div", { className: b('wrap') },
|
|
66
67
|
renderSearch && (react_1.default.createElement("div", { className: b('icons-container') }, renderSearch({ onActiveToggle: toggleSearch }))),
|
|
67
68
|
react_1.default.createElement("div", { className: b('buttons') },
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
/* use this for style redefinitions to awoid problems with
|
|
2
2
|
unpredictable css rules order in build */
|
|
3
|
+
.pc-addons-nh-login-button__wrapper {
|
|
4
|
+
display: flex;
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
.pc-addons-nh-login-button {
|
|
8
|
+
display: inline-block;
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
font: inherit;
|
|
12
|
+
border: none;
|
|
13
|
+
outline: none;
|
|
14
|
+
color: inherit;
|
|
15
|
+
background: none;
|
|
16
|
+
cursor: pointer;
|
|
4
17
|
display: flex;
|
|
5
18
|
align-items: center;
|
|
6
19
|
height: 36px;
|
|
@@ -17,4 +30,9 @@ unpredictable css rules order in build */
|
|
|
17
30
|
|
|
18
31
|
.pc-addons-nh-login-button:hover {
|
|
19
32
|
background: var(--g-color-base-brand-hover);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.pc-addons-nh-login-button:focus-visible {
|
|
36
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
37
|
+
outline-offset: 2px;
|
|
20
38
|
}
|
|
@@ -15,19 +15,30 @@ const NHLoginButton = ({ data, headerRef, setupRouteChangeHandler }) => {
|
|
|
15
15
|
const [isActive, setIsActive] = (0, react_1.useState)(false);
|
|
16
16
|
const [pretendentActiveTab, setPretendentAciveTab] = (0, react_1.useState)(false);
|
|
17
17
|
const [previouslyFocusedElement, setPreviouslyFocusedElement] = (0, react_1.useState)(null);
|
|
18
|
+
const popupId = (0, uikit_1.useUniqId)();
|
|
18
19
|
const handleActiveTab = (0, react_1.useCallback)((val) => {
|
|
19
20
|
setPreviouslyFocusedElement(document.activeElement);
|
|
20
21
|
setPretendentAciveTab(val);
|
|
21
22
|
}, []);
|
|
22
23
|
const onEscapeKeyDown = (0, react_1.useCallback)((event) => {
|
|
23
|
-
if (event.key === 'Escape') {
|
|
24
|
+
if (event.key === 'Escape' && isActive) {
|
|
24
25
|
setIsActive(false);
|
|
25
26
|
setPretendentAciveTab(false);
|
|
26
27
|
previouslyFocusedElement === null || previouslyFocusedElement === void 0 ? void 0 : previouslyFocusedElement.focus({ preventScroll: true });
|
|
27
28
|
}
|
|
28
|
-
}, [previouslyFocusedElement]);
|
|
29
|
+
}, [isActive, previouslyFocusedElement]);
|
|
29
30
|
const handleMouseEnter = (0, react_1.useCallback)(() => handleActiveTab(true), [handleActiveTab]);
|
|
30
31
|
const handleMouseLeave = (0, react_1.useCallback)(() => handleActiveTab(false), [handleActiveTab]);
|
|
32
|
+
const handleToggle = (0, react_1.useCallback)(() => {
|
|
33
|
+
const focusedElement = document.activeElement;
|
|
34
|
+
const nextIsActive = !isActive;
|
|
35
|
+
setPreviouslyFocusedElement(focusedElement);
|
|
36
|
+
setPretendentAciveTab(nextIsActive);
|
|
37
|
+
setIsActive(nextIsActive);
|
|
38
|
+
if (!nextIsActive) {
|
|
39
|
+
focusedElement === null || focusedElement === void 0 ? void 0 : focusedElement.focus({ preventScroll: true });
|
|
40
|
+
}
|
|
41
|
+
}, [isActive]);
|
|
31
42
|
(0, react_1.useEffect)(() => {
|
|
32
43
|
const timerId = setTimeout(() => {
|
|
33
44
|
setIsActive(pretendentActiveTab);
|
|
@@ -43,10 +54,11 @@ const NHLoginButton = ({ data, headerRef, setupRouteChangeHandler }) => {
|
|
|
43
54
|
(0, react_1.useEffect)(() => setupRouteChangeHandler === null || setupRouteChangeHandler === void 0 ? void 0 : setupRouteChangeHandler(() => {
|
|
44
55
|
handleMouseLeave();
|
|
45
56
|
}), [handleMouseLeave, setupRouteChangeHandler]);
|
|
46
|
-
return (react_1.default.createElement("div", { className: b(), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
return (react_1.default.createElement("div", { className: b('wrapper'), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
|
|
58
|
+
react_1.default.createElement("button", { className: b(), type: "button", onClick: handleToggle, "aria-expanded": isActive, "aria-controls": popupId },
|
|
59
|
+
data.text,
|
|
60
|
+
react_1.default.createElement(uikit_1.Icon, { data: isActive ? ChevronUp_1.ChevronUp : ChevronDown_1.ChevronDown, size: 16 })),
|
|
61
|
+
isActive && (react_1.default.createElement(NHNavigationPopup_1.NHNavigationPopup, { headerRef: headerRef, id: popupId },
|
|
50
62
|
react_1.default.createElement(NHLoginPopup_1.NHLoginPopup, Object.assign({}, data))))));
|
|
51
63
|
};
|
|
52
64
|
exports.NHLoginButton = NHLoginButton;
|
|
@@ -29,6 +29,11 @@ unpredictable css rules order in build */
|
|
|
29
29
|
display: none;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
.pc-addons-nh-mobile-navigation__icon:focus-visible {
|
|
33
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
34
|
+
outline-offset: 2px;
|
|
35
|
+
}
|
|
36
|
+
|
|
32
37
|
.pc-addons-nh-mobile-navigation__header {
|
|
33
38
|
position: sticky;
|
|
34
39
|
top: 0;
|
|
@@ -48,6 +53,11 @@ unpredictable css rules order in build */
|
|
|
48
53
|
gap: 8px;
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
.pc-addons-nh-mobile-navigation__close-button:focus-visible {
|
|
57
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
58
|
+
outline-offset: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
.pc-addons-nh-mobile-navigation__search-container {
|
|
52
62
|
display: flex;
|
|
53
63
|
align-items: center;
|
|
@@ -14,17 +14,22 @@ const NHPopupItem_1 = require("../NHPopupItem/NHPopupItem");
|
|
|
14
14
|
const b = (0, cn_1.block)('nh-mobile-navigation');
|
|
15
15
|
const NHMobileNavigation = ({ isOpened, toogleOpen, isSearchOpen, data, onMenuScroll, }) => {
|
|
16
16
|
var _a, _b;
|
|
17
|
+
const popupId = (0, uikit_1.useUniqId)();
|
|
17
18
|
return (react_1.default.createElement("div", { className: b() },
|
|
18
|
-
react_1.default.createElement(uikit_1.Button, { view: "flat", size: "l", className: b('icon', { hidden: isSearchOpen }),
|
|
19
|
+
react_1.default.createElement(uikit_1.Button, { view: "flat", size: "l", className: b('icon', { hidden: isSearchOpen }), extraProps: {
|
|
20
|
+
'aria-label': isOpened ? 'Close navigation menu' : 'Open navigation menu',
|
|
21
|
+
'aria-expanded': isOpened,
|
|
22
|
+
'aria-controls': popupId,
|
|
23
|
+
}, onClick: (e) => {
|
|
19
24
|
e.stopPropagation();
|
|
20
25
|
toogleOpen(!isOpened);
|
|
21
26
|
} },
|
|
22
27
|
react_1.default.createElement(uikit_1.Icon, { data: isOpened ? icons_1.Xmark : icons_1.Bars, size: 24 })),
|
|
23
|
-
react_1.default.createElement(NHMobileNavigationPopup_1.NHMobileNavigationPopup, { isOpened: isOpened, onClose: () => toogleOpen(false), onMenuScroll: onMenuScroll },
|
|
28
|
+
react_1.default.createElement(NHMobileNavigationPopup_1.NHMobileNavigationPopup, { id: popupId, isOpened: isOpened, onClose: () => toogleOpen(false), onMenuScroll: onMenuScroll },
|
|
24
29
|
react_1.default.createElement("div", { className: b('header') },
|
|
25
30
|
(data === null || data === void 0 ? void 0 : data.logo) && react_1.default.createElement(NHLogo_1.NHLogo, { data: data.logo }),
|
|
26
31
|
react_1.default.createElement("div", { className: b('header-right') },
|
|
27
|
-
react_1.default.createElement(uikit_1.Button, { view: "flat", size: "l", className: b('close-button'), onClick: () => toogleOpen(false) },
|
|
32
|
+
react_1.default.createElement(uikit_1.Button, { view: "flat", size: "l", className: b('close-button'), extraProps: { 'aria-label': 'Close navigation menu' }, onClick: () => toogleOpen(false) },
|
|
28
33
|
react_1.default.createElement(uikit_1.Icon, { data: icons_1.Xmark, size: 24 })))),
|
|
29
34
|
react_1.default.createElement("nav", { className: b('nav') },
|
|
30
35
|
react_1.default.createElement("ul", { className: b('list') }, (_a = data === null || data === void 0 ? void 0 : data.left) === null || _a === void 0 ? void 0 : _a.map((item, index) => (react_1.default.createElement("li", { className: b('item'), key: index },
|
package/build/cjs/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.css
CHANGED
|
@@ -8,6 +8,11 @@ unpredictable css rules order in build */
|
|
|
8
8
|
align-items: center;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
.pc-addons-nh-mobile-navigation-item:focus-visible {
|
|
12
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
13
|
+
outline-offset: 2px;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
.pc-addons-nh-mobile-navigation-item_type_link {
|
|
12
17
|
color: inherit;
|
|
13
18
|
text-decoration: none;
|
|
@@ -27,6 +32,7 @@ unpredictable css rules order in build */
|
|
|
27
32
|
|
|
28
33
|
.pc-addons-nh-mobile-navigation-item__arrow {
|
|
29
34
|
color: var(--g-color-text-secondary);
|
|
35
|
+
display: flex;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
.pc-addons-nh-mobile-navigation-item__content {
|
package/build/cjs/components/NewHeader/components/NHMobileNavigationItem/NHMobileNavigationItem.js
CHANGED
|
@@ -15,6 +15,7 @@ const NHMobileNavigationItem = ({ item }) => {
|
|
|
15
15
|
}, [isOpened]);
|
|
16
16
|
const handleKeyDown = (0, react_1.useCallback)((e) => {
|
|
17
17
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
18
|
+
e.preventDefault();
|
|
18
19
|
toggleOpen();
|
|
19
20
|
}
|
|
20
21
|
}, [toggleOpen]);
|
|
@@ -23,7 +24,7 @@ const NHMobileNavigationItem = ({ item }) => {
|
|
|
23
24
|
return (react_1.default.createElement("a", Object.assign({ href: item.data.url, className: b({ type: 'link' }) }, (0, gravity_ui_page_constructor_1.getLinkProps)(item.data.url || '', undefined, item.data.target)), item.title));
|
|
24
25
|
}
|
|
25
26
|
return (react_1.default.createElement(react_1.Fragment, null,
|
|
26
|
-
react_1.default.createElement("div", { className: b(), onClick: toggleOpen, role: "button", tabIndex: 0, onKeyDown: handleKeyDown },
|
|
27
|
+
react_1.default.createElement("div", { className: b(), onClick: toggleOpen, role: "button", tabIndex: 0, "aria-expanded": isOpened, onKeyDown: handleKeyDown },
|
|
27
28
|
react_1.default.createElement("div", { className: b('text') }, item.title),
|
|
28
29
|
react_1.default.createElement("div", { className: b('arrow') },
|
|
29
30
|
react_1.default.createElement(gravity_ui_page_constructor_1.ToggleArrow, { size: 12, type: "vertical", open: isOpened, iconType: "navigation" }))),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
interface MobileNavigationPopupProps {
|
|
3
|
+
id?: string;
|
|
3
4
|
isOpened: boolean;
|
|
4
5
|
onClose: () => void;
|
|
5
6
|
children: React.ReactNode;
|
|
6
7
|
onMenuScroll: (scrollTop: number) => void;
|
|
7
8
|
}
|
|
8
|
-
export declare const NHMobileNavigationPopup: ({ isOpened, onClose, children, onMenuScroll, }: MobileNavigationPopupProps) => React.ReactPortal | null;
|
|
9
|
+
export declare const NHMobileNavigationPopup: ({ id, isOpened, onClose, children, onMenuScroll, }: MobileNavigationPopupProps) => React.ReactPortal | null;
|
|
9
10
|
export {};
|
package/build/cjs/components/NewHeader/components/NHMobileNavigationPopup/NHMobileNavigationPopup.js
CHANGED
|
@@ -10,7 +10,7 @@ const react_transition_group_1 = require("react-transition-group");
|
|
|
10
10
|
const cn_1 = require("../../../../utils/cn");
|
|
11
11
|
const b = (0, cn_1.block)('nh-mobile-navigation-popup');
|
|
12
12
|
const TRANSITION_TIME = 400;
|
|
13
|
-
const NHMobileNavigationPopup = ({ isOpened, onClose, children, onMenuScroll, }) => {
|
|
13
|
+
const NHMobileNavigationPopup = ({ id, isOpened, onClose, children, onMenuScroll, }) => {
|
|
14
14
|
const [body, setBody] = (0, react_1.useState)();
|
|
15
15
|
const ref = (0, react_1.useRef)(null);
|
|
16
16
|
const handleScroll = (0, react_1.useCallback)(() => {
|
|
@@ -38,6 +38,6 @@ const NHMobileNavigationPopup = ({ isOpened, onClose, children, onMenuScroll, })
|
|
|
38
38
|
}
|
|
39
39
|
return react_dom_1.default.createPortal(react_1.default.createElement(react_transition_group_1.CSSTransition, { in: isOpened, classNames: b('transition'), unmountOnExit: true, timeout: TRANSITION_TIME },
|
|
40
40
|
react_1.default.createElement(gravity_ui_page_constructor_1.OutsideClick, { className: b(), onOutsideClick: onClose },
|
|
41
|
-
react_1.default.createElement("div", { ref: ref, className: b('container') }, children))), body);
|
|
41
|
+
react_1.default.createElement("div", { ref: ref, className: b('container'), id: id }, children))), body);
|
|
42
42
|
};
|
|
43
43
|
exports.NHMobileNavigationPopup = NHMobileNavigationPopup;
|
|
@@ -2,9 +2,12 @@ import type { RefObject } from 'react';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { NHNavigationItemData, SetupRouteChangeHandler } from '../../models';
|
|
4
4
|
interface NavigationProps {
|
|
5
|
+
activeNavigationId: string | null;
|
|
5
6
|
data: NHNavigationItemData[];
|
|
6
7
|
headerRef?: RefObject<HTMLDivElement>;
|
|
8
|
+
navigationId: string;
|
|
7
9
|
setupRouteChangeHandler?: SetupRouteChangeHandler;
|
|
10
|
+
setActiveNavigationId: (navigationId: string | null) => void;
|
|
8
11
|
}
|
|
9
|
-
export declare const NHNavigation: ({ data, headerRef, setupRouteChangeHandler }: NavigationProps) => React.JSX.Element;
|
|
12
|
+
export declare const NHNavigation: ({ activeNavigationId, data, headerRef, navigationId, setupRouteChangeHandler, setActiveNavigationId, }: NavigationProps) => React.JSX.Element;
|
|
10
13
|
export {};
|
|
@@ -9,6 +9,7 @@ const models_1 = require("../../models");
|
|
|
9
9
|
const NHDefaultPopup_1 = require("../NHDefaultPopup/NHDefaultPopup");
|
|
10
10
|
const NHNavigationItem_1 = require("../NHNavigationItem/NHNavigationItem");
|
|
11
11
|
const NHNavigationPopup_1 = require("../NHNavigationPopup/NHNavigationPopup");
|
|
12
|
+
const keyboardNavigation_1 = require("../NHNavigationPopup/keyboardNavigation");
|
|
12
13
|
const b = (0, cn_1.block)('nh-navigation');
|
|
13
14
|
const tooltipPrefixId = 'navigation-item-key';
|
|
14
15
|
const getPopupContent = (sectionData) => {
|
|
@@ -19,37 +20,99 @@ const getPopupContent = (sectionData) => {
|
|
|
19
20
|
return null;
|
|
20
21
|
}
|
|
21
22
|
};
|
|
22
|
-
const NHNavigation = ({ data, headerRef, setupRouteChangeHandler }) => {
|
|
23
|
+
const NHNavigation = ({ activeNavigationId, data, headerRef, navigationId, setupRouteChangeHandler, setActiveNavigationId, }) => {
|
|
23
24
|
const [activeTab, setActiveTab] = (0, react_1.useState)(constants_1.NO_MENU_TAB_SELECTED);
|
|
24
25
|
const [pretendentActiveTab, setPretendentAciveTab] = (0, react_1.useState)(constants_1.NO_MENU_TAB_SELECTED);
|
|
25
26
|
const [previouslyFocusedElement, setPreviouslyFocusedElement] = (0, react_1.useState)(null);
|
|
27
|
+
const [popupTabToFocus, setPopupTabToFocus] = (0, react_1.useState)(null);
|
|
28
|
+
const setNavigationTab = (0, react_1.useCallback)((currentIndex) => {
|
|
29
|
+
setPretendentAciveTab(currentIndex);
|
|
30
|
+
setActiveTab(currentIndex);
|
|
31
|
+
setPopupTabToFocus(null);
|
|
32
|
+
setActiveNavigationId(currentIndex === constants_1.NO_MENU_TAB_SELECTED ? null : navigationId);
|
|
33
|
+
}, [navigationId, setActiveNavigationId]);
|
|
26
34
|
const handleActiveTab = (0, react_1.useCallback)((currentIndex) => {
|
|
27
35
|
setPreviouslyFocusedElement(document.activeElement);
|
|
28
36
|
setPretendentAciveTab(currentIndex);
|
|
29
37
|
}, []);
|
|
38
|
+
const handleToggleTab = (0, react_1.useCallback)((currentIndex) => {
|
|
39
|
+
const focusedElement = document.activeElement;
|
|
40
|
+
const nextActiveTab = activeTab === currentIndex ? constants_1.NO_MENU_TAB_SELECTED : currentIndex;
|
|
41
|
+
setPreviouslyFocusedElement(focusedElement);
|
|
42
|
+
setNavigationTab(nextActiveTab);
|
|
43
|
+
if (nextActiveTab === constants_1.NO_MENU_TAB_SELECTED) {
|
|
44
|
+
focusedElement === null || focusedElement === void 0 ? void 0 : focusedElement.focus({ preventScroll: true });
|
|
45
|
+
}
|
|
46
|
+
}, [activeTab, setNavigationTab]);
|
|
47
|
+
const handleFocusTabPopup = (0, react_1.useCallback)((currentIndex) => {
|
|
48
|
+
setPreviouslyFocusedElement(document.activeElement);
|
|
49
|
+
setPretendentAciveTab(currentIndex);
|
|
50
|
+
setActiveTab(currentIndex);
|
|
51
|
+
setPopupTabToFocus(currentIndex);
|
|
52
|
+
setActiveNavigationId(navigationId);
|
|
53
|
+
}, [navigationId, setActiveNavigationId]);
|
|
54
|
+
const handleFocusTab = (0, react_1.useCallback)((currentIndex) => {
|
|
55
|
+
if (activeNavigationId === null) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
setPreviouslyFocusedElement(document.activeElement);
|
|
59
|
+
setNavigationTab(currentIndex);
|
|
60
|
+
}, [activeNavigationId, setNavigationTab]);
|
|
61
|
+
const handleCloseTab = (0, react_1.useCallback)(() => {
|
|
62
|
+
setNavigationTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
63
|
+
previouslyFocusedElement === null || previouslyFocusedElement === void 0 ? void 0 : previouslyFocusedElement.focus({ preventScroll: true });
|
|
64
|
+
}, [previouslyFocusedElement, setNavigationTab]);
|
|
65
|
+
const handleBlur = (0, react_1.useCallback)((event) => {
|
|
66
|
+
if (activeTab === constants_1.NO_MENU_TAB_SELECTED) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const nextFocusedElement = event.relatedTarget;
|
|
70
|
+
const popup = document.getElementById(`${tooltipPrefixId}-${activeTab}`);
|
|
71
|
+
if (nextFocusedElement &&
|
|
72
|
+
(event.currentTarget.contains(nextFocusedElement) ||
|
|
73
|
+
(popup === null || popup === void 0 ? void 0 : popup.contains(nextFocusedElement)))) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setNavigationTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
77
|
+
}, [activeTab, setNavigationTab]);
|
|
30
78
|
const onEscapeKeyDown = (0, react_1.useCallback)((event) => {
|
|
31
|
-
if (event.key === 'Escape') {
|
|
32
|
-
|
|
33
|
-
setPretendentAciveTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
34
|
-
previouslyFocusedElement === null || previouslyFocusedElement === void 0 ? void 0 : previouslyFocusedElement.focus({ preventScroll: true });
|
|
79
|
+
if (event.key === 'Escape' && activeTab !== constants_1.NO_MENU_TAB_SELECTED) {
|
|
80
|
+
handleCloseTab();
|
|
35
81
|
}
|
|
36
|
-
}, [
|
|
82
|
+
}, [activeTab, handleCloseTab]);
|
|
37
83
|
(0, react_1.useEffect)(() => setupRouteChangeHandler === null || setupRouteChangeHandler === void 0 ? void 0 : setupRouteChangeHandler(() => {
|
|
38
84
|
handleActiveTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
39
85
|
}), [setupRouteChangeHandler, handleActiveTab]);
|
|
40
86
|
(0, react_1.useEffect)(() => {
|
|
41
87
|
const timerId = setTimeout(() => {
|
|
42
88
|
setActiveTab(pretendentActiveTab);
|
|
89
|
+
setActiveNavigationId(pretendentActiveTab === constants_1.NO_MENU_TAB_SELECTED ? null : navigationId);
|
|
43
90
|
}, constants_1.SWITCH_MENU_TAB_TIMEOUT);
|
|
44
91
|
return () => clearTimeout(timerId);
|
|
45
|
-
}, [activeTab, pretendentActiveTab]);
|
|
92
|
+
}, [activeTab, navigationId, pretendentActiveTab, setActiveNavigationId]);
|
|
93
|
+
(0, react_1.useEffect)(() => {
|
|
94
|
+
if (activeNavigationId !== navigationId && activeTab !== constants_1.NO_MENU_TAB_SELECTED) {
|
|
95
|
+
setActiveTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
96
|
+
setPretendentAciveTab(constants_1.NO_MENU_TAB_SELECTED);
|
|
97
|
+
setPopupTabToFocus(null);
|
|
98
|
+
}
|
|
99
|
+
}, [activeNavigationId, activeTab, navigationId]);
|
|
100
|
+
(0, react_1.useEffect)(() => {
|
|
101
|
+
if (popupTabToFocus === null || activeTab !== popupTabToFocus) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const popup = document.getElementById(`${tooltipPrefixId}-${popupTabToFocus}`);
|
|
105
|
+
const [firstFocusableElement] = (0, keyboardNavigation_1.getFocusableElements)(popup);
|
|
106
|
+
(0, keyboardNavigation_1.focusFromKeyboard)(firstFocusableElement, popup);
|
|
107
|
+
setPopupTabToFocus(null);
|
|
108
|
+
}, [activeTab, popupTabToFocus]);
|
|
46
109
|
(0, react_1.useEffect)(() => {
|
|
47
110
|
document.addEventListener('keydown', onEscapeKeyDown);
|
|
48
111
|
return () => {
|
|
49
112
|
document.removeEventListener('keydown', onEscapeKeyDown);
|
|
50
113
|
};
|
|
51
114
|
}, [onEscapeKeyDown]);
|
|
52
|
-
return (react_1.default.createElement("nav",
|
|
53
|
-
react_1.default.createElement("ul", { className: b() }, data.map((item, i) => (react_1.default.createElement(NHNavigationItem_1.NHNavigationItem, { key: i, item: item, handleActiveTab: handleActiveTab, index: i, isActive: activeTab === i, tooltipId: `${tooltipPrefixId}-${i}` }, activeTab === i && item.type !== models_1.NHNavigationItemType.Link && (react_1.default.createElement(NHNavigationPopup_1.NHNavigationPopup, { headerRef: headerRef, id: `${tooltipPrefixId}-${i}` }, getPopupContent(item)))))))));
|
|
115
|
+
return (react_1.default.createElement("nav", { onBlur: handleBlur },
|
|
116
|
+
react_1.default.createElement("ul", { className: b() }, data.map((item, i) => (react_1.default.createElement(NHNavigationItem_1.NHNavigationItem, { key: i, item: item, handleActiveTab: handleActiveTab, handleFocusTabPopup: handleFocusTabPopup, handleFocusTab: handleFocusTab, handleToggleTab: handleToggleTab, index: i, isActive: activeTab === i, tooltipId: `${tooltipPrefixId}-${i}` }, activeTab === i && item.type !== models_1.NHNavigationItemType.Link && (react_1.default.createElement(NHNavigationPopup_1.NHNavigationPopup, { headerRef: headerRef, id: `${tooltipPrefixId}-${i}` }, getPopupContent(item)))))))));
|
|
54
117
|
};
|
|
55
118
|
exports.NHNavigation = NHNavigation;
|
|
@@ -55,6 +55,11 @@ unpredictable css rules order in build */
|
|
|
55
55
|
cursor: default;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
.pc-addons-nh-navigation-item__text:focus-visible {
|
|
59
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
60
|
+
outline-offset: 2px;
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
.pc-addons-nh-navigation-item:first-child .pc-addons-nh-navigation-item__text {
|
|
59
64
|
margin-left: 0;
|
|
60
65
|
}
|
|
@@ -5,6 +5,9 @@ interface NavigationItemOwnProps {
|
|
|
5
5
|
item: NHNavigationItemData;
|
|
6
6
|
isActive: boolean;
|
|
7
7
|
handleActiveTab: (currentIndex: number) => void;
|
|
8
|
+
handleFocusTab: (currentIndex: number) => void;
|
|
9
|
+
handleFocusTabPopup: (currentIndex: number) => void;
|
|
10
|
+
handleToggleTab: (currentIndex: number) => void;
|
|
8
11
|
children?: ReactNode;
|
|
9
12
|
tooltipId?: string;
|
|
10
13
|
}
|
|
@@ -12,21 +12,30 @@ const models_1 = require("../../models");
|
|
|
12
12
|
const ChevronDown_1 = require("../ChevronDown");
|
|
13
13
|
const ChevronUp_1 = require("../ChevronUp");
|
|
14
14
|
const b = (0, cn_1.block)('nh-navigation-item');
|
|
15
|
-
const NHNavigationItem = ({ item, isActive, handleActiveTab, index, children, tooltipId, }) => {
|
|
15
|
+
const NHNavigationItem = ({ item, isActive, handleActiveTab, handleFocusTab, handleFocusTabPopup, handleToggleTab, index, children, tooltipId, }) => {
|
|
16
16
|
var _a, _b, _c, _d;
|
|
17
17
|
const setupRouteChangeHandler = (0, react_1.useContext)(route_change_1.RouteChangeHandlerContext);
|
|
18
18
|
const handleMouseEnter = (0, react_1.useCallback)(() => handleActiveTab(index), [handleActiveTab, index]);
|
|
19
19
|
const handleMouseLeave = (0, react_1.useCallback)(() => handleActiveTab(constants_1.NO_MENU_TAB_SELECTED), [handleActiveTab]);
|
|
20
|
+
const handleToggle = (0, react_1.useCallback)(() => handleToggleTab(index), [handleToggleTab, index]);
|
|
21
|
+
const handlePopupFocus = (0, react_1.useCallback)(() => handleFocusTab(index), [handleFocusTab, index]);
|
|
22
|
+
const handleLinkFocus = (0, react_1.useCallback)(() => handleFocusTab(constants_1.NO_MENU_TAB_SELECTED), [handleFocusTab]);
|
|
23
|
+
const handleKeyDown = (0, react_1.useCallback)((event) => {
|
|
24
|
+
if (event.key === 'ArrowDown') {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
handleFocusTabPopup(index);
|
|
27
|
+
}
|
|
28
|
+
}, [handleFocusTabPopup, index]);
|
|
20
29
|
(0, react_1.useEffect)(() => setupRouteChangeHandler === null || setupRouteChangeHandler === void 0 ? void 0 : setupRouteChangeHandler(() => {
|
|
21
30
|
handleMouseLeave();
|
|
22
31
|
}), [handleMouseLeave, setupRouteChangeHandler]);
|
|
23
32
|
if (item.type === models_1.NHNavigationItemType.Link) {
|
|
24
33
|
return (react_1.default.createElement("li", { className: b({ disable: !((_a = item.data) === null || _a === void 0 ? void 0 : _a.url) }), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
|
|
25
|
-
react_1.default.createElement("a", Object.assign({ className: b('text', { active: isActive }), href: (_b = item.data) === null || _b === void 0 ? void 0 : _b.url }, (0, gravity_ui_page_constructor_1.getLinkProps)(((_c = item.data) === null || _c === void 0 ? void 0 : _c.url) || '', undefined, (_d = item.data) === null || _d === void 0 ? void 0 : _d.target)), item.title),
|
|
34
|
+
react_1.default.createElement("a", Object.assign({ className: b('text', { active: isActive }), href: (_b = item.data) === null || _b === void 0 ? void 0 : _b.url, onFocus: handleLinkFocus }, (0, gravity_ui_page_constructor_1.getLinkProps)(((_c = item.data) === null || _c === void 0 ? void 0 : _c.url) || '', undefined, (_d = item.data) === null || _d === void 0 ? void 0 : _d.target)), item.title),
|
|
26
35
|
children));
|
|
27
36
|
}
|
|
28
37
|
return (react_1.default.createElement("li", { className: b({}), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
|
|
29
|
-
react_1.default.createElement("button", { className: b('text', { active: isActive, cursor: 'default' }), onClick:
|
|
38
|
+
react_1.default.createElement("button", { className: b('text', { active: isActive, cursor: 'default' }), type: "button", onClick: handleToggle, onFocus: handlePopupFocus, onKeyDown: handleKeyDown, "aria-expanded": isActive, "aria-controls": tooltipId },
|
|
30
39
|
item.title,
|
|
31
40
|
react_1.default.createElement(uikit_1.Icon, { className: b('icon'), data: isActive ? ChevronUp_1.ChevronUp : ChevronDown_1.ChevronDown, size: 16 })),
|
|
32
41
|
children));
|
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
z-index: 10;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.pc-addons-nh-navigation-popup:focus
|
|
12
|
-
|
|
11
|
+
.pc-addons-nh-navigation-popup a:focus-visible, .pc-addons-nh-navigation-popup a[data-keyboard-focus=true],
|
|
12
|
+
.pc-addons-nh-navigation-popup button:focus-visible,
|
|
13
|
+
.pc-addons-nh-navigation-popup button[data-keyboard-focus=true],
|
|
14
|
+
.pc-addons-nh-navigation-popup input:focus-visible,
|
|
15
|
+
.pc-addons-nh-navigation-popup input[data-keyboard-focus=true],
|
|
16
|
+
.pc-addons-nh-navigation-popup select:focus-visible,
|
|
17
|
+
.pc-addons-nh-navigation-popup select[data-keyboard-focus=true],
|
|
18
|
+
.pc-addons-nh-navigation-popup textarea:focus-visible,
|
|
19
|
+
.pc-addons-nh-navigation-popup textarea[data-keyboard-focus=true],
|
|
20
|
+
.pc-addons-nh-navigation-popup [tabindex]:not([tabindex="-1"]):focus-visible,
|
|
21
|
+
.pc-addons-nh-navigation-popup [tabindex]:not([tabindex="-1"])[data-keyboard-focus=true] {
|
|
22
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
23
|
+
outline-offset: 4px;
|
|
13
24
|
}
|
|
@@ -2,17 +2,69 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NHNavigationPopup = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const react_1 = tslib_1.
|
|
5
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
6
6
|
const react_dom_1 = tslib_1.__importDefault(require("react-dom"));
|
|
7
|
-
const FocusTrap_1 = require("../../../../utils/FocusTrap");
|
|
8
7
|
const cn_1 = require("../../../../utils/cn");
|
|
8
|
+
const keyboardNavigation_1 = require("./keyboardNavigation");
|
|
9
9
|
const b = (0, cn_1.block)('nh-navigation-popup');
|
|
10
|
+
const nextKeys = new Set(['ArrowDown', 'ArrowRight']);
|
|
11
|
+
const previousKeys = new Set(['ArrowUp', 'ArrowLeft']);
|
|
12
|
+
const getNextIndex = (currentIndex, offset, elementsCount) => {
|
|
13
|
+
if (currentIndex === -1) {
|
|
14
|
+
return offset > 0 ? 0 : elementsCount - 1;
|
|
15
|
+
}
|
|
16
|
+
return (currentIndex + offset + elementsCount) % elementsCount;
|
|
17
|
+
};
|
|
10
18
|
const NHNavigationPopup = ({ headerRef, children, id }) => {
|
|
19
|
+
const popupRef = (0, react_1.useRef)(null);
|
|
20
|
+
const focusRelativeElement = (0, react_1.useCallback)((offset) => {
|
|
21
|
+
const popup = popupRef.current;
|
|
22
|
+
const focusableElements = (0, keyboardNavigation_1.getFocusableElements)(popup);
|
|
23
|
+
if (!popup || !focusableElements.length) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const activeElement = popup.ownerDocument.activeElement;
|
|
27
|
+
const currentIndex = activeElement ? focusableElements.indexOf(activeElement) : -1;
|
|
28
|
+
const nextIndex = getNextIndex(currentIndex, offset, focusableElements.length);
|
|
29
|
+
(0, keyboardNavigation_1.focusFromKeyboard)(focusableElements[nextIndex], popup);
|
|
30
|
+
}, []);
|
|
31
|
+
(0, react_1.useEffect)(() => {
|
|
32
|
+
const popup = popupRef.current;
|
|
33
|
+
if (!popup) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const handleKeyDown = (event) => {
|
|
37
|
+
if (event.key === 'Tab') {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
focusRelativeElement(event.shiftKey ? -1 : 1);
|
|
40
|
+
}
|
|
41
|
+
else if (nextKeys.has(event.key)) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
focusRelativeElement(1);
|
|
44
|
+
}
|
|
45
|
+
else if (previousKeys.has(event.key)) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
focusRelativeElement(-1);
|
|
48
|
+
}
|
|
49
|
+
else if (event.key === 'Home') {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
const popupElement = popupRef.current;
|
|
52
|
+
(0, keyboardNavigation_1.focusFromKeyboard)((0, keyboardNavigation_1.getFocusableElements)(popupElement)[0], popupElement);
|
|
53
|
+
}
|
|
54
|
+
else if (event.key === 'End') {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
const popupElement = popupRef.current;
|
|
57
|
+
const focusableElements = (0, keyboardNavigation_1.getFocusableElements)(popupElement);
|
|
58
|
+
(0, keyboardNavigation_1.focusFromKeyboard)(focusableElements[focusableElements.length - 1], popupElement);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
popup.addEventListener('keydown', handleKeyDown);
|
|
62
|
+
return () => {
|
|
63
|
+
popup.removeEventListener('keydown', handleKeyDown);
|
|
64
|
+
};
|
|
65
|
+
}, [focusRelativeElement]);
|
|
11
66
|
return (headerRef === null || headerRef === void 0 ? void 0 : headerRef.current)
|
|
12
|
-
? react_dom_1.default.createPortal(react_1.default.createElement(
|
|
13
|
-
react_1.default.createElement("div", {
|
|
14
|
-
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
|
15
|
-
tabIndex: 0, className: b(), id: id }, children)), headerRef.current)
|
|
67
|
+
? react_dom_1.default.createPortal(react_1.default.createElement("div", { className: b(), id: id, ref: popupRef }, children), headerRef.current)
|
|
16
68
|
: null;
|
|
17
69
|
};
|
|
18
70
|
exports.NHNavigationPopup = NHNavigationPopup;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const keyboardFocusAttribute = "data-keyboard-focus";
|
|
2
|
+
export declare const focusableElementSelector: string;
|
|
3
|
+
export declare const getFocusableElements: (root?: HTMLElement | null) => HTMLElement[];
|
|
4
|
+
export declare const focusFromKeyboard: (element?: HTMLElement | null, root?: ParentNode | null) => void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.focusFromKeyboard = exports.getFocusableElements = exports.focusableElementSelector = exports.keyboardFocusAttribute = void 0;
|
|
4
|
+
exports.keyboardFocusAttribute = 'data-keyboard-focus';
|
|
5
|
+
exports.focusableElementSelector = [
|
|
6
|
+
'a[href]',
|
|
7
|
+
'button:not([disabled])',
|
|
8
|
+
'input:not([disabled])',
|
|
9
|
+
'select:not([disabled])',
|
|
10
|
+
'textarea:not([disabled])',
|
|
11
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
12
|
+
].join(',');
|
|
13
|
+
const keyboardFocusSelector = `[${exports.keyboardFocusAttribute}='true']`;
|
|
14
|
+
const blurHandlers = new WeakMap();
|
|
15
|
+
const clearKeyboardFocus = (root) => {
|
|
16
|
+
root.querySelectorAll(keyboardFocusSelector).forEach((element) => {
|
|
17
|
+
const blurHandler = blurHandlers.get(element);
|
|
18
|
+
if (blurHandler) {
|
|
19
|
+
element.removeEventListener('blur', blurHandler);
|
|
20
|
+
blurHandlers.delete(element);
|
|
21
|
+
}
|
|
22
|
+
element.removeAttribute(exports.keyboardFocusAttribute);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const getFocusableElements = (root) => Array.from((root === null || root === void 0 ? void 0 : root.querySelectorAll(exports.focusableElementSelector)) || []);
|
|
26
|
+
exports.getFocusableElements = getFocusableElements;
|
|
27
|
+
const focusFromKeyboard = (element, root) => {
|
|
28
|
+
if (!element) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const focusRoot = root || element.ownerDocument;
|
|
32
|
+
const handleBlur = () => {
|
|
33
|
+
element.removeAttribute(exports.keyboardFocusAttribute);
|
|
34
|
+
element.removeEventListener('blur', handleBlur);
|
|
35
|
+
blurHandlers.delete(element);
|
|
36
|
+
};
|
|
37
|
+
clearKeyboardFocus(focusRoot);
|
|
38
|
+
element.setAttribute(exports.keyboardFocusAttribute, 'true');
|
|
39
|
+
element.addEventListener('blur', handleBlur);
|
|
40
|
+
blurHandlers.set(element, handleBlur);
|
|
41
|
+
element.focus({ preventScroll: true });
|
|
42
|
+
};
|
|
43
|
+
exports.focusFromKeyboard = focusFromKeyboard;
|
|
@@ -57,6 +57,11 @@ unpredictable css rules order in build */
|
|
|
57
57
|
opacity: 1;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
.pc-addons-nh-navigation-popup-item:focus, .pc-addons-nh-navigation-popup-item:focus-visible, .pc-addons-nh-navigation-popup-item[data-keyboard-focus=true] {
|
|
61
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
62
|
+
outline-offset: 4px;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
.pc-addons-nh-navigation-popup-item_disable {
|
|
61
66
|
pointer-events: none;
|
|
62
67
|
}
|
|
@@ -5,9 +5,8 @@ import './GroupLinks.css';
|
|
|
5
5
|
const b = block('group-links');
|
|
6
6
|
const GroupLinks = ({ columnGroup: { title, items }, className }) => {
|
|
7
7
|
return (React.createElement("div", { className: b(null, className), key: title },
|
|
8
|
-
React.createElement("
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
React.createElement(EnrichedLink, Object.assign({ className: b('item') }, item))))))));
|
|
8
|
+
title && React.createElement("h5", { className: b('group-title') }, title),
|
|
9
|
+
React.createElement("ul", { className: b('group'), "aria-label": title }, items.map((item) => (React.createElement("li", { key: item.title, className: b('item-wrapper') },
|
|
10
|
+
React.createElement(EnrichedLink, Object.assign({ className: b('item') }, item))))))));
|
|
12
11
|
};
|
|
13
12
|
export default GroupLinks;
|
|
@@ -172,6 +172,11 @@ unpredictable css rules order in build */
|
|
|
172
172
|
border-color: rgba(5, 43, 66, 0.25);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
.pc-addons-new-header__button:focus-visible {
|
|
176
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
177
|
+
outline-offset: 2px;
|
|
178
|
+
}
|
|
179
|
+
|
|
175
180
|
@media (max-width: 1081px) {
|
|
176
181
|
.pc-addons-new-header__left {
|
|
177
182
|
margin-right: 0;
|