mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
322a14fe6e
commit
1c34cc8b91
@ -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({
|
||||
|
@ -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,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
41
public/app/core/components/NavBar/Next/NavBarToggle.tsx
Normal file
41
public/app/core/components/NavBar/Next/NavBarToggle.tsx
Normal 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',
|
||||
},
|
||||
}),
|
||||
});
|
Loading…
Reference in New Issue
Block a user