diff --git a/public/app/core/components/AppChrome/DockedMegaMenu/MegaMenuItem.tsx b/public/app/core/components/AppChrome/DockedMegaMenu/MegaMenuItem.tsx index 26ee801d35c..11fbe24bbc7 100644 --- a/public/app/core/components/AppChrome/DockedMegaMenu/MegaMenuItem.tsx +++ b/public/app/core/components/AppChrome/DockedMegaMenu/MegaMenuItem.tsx @@ -1,5 +1,5 @@ import { css, cx } from '@emotion/css'; -import React from 'react'; +import React, { useEffect, useRef } from 'react'; import { useLocalStorage } from 'react-use'; import { GrafanaTheme2, NavModelItem, toIconName } from '@grafana/data'; @@ -24,18 +24,37 @@ export function MegaMenuItem({ link, activeItem, level = 0, onClick }: Props) { const FeatureHighlightWrapper = link.highlightText ? FeatureHighlight : React.Fragment; const hasActiveChild = hasChildMatch(link, activeItem); const isActive = link === activeItem || (level === MAX_DEPTH && hasActiveChild); - const [sectionExpanded, setSectionExpanded] = - useLocalStorage(`grafana.navigation.expanded[${link.text}]`, false) ?? Boolean(hasActiveChild); + const [sectionExpanded, setSectionExpanded] = useLocalStorage( + `grafana.navigation.expanded[${link.text}]`, + Boolean(hasActiveChild) + ); const showExpandButton = level < MAX_DEPTH && Boolean(linkHasChildren(link) || link.emptyMessage); + const item = useRef(null); const styles = useStyles2(getStyles); + // expand parent sections if child is active + useEffect(() => { + if (hasActiveChild) { + setSectionExpanded(true); + } + }, [hasActiveChild, setSectionExpanded]); + + // scroll active element into center if it's offscreen + useEffect(() => { + if (isActive && item.current && isElementOffscreen(item.current)) { + item.current.scrollIntoView({ + block: 'center', + }); + } + }, [isActive]); + if (!link.url) { return null; } return ( -
  • +
  • ({ function linkHasChildren(link: NavModelItem): link is NavModelItem & { children: NavModelItem[] } { return Boolean(link.children && link.children.length > 0); } + +function isElementOffscreen(element: HTMLElement) { + const rect = element.getBoundingClientRect(); + return rect.bottom < 0 || rect.top >= window.innerHeight; +}