Navigation: Expand active page hierarchy and scroll into center if not visible (#76949)

* expand page hierarchy and scroll into center if not visible

* remove unnecessary id
This commit is contained in:
Ashley Harrison
2023-10-23 15:47:16 +01:00
committed by GitHub
parent 1b420585f9
commit efea86eb52

View File

@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import React from 'react'; import React, { useEffect, useRef } from 'react';
import { useLocalStorage } from 'react-use'; import { useLocalStorage } from 'react-use';
import { GrafanaTheme2, NavModelItem, toIconName } from '@grafana/data'; 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 FeatureHighlightWrapper = link.highlightText ? FeatureHighlight : React.Fragment;
const hasActiveChild = hasChildMatch(link, activeItem); const hasActiveChild = hasChildMatch(link, activeItem);
const isActive = link === activeItem || (level === MAX_DEPTH && hasActiveChild); const isActive = link === activeItem || (level === MAX_DEPTH && hasActiveChild);
const [sectionExpanded, setSectionExpanded] = const [sectionExpanded, setSectionExpanded] = useLocalStorage(
useLocalStorage(`grafana.navigation.expanded[${link.text}]`, false) ?? Boolean(hasActiveChild); `grafana.navigation.expanded[${link.text}]`,
Boolean(hasActiveChild)
);
const showExpandButton = level < MAX_DEPTH && Boolean(linkHasChildren(link) || link.emptyMessage); const showExpandButton = level < MAX_DEPTH && Boolean(linkHasChildren(link) || link.emptyMessage);
const item = useRef<HTMLLIElement>(null);
const styles = useStyles2(getStyles); 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) { if (!link.url) {
return null; return null;
} }
return ( return (
<li className={styles.listItem}> <li ref={item} className={styles.listItem}>
<div <div
className={cx(styles.menuItem, { className={cx(styles.menuItem, {
[styles.hasIcon]: Boolean(level === 0 && link.icon), [styles.hasIcon]: Boolean(level === 0 && link.icon),
@@ -175,3 +194,8 @@ const getStyles = (theme: GrafanaTheme2) => ({
function linkHasChildren(link: NavModelItem): link is NavModelItem & { children: NavModelItem[] } { function linkHasChildren(link: NavModelItem): link is NavModelItem & { children: NavModelItem[] } {
return Boolean(link.children && link.children.length > 0); return Boolean(link.children && link.children.length > 0);
} }
function isElementOffscreen(element: HTMLElement) {
const rect = element.getBoundingClientRect();
return rect.bottom < 0 || rect.top >= window.innerHeight;
}