Skip to content

Commit 739aeea

Browse files
committed
update docs, add click/keydown handling, add tooltips, add aria-labels, fix breakpoint
1 parent c98086f commit 739aeea

4 files changed

Lines changed: 106 additions & 10 deletions

File tree

packages/react-core/src/components/Nav/examples/Nav.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ A flyout should be a `Menu` component. Press `space` or `right arrow` to open a
8484

8585
### Docked
8686

87-
The docked variant of `Navigation` displays only icons passed to child `NavItems` or `NavExpandable`. Text becomes visible when `.pf-m-text-expanded` or `.pf-m-expandable-expanded` are applied to an outer page or compass dock.
87+
The docked variant of `Navigation` displays only icons passed to child `NavItems` or `NavExpandable`. Text becomes visible when `isDockTextExpanded` or `isDockExpandableExpanded` are applied to an outer page or compass dock.
8888

8989
`NavExpandable` items should include the `hasExpandableIcon` prop to indicate their expandable nature while in the collapsed state of the docked nav as the caret will not be rendered.
9090

packages/react-core/src/demos/Compass/examples/CompassDockDemo.tsx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,46 @@ export const CompassDockDemo: React.FunctionComponent = () => {
6868
return () => mediaQuery.removeEventListener('change', handleResize);
6969
}, []);
7070

