Navigation: Put expand toggle at beginning of tab order (#47268)

* Put toggle at beginning of tab order

* create NavBarToggle

* move margin into the common component

* lint fixes
This commit is contained in:
Ashley Harrison 2022-04-04 16:51:24 +01:00 committed by GitHub
parent 322a14fe6e
commit 1c34cc8b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 31 deletions

View File

@ -8,21 +8,23 @@ import { css, cx } from '@emotion/css';
import { NavBarMenuItem } from './NavBarMenuItem';
import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu';
import { isMatchOrChildMatch } from '../utils';
import { NavBarToggle } from './NavBarToggle';
export interface Props {
activeItem?: NavModelItem;
isOpen: boolean;
navItems: NavModelItem[];
onClose: () => void;
}
export function NavBarMenu({ activeItem, navItems, onClose }: Props) {
export function NavBarMenu({ activeItem, isOpen, navItems, onClose }: Props) {
const styles = useStyles2(getStyles);
const ref = useRef(null);
const { dialogProps } = useDialog({}, ref);
const { overlayProps } = useOverlay(
{
isDismissable: true,
isOpen: true,
isOpen,
onClose,
},
ref
@ -32,6 +34,7 @@ export function NavBarMenu({ activeItem, navItems, onClose }: Props) {
<div data-testid="navbarmenu" className={styles.container}>
<FocusScope contain restoreFocus autoFocus>
<nav className={styles.content} ref={ref} {...overlayProps} {...dialogProps}>
<NavBarToggle className={styles.menuCollapseIcon} isExpanded={isOpen} onClick={onClose} />
<CustomScrollbar hideHorizontalTrack>
<ul className={styles.itemList}>
{navItems.map((link) => (
@ -75,6 +78,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
display: 'grid',
gridAutoRows: `minmax(${theme.spacing(6)}, auto)`,
}),
menuCollapseIcon: css({
position: 'absolute',
top: '43px',
right: '0px',
}),
});
function NavItem({

View File

@ -4,7 +4,7 @@ import CSSTransition from 'react-transition-group/CSSTransition';
import { css, cx } from '@emotion/css';
import { cloneDeep } from 'lodash';
import { GrafanaTheme2, NavModelItem, NavSection } from '@grafana/data';
import { Icon, IconButton, IconName, useStyles2, useTheme2 } from '@grafana/ui';
import { Icon, IconName, useStyles2, useTheme2 } from '@grafana/ui';
import { config, locationService } from '@grafana/runtime';
import { getKioskMode } from 'app/core/navigation/kiosk';
import { KioskMode, StoreState } from 'app/types';
@ -16,6 +16,7 @@ import { useSelector } from 'react-redux';
import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu';
import { FocusScope } from '@react-aria/focus';
import { NavBarContext } from '../context';
import { NavBarToggle } from './NavBarToggle';
const onOpenSearch = () => {
locationService.partial({ search: 'open' });
@ -79,6 +80,12 @@ export const NavBarNext = React.memo(() => {
<Icon name="bars" size="xl" />
</div>
<NavBarToggle
className={styles.menuExpandIcon}
isExpanded={menuOpen}
onClick={() => setMenuOpen(!menuOpen)}
/>
<ul className={styles.itemList}>
<NavBarItemWithoutMenu
isActive={isMatchOrChildMatch(homeItem, activeItem)}
@ -132,16 +139,11 @@ export const NavBarNext = React.memo(() => {
<CSSTransition in={menuOpen} classNames={animStyles} timeout={150} unmountOnExit>
<NavBarMenu
activeItem={activeItem}
isOpen={menuOpen}
navItems={[homeItem, searchItem, ...coreItems, ...pluginItems, ...configItems]}
onClose={() => setMenuOpen(false)}
/>
</CSSTransition>
<IconButton
name={menuOpen ? 'angle-left' : 'angle-right'}
className={styles.menuToggle}
size="xl"
onClick={() => setMenuOpen(!menuOpen)}
/>
</div>
</div>
);
@ -233,20 +235,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
height: '100%',
zIndex: theme.zIndex.sidemenu,
}),
menuToggle: css({
backgroundColor: theme.colors.background.secondary,
border: `1px solid ${theme.colors.border.weak}`,
menuExpandIcon: css({
position: 'absolute',
marginRight: 0,
top: '43px',
right: '0px',
zIndex: theme.zIndex.sidemenu,
transform: `translateX(calc(${theme.spacing(7)} + 50%))`,
borderRadius: '50%',
[theme.breakpoints.down('md')]: {
display: 'none',
},
transform: `translateX(50%)`,
}),
});
@ -267,34 +260,23 @@ const getAnimStyles = (theme: GrafanaTheme2) => {
width: theme.spacing(7),
};
const buttonShift = {
'& + button': {
transform: 'translateX(0%)',
},
};
return {
enter: css({
...closedStyles,
...buttonShift,
}),
enterActive: css({
...transitionProps,
...openStyles,
...buttonShift,
}),
enterDone: css({
...openStyles,
...buttonShift,
}),
exit: css({
...openStyles,
...buttonShift,
}),
exitActive: css({
...transitionProps,
...closedStyles,
...buttonShift,
}),
};
};

View File

@ -0,0 +1,41 @@
import React from 'react';
import { IconButton, useTheme2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { css } from '@emotion/css';
import classnames from 'classnames';
export interface Props {
className?: string;
isExpanded: boolean;
onClick: () => void;
}
export const NavBarToggle = ({ className, isExpanded, onClick }: Props) => {
const theme = useTheme2();
const styles = getStyles(theme);
return (
<IconButton
name={isExpanded ? 'angle-left' : 'angle-right'}
className={classnames(className, styles.icon)}
size="xl"
onClick={onClick}
/>
);
};
NavBarToggle.displayName = 'NavBarToggle';
const getStyles = (theme: GrafanaTheme2) => ({
icon: css({
backgroundColor: theme.colors.background.secondary,
border: `1px solid ${theme.colors.border.weak}`,
borderRadius: '50%',
marginRight: 0,
zIndex: theme.zIndex.sidemenu,
[theme.breakpoints.down('md')]: {
display: 'none',
},
}),
});