diff --git a/public/app/core/components/NavBar/Next/NavBarMenu.tsx b/public/app/core/components/NavBar/Next/NavBarMenu.tsx index e564373139b..14c77ebd420 100644 --- a/public/app/core/components/NavBar/Next/NavBarMenu.tsx +++ b/public/app/core/components/NavBar/Next/NavBarMenu.tsx @@ -4,7 +4,7 @@ import { CollapsableSection, CustomScrollbar, Icon, IconName, useStyles2 } from import { FocusScope } from '@react-aria/focus'; import { useDialog } from '@react-aria/dialog'; import { useOverlay } from '@react-aria/overlays'; -import { css, cx, keyframes } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import { NavBarMenuItem } from './NavBarMenuItem'; import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu'; import { isMatchOrChildMatch } from '../utils'; @@ -29,9 +29,9 @@ export function NavBarMenu({ activeItem, navItems, onClose }: Props) { ); return ( - -
-
); } NavBarMenu.displayName = 'NavBarMenu'; -const getStyles = (theme: GrafanaTheme2) => { - const fadeIn = keyframes` - from { - background-color: ${theme.colors.background.primary}; - width: ${theme.spacing(7)}; - } - to { - background-color: ${theme.colors.background.canvas}; - width: 300px; - }`; - - return { - container: css({ - animation: `150ms ease-in 0s 1 normal forwards ${fadeIn}`, - bottom: 0, - display: 'flex', - flexDirection: 'column', - left: 0, - whiteSpace: 'nowrap', - paddingTop: theme.spacing(1), - marginRight: theme.spacing(1.5), - right: 0, - zIndex: theme.zIndex.sidemenu, - top: 0, - [theme.breakpoints.up('md')]: { - borderRight: `1px solid ${theme.colors.border.weak}`, - right: 'unset', - }, - }), - content: css({ - display: 'flex', - flexDirection: 'column', - overflow: 'auto', - }), - itemList: css({ - display: 'grid', - gridAutoRows: `minmax(${theme.spacing(6)}, auto)`, - }), - }; -}; +const getStyles = (theme: GrafanaTheme2) => ({ + container: css({ + bottom: 0, + display: 'flex', + flexDirection: 'column', + left: 0, + whiteSpace: 'nowrap', + paddingTop: theme.spacing(1), + marginRight: theme.spacing(1.5), + right: 0, + zIndex: theme.zIndex.sidemenu, + top: 0, + [theme.breakpoints.up('md')]: { + borderRight: `1px solid ${theme.colors.border.weak}`, + right: 'unset', + }, + }), + content: css({ + display: 'flex', + flexDirection: 'column', + overflow: 'auto', + }), + itemList: css({ + display: 'grid', + gridAutoRows: `minmax(${theme.spacing(6)}, auto)`, + }), +}); function NavItem({ link, diff --git a/public/app/core/components/NavBar/Next/NavBarNext.tsx b/public/app/core/components/NavBar/Next/NavBarNext.tsx index 7a228cfaba9..6472b150eb5 100644 --- a/public/app/core/components/NavBar/Next/NavBarNext.tsx +++ b/public/app/core/components/NavBar/Next/NavBarNext.tsx @@ -1,9 +1,10 @@ import React, { useState } from 'react'; import { useLocation } from 'react-router-dom'; +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, useTheme2 } from '@grafana/ui'; +import { Icon, IconButton, 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'; @@ -37,6 +38,7 @@ export const NavBarNext = React.memo(() => { const navBarTree = useSelector((state: StoreState) => state.navBarTree); const theme = useTheme2(); const styles = getStyles(theme); + const animStyles = useStyles2(getAnimStyles); const location = useLocation(); const kiosk = getKioskMode(); const [showSwitcherModal, setShowSwitcherModal] = useState(false); @@ -115,16 +117,16 @@ export const NavBarNext = React.memo(() => { {showSwitcherModal && }
- {menuOpen && ( + setMenuOpen(false)} /> - )} + setMenuOpen(!menuOpen)} /> @@ -233,7 +235,53 @@ const getStyles = (theme: GrafanaTheme2) => ({ display: 'none', }, }), - menuOpen: css({ - transform: 'translateX(0%)', - }), }); + +const getAnimStyles = (theme: GrafanaTheme2) => { + const transitionProps = { + transitionProperty: 'width, background-color', + transitionDuration: '150ms', + transitionTimingFunction: 'ease-in-out', + }; + + const openStyles = { + backgroundColor: theme.colors.background.canvas, + width: '300px', + }; + + const closedStyles = { + backgroundColor: theme.colors.background.primary, + 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, + }), + }; +};