mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 08:35:43 -06:00
Navigation: Keeps nav item hover when hovering over the item menu (#47281)
This commit is contained in:
parent
c1c78bbc32
commit
d311a3bef5
@ -12,6 +12,7 @@ import { NavBarItemMenu } from './NavBarItemMenu';
|
||||
import { getNavModelItemKey } from '../utils';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import menuItemTranslations from '../navBarItem-translations';
|
||||
import { useNavBarContext } from '../context';
|
||||
|
||||
export interface Props {
|
||||
isActive?: boolean;
|
||||
@ -33,6 +34,7 @@ const NavBarItem = ({
|
||||
const { i18n } = useLingui();
|
||||
const theme = useTheme2();
|
||||
const menuItems = link.children ?? [];
|
||||
const { menuIdOpen } = useNavBarContext();
|
||||
|
||||
// Spreading `menuItems` here as otherwise we'd be mutating props
|
||||
const menuItemsSorted = reverseMenuDirection ? [...menuItems].reverse() : menuItems;
|
||||
@ -81,7 +83,7 @@ const NavBarItem = ({
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<li className={cx(styles.container, className)}>
|
||||
<li className={cx(styles.container, { [styles.containerHover]: section.id === menuIdOpen }, className)}>
|
||||
<NavBarItemMenuTrigger
|
||||
item={section}
|
||||
isActive={isActive}
|
||||
@ -126,6 +128,10 @@ export default NavBarItem;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2, adjustHeightForBorder: boolean, isActive?: boolean) => ({
|
||||
...getNavBarItemWithoutMenuStyles(theme, isActive),
|
||||
containerHover: css({
|
||||
backgroundColor: theme.colors.action.hover,
|
||||
color: theme.colors.text.primary,
|
||||
}),
|
||||
primaryText: css({
|
||||
color: theme.colors.text.primary,
|
||||
}),
|
||||
|
@ -47,9 +47,10 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
onHoverChange: (isHovering) => {
|
||||
if (isHovering) {
|
||||
state.open();
|
||||
setMenuIdOpen(ref.current?.id || null);
|
||||
setMenuIdOpen(item.id);
|
||||
} else {
|
||||
state.close();
|
||||
setMenuIdOpen(undefined);
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -57,13 +58,13 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
useEffect(() => {
|
||||
// close the menu when changing submenus
|
||||
// or when the state of the overlay changes (i.e hovering outside)
|
||||
if (menuIdOpen !== ref.current?.id || !state.isOpen) {
|
||||
if (menuIdOpen !== item.id || !state.isOpen) {
|
||||
state.close();
|
||||
setMenuHasFocus(false);
|
||||
} else {
|
||||
state.open();
|
||||
}
|
||||
}, [menuIdOpen, state]);
|
||||
}, [menuIdOpen, state, item.id]);
|
||||
|
||||
const { keyboardProps } = useKeyboard({
|
||||
onKeyDown: (e) => {
|
||||
@ -71,11 +72,12 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
case 'ArrowRight':
|
||||
if (!state.isOpen) {
|
||||
state.open();
|
||||
setMenuIdOpen(item.id);
|
||||
}
|
||||
setMenuHasFocus(true);
|
||||
break;
|
||||
case 'Tab':
|
||||
setMenuIdOpen(null);
|
||||
setMenuIdOpen(undefined);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -142,7 +144,10 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
const { dialogProps } = useDialog({}, overlayRef);
|
||||
const { overlayProps } = useOverlay(
|
||||
{
|
||||
onClose: () => state.close(),
|
||||
onClose: () => {
|
||||
state.close();
|
||||
setMenuIdOpen(undefined);
|
||||
},
|
||||
isOpen: state.isOpen,
|
||||
isDismissable: true,
|
||||
},
|
||||
@ -160,7 +165,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
onFocusWithin: (e) => {
|
||||
if (e.target.id === ref.current?.id) {
|
||||
// If focussing on the trigger itself, set the menu id that is open
|
||||
setMenuIdOpen(ref.current?.id);
|
||||
setMenuIdOpen(item.id);
|
||||
state.open();
|
||||
}
|
||||
},
|
||||
@ -168,7 +173,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
||||
if (e.target?.getAttribute('role') === 'menuitem' && !overlayRef.current?.contains(e.relatedTarget)) {
|
||||
// If it is blurring from a menuitem to an element outside the current overlay
|
||||
// close the menu that is open
|
||||
setMenuIdOpen(null);
|
||||
setMenuIdOpen(undefined);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -59,7 +59,7 @@ export const NavBarNext = React.memo(() => {
|
||||
const activeItem = isSearchActive(location) ? searchItem : getActiveItem(navTree, location.pathname);
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [menuAnimationInProgress, setMenuAnimationInProgress] = useState(false);
|
||||
const [menuIdOpen, setMenuIdOpen] = useState<string | null>(null);
|
||||
const [menuIdOpen, setMenuIdOpen] = useState<string | undefined>(undefined);
|
||||
|
||||
if (kiosk !== KioskMode.Off) {
|
||||
return null;
|
||||
|
@ -18,12 +18,12 @@ export function useNavBarItemMenuContext(): NavBarItemMenuContextProps {
|
||||
}
|
||||
|
||||
export interface NavBarContextProps {
|
||||
menuIdOpen: string | null;
|
||||
setMenuIdOpen: (id: string | null) => void;
|
||||
menuIdOpen: string | undefined;
|
||||
setMenuIdOpen: (id: string | undefined) => void;
|
||||
}
|
||||
|
||||
export const NavBarContext = createContext<NavBarContextProps>({
|
||||
menuIdOpen: null,
|
||||
menuIdOpen: undefined,
|
||||
setMenuIdOpen: () => undefined,
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user