71+
const handleDockClickOutside = (event: MouseEvent) => {
72+
if ((!isMobile && !isDockExpandableExpanded) || (isMobile && !isDockExpanded)) {
73+
return;
74+
}
75+
76+
const dockedMastheadElement = document.getElementById('docked-masthead');
77+
const dockedMobileMasthead = document.getElementById('mobile-masthead');
78+
79+
if (
80+
dockedMastheadElement &&
81+
!dockedMastheadElement.contains(event.target as Node) &&
82+
!dockedMobileMasthead?.contains(event.target as Node) &&
83+
(isDockExpandableExpanded || isDockExpanded)
84+
) {
85+
setIsDockExpandableExpanded(false);
86+
setIsDockExpanded(false);
87+
}
88+
};
89+
90+
const handleDockKeydown = (_event: KeyboardEvent) => {
91+
if ((!isMobile && !isDockExpandableExpanded) || (isMobile && !isDockExpanded)) {
92+
return;
93+
}
94+
95+
if (_event.key === 'Escape') {
96+
setIsDockExpandableExpanded(false);
97+
setIsDockExpanded(false);
98+
}
99+
};
100+
101+
useEffect(() => {
102+
window.addEventListener('click', handleDockClickOutside);
103+
window.addEventListener('keydown', handleDockKeydown);
104+
105+
return () => {
106+
window.removeEventListener('click', handleDockClickOutside);
107+
window.removeEventListener('keydown', handleDockKeydown);
108+
};
109+
}, [isDockExpandableExpanded, isDockTextExpanded, isDockExpanded, isMobile]);
110+
71111
const onNavSelect = (_event: React.FormEvent<HTMLInputElement>, selectedItem: NavOnSelectProps) => {
72112
typeof selectedItem.itemId === 'number' && setActiveItem(selectedItem.itemId);
73113

@@ -81,6 +121,8 @@ export const CompassDockDemo: React.FunctionComponent = () => {
81121
const navItem2Ref = useRef<HTMLAnchorElement>(null);
82122
const navItem3Ref = useRef<HTMLAnchorElement>(null);
83123
const navItem4Ref = useRef<HTMLAnchorElement>(null);
124+
const navItem5Ref = useRef<HTMLAnchorElement>(null);
125+
const navItem6Ref = useRef<HTMLAnchorElement>(null);
84126
const settingsRef = useRef<HTMLButtonElement>(null);
85127
const helpRef = useRef<HTMLButtonElement>(null);
86128
const appsRef = useRef<HTMLButtonElement>(null);
@@ -305,11 +347,13 @@ export const CompassDockDemo: React.FunctionComponent = () => {
305347
System panel
306348
</NavItem>
307349
<NavExpandable
308-
title="Policy"
350+
title="Folder"
309351
groupId={4}
310352
isExpanded={isNavGroupExpanded}
311353
icon={<RhUiFolderIcon />}
312354
hasExpandableIcon={!isMobile}
355+
buttonProps={{ ref: navItem5Ref }}
356+
aria-label="Folder"
313357
>
314358
<NavItem
315359
preventDefault
@@ -319,6 +363,8 @@ export const CompassDockDemo: React.FunctionComponent = () => {
319363
itemId={5}
320364
isActive={activeItem === 5}
321365
icon={<RhUiResourceIcon />}
366+
anchorRef={navItem6Ref}
367+
aria-label="Subnav link 1"
322368
>
323369
Subnav link 1
324370
</NavItem>
@@ -370,6 +416,8 @@ export const CompassDockDemo: React.FunctionComponent = () => {
370416
<Tooltip aria="none" aria-live="off" triggerRef={navItem2Ref} content="Policy"></Tooltip>
371417
<Tooltip aria="none" aria-live="off" triggerRef={navItem3Ref} content="Authentication"></Tooltip>
372418
<Tooltip aria="none" aria-live="off" triggerRef={navItem4Ref} content="Network services"></Tooltip>
419+
<Tooltip aria="none" aria-live="off" triggerRef={navItem5Ref} content="Folder"></Tooltip>
420+
<Tooltip aria="none" aria-live="off" triggerRef={navItem6Ref} content="Subnav link 1"></Tooltip>
373421
</>
374422
)}
375423
</ToolbarItem>

packages/react-core/src/demos/Nav.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import RhMicronsSearchIcon from '@patternfly/react-icons/dist/esm/icons/rh-micro
2020
import pfIconLogo from '@patternfly/react-core/src/demos/assets/PF-IconLogo-color.svg';
2121
import { DashboardBreadcrumb } from '@patternfly/react-core/dist/js/demos/DashboardWrapper';
2222
import { DashboardHeader } from '@patternfly/react-core/dist/js/demos/DashboardHeader';
23-
import globalBreakpointXl from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_xl';
23+
import globalBreakpointLg from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_lg';
2424
import RhUiCubesIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-cubes-icon';
2525
import RhUiFolderIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-folder-icon';
2626
import RhUiResourceIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-resource-icon';

packages/react-core/src/demos/examples/Nav/NavDockedNav.tsx

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import RhUiCubesIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-cubes-ic
4141
import RhUiFolderIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-folder-icon';
4242
import RhUiResourceIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-resource-icon';
4343
import pfIconLogo from '@patternfly/react-core/src/demos/assets/PF-IconLogo-color.svg';
44-
import globalBreakpointXl from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_xl';
44+
import globalBreakpointLg from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_lg';
4545
import { IS_INERT } from '../../../helpers/inert';
4646

4747
interface NavOnSelectProps {
@@ -59,7 +59,7 @@ export const NavDockedNav: React.FunctionComponent = () => {
5959
const [isMobile, setIsMobile] = useState(false);
6060

6161
useEffect(() => {
62-
const mobileBreakpoint = Number.parseInt(globalBreakpointXl.value) * 16;
62+
const mobileBreakpoint = Number.parseInt(globalBreakpointLg.value) * 16;
6363
const mediaQuery = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`);
6464
const handleResize = (e: MediaQueryListEvent | MediaQueryList) => {
6565
setIsMobile(e.matches);
@@ -71,6 +71,46 @@ export const NavDockedNav: React.FunctionComponent = () => {
7171
return () => mediaQuery.removeEventListener('change', handleResize);
7272
}, []);
7373

74+
const handleDockClickOutside = (event: MouseEvent) => {
75+
if ((!isMobile && !isDockExpandableExpanded) || (isMobile && !isDockExpanded)) {
76+
return;
77+
}
78+
79+
const dockedMastheadElement = document.getElementById('docked-masthead');
80+
const dockedMobileMasthead = document.getElementById('mobile-masthead');
81+
82+
if (
83+
dockedMastheadElement &&
84+
!dockedMastheadElement.contains(event.target as Node) &&
85+
!dockedMobileMasthead?.contains(event.target as Node) &&
86+
(isDockExpandableExpanded || isDockExpanded)
87+
) {
88+
setIsDockExpandableExpanded(false);
89+
setIsDockExpanded(false);
90+
}
91+
};
92+
93+
const handleDockKeydown = (_event: KeyboardEvent) => {
94+
if ((!isMobile && !isDockExpandableExpanded) || (isMobile && !isDockExpanded)) {
95+
return;
96+
}
97+
98+
if (_event.key === 'Escape') {
99+
setIsDockExpandableExpanded(false);
100+
setIsDockExpanded(false);
101+
}
102+
};
103+
104+
useEffect(() => {
105+
window.addEventListener('click', handleDockClickOutside);
106+
window.addEventListener('keydown', handleDockKeydown);
107+
108+
return () => {
109+
window.removeEventListener('click', handleDockClickOutside);
110+
window.removeEventListener('keydown', handleDockKeydown);
111+
};
112+
}, [isDockExpandableExpanded, isDockTextExpanded, isDockExpanded, isMobile]);
113+
74114
const onNavSelect = (_event: React.FormEvent<HTMLInputElement>, selectedItem: NavOnSelectProps) => {
75115
typeof selectedItem.itemId === 'number' && setActiveItem(selectedItem.itemId);
76116

@@ -191,6 +231,8 @@ export const NavDockedNav: React.FunctionComponent = () => {
191231
const navItem2Ref = useRef<HTMLAnchorElement>(null);
192232
const navItem3Ref = useRef<HTMLAnchorElement>(null);
193233
const navItem4Ref = useRef<HTMLAnchorElement>(null);
234+
const navItem5Ref = useRef<HTMLAnchorElement>(null);
235+
const navItem6Ref = useRef<HTMLAnchorElement>(null);
194236
const appsRef = useRef<HTMLButtonElement>(null);
195237
const settingsRef = useRef<HTMLButtonElement>(null);
196238
const helpRef = useRef<HTMLButtonElement>(null);
@@ -322,20 +364,24 @@ export const NavDockedNav: React.FunctionComponent = () => {
322364
System panel
323365
</NavItem>
324366
<NavExpandable
325-
title="Policy"
326-
groupId={4}
367+
title="Folder"
368+
groupId="nav-expandable-group-1"
327369
isExpanded={isNavGroupExpanded}
328370
icon={<RhUiFolderIcon />}
329371
hasExpandableIcon={!isMobile}
372+
buttonProps={{ ref: navItem5Ref }}
373+
aria-label="Folder"
330374
>
331375
<NavItem
332376
preventDefault
333-
id="expandable3rd-1"
334-
to="#expandable3rd-1"
335-
groupId="nav-expand3rd-group-1"
377+
id="nav-expandable-item-1"
378+
to="#nav-expandable-item-1"
379+
groupId="nav-expandable-group-1"
336380
itemId={5}
337381
isActive={activeItem === 5}
338382
icon={<RhUiResourceIcon />}
383+
anchorRef={navItem6Ref}
384+
aria-label="Subnav link 1"
339385
>
340386
Subnav link 1
341387
</NavItem>
@@ -384,6 +430,8 @@ export const NavDockedNav: React.FunctionComponent = () => {
384430
<Tooltip aria="none" aria-live="off" triggerRef={navItem2Ref} content="Policy"></Tooltip>
385431
<Tooltip aria="none" aria-live="off" triggerRef={navItem3Ref} content="Authentication"></Tooltip>
386432
<Tooltip aria="none" aria-live="off" triggerRef={navItem4Ref} content="Network services"></Tooltip>
433+
<Tooltip aria="none" aria-live="off" triggerRef={navItem5Ref} content="Folder"></Tooltip>
434+
<Tooltip aria="none" aria-live="off" triggerRef={navItem6Ref} content="Subnav link 1"></Tooltip>
387435
</>
388436
)}
389437
</ToolbarItem>

0 commit comments

Comments
 (0)