Navigation: Fixes closing submenus on scrolling (#48207)

pull/48403/head
Joao Silva 3 years ago committed by GitHub
parent ab144bf05e
commit cc114e24ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      public/app/core/components/NavBar/Next/NavBarItemMenu.tsx
  2. 98
      public/app/core/components/NavBar/Next/NavBarItemMenuItem.tsx
  3. 3
      public/app/core/components/NavBar/Next/NavBarItemMenuTrigger.tsx

@ -8,10 +8,11 @@ import React, { ReactElement, useEffect, useRef } from 'react';
import { GrafanaTheme2, NavMenuItemType, NavModelItem } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
import { NavBarItemMenuItem } from '../NavBarItemMenuItem';
import { useNavBarItemMenuContext } from '../context';
import { getNavModelItemKey } from '../utils';
import { NavBarItemMenuItem } from './NavBarItemMenuItem';
export interface NavBarItemMenuProps extends SpectrumMenuProps<NavModelItem> {
onNavigate: (item: NavModelItem) => void;
adjustHeightForBorder: boolean;

@ -0,0 +1,98 @@
import { css } from '@emotion/css';
import { useFocus, useKeyboard } from '@react-aria/interactions';
import { useMenuItem } from '@react-aria/menu';
import { mergeProps } from '@react-aria/utils';
import { TreeState } from '@react-stately/tree';
import { Node } from '@react-types/shared';
import React, { ReactElement, useRef, useState } from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
import { useNavBarItemMenuContext, useNavBarContext } from '../context';
export interface NavBarItemMenuItemProps {
item: Node<NavModelItem>;
state: TreeState<NavModelItem>;
onNavigate: (item: NavModelItem) => void;
}
export function NavBarItemMenuItem({ item, state, onNavigate }: NavBarItemMenuItemProps): ReactElement {
const { onClose, onLeft } = useNavBarItemMenuContext();
const { setMenuIdOpen } = useNavBarContext();
const { key, rendered } = item;
const ref = useRef<HTMLLIElement>(null);
const isDisabled = state.disabledKeys.has(key);
// style to the focused menu item
const [isFocused, setFocused] = useState(false);
const { focusProps } = useFocus({ onFocusChange: setFocused, isDisabled });
const theme = useTheme2();
const isSection = item.value.menuItemType === 'section';
const styles = getStyles(theme, isFocused, isSection);
const onAction = () => {
setMenuIdOpen(undefined);
onNavigate(item.value);
onClose();
};
let { menuItemProps } = useMenuItem(
{
isDisabled,
'aria-label': item['aria-label'],
key,
closeOnSelect: true,
onClose,
onAction,
},
state,
ref
);
const { keyboardProps } = useKeyboard({
onKeyDown: (e) => {
if (e.key === 'ArrowLeft') {
onLeft();
}
e.continuePropagation();
},
});
return (
<>
<li {...mergeProps(menuItemProps, focusProps, keyboardProps)} ref={ref} className={styles.menuItem}>
{rendered}
</li>
</>
);
}
function getStyles(theme: GrafanaTheme2, isFocused: boolean, isSection: boolean) {
let backgroundColor = 'transparent';
if (isFocused) {
backgroundColor = theme.colors.action.hover;
} else if (isSection) {
backgroundColor = theme.colors.background.secondary;
}
return {
menuItem: css`
background-color: ${backgroundColor};
color: ${theme.colors.text.primary};
&:focus-visible {
background-color: ${theme.colors.action.hover};
box-shadow: none;
color: ${theme.colors.text.primary};
outline: 2px solid ${theme.colors.primary.main};
outline-offset: -2px;
transition: none;
}
`,
upgradeBoxContainer: css`
padding: ${theme.spacing(1)};
`,
upgradeBox: css`
width: 300px;
`,
};
}

@ -60,8 +60,7 @@ 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 !== item.id || !state.isOpen) {
if (menuIdOpen !== item.id) {
state.close();
setMenuHasFocus(false);
} else {

Loading…
Cancel
Save