qlik-oss/sn-table

View on GitHub
src/table/components/head/MenuList/MenuGroup.tsx

Summary

Maintainability
A
0 mins
Test Coverage
A
95%
/* eslint-disable import/no-cycle */
import Typography from "@mui/material/Typography";
import ArrowRight from "@qlik-trial/sprout/icons/react/ArrowRight";
import React, { useRef, useState } from "react";
import { HeadCellMenuItem, MenuItemGroup } from "../../../types";
import { handleHeadCellMenuKeyDown } from "../../../utils/handle-keyboard";
import { StyledListItemIcon, StyledMenuItem, StyledMenuItemLabel } from "../styles";
import RecursiveMenuList from "./RecursiveMenuList";

export const interceptClickOnMenuItems = (menuGroups: MenuItemGroup[], cache: SubMenusOpenStatusCache) => {
  const result = menuGroups.map((grp) =>
    grp.map(({ onClick, ...restProps }) => ({
      ...restProps,
      ...(onClick
        ? {
            onClick: (evt: React.MouseEvent) => {
              // reset all opened submenu levels here!
              Object.entries(cache).map(([, setter]) => setter(false));
              onClick(evt);
            },
          }
        : {}),
    })),
  );
  return result;
};

type SubMenusOpenStatusCache = Record<string, React.Dispatch<React.SetStateAction<boolean>>>;
let subMenusOpenStatusCache: SubMenusOpenStatusCache = {};

const MenuGroupItems = ({ autoFocus, id, onClick, itemTitle, icon, enabled, subMenus }: HeadCellMenuItem) => {
  const [openMenu, setOpenMenu] = useState(false);
  const anchorRef = useRef<HTMLDivElement | null>(null);

  const handleOnClick = (evt: React.MouseEvent) => {
    if (onClick) {
      onClick(evt);
      subMenusOpenStatusCache = {};
    }
    if (subMenus?.length) {
      setOpenMenu(true);
      subMenusOpenStatusCache[itemTitle] = setOpenMenu;
    }
  };

  return (
    <>
      <StyledMenuItem
        ref={subMenus ? anchorRef : null}
        key={id}
        data-testid={`menu-item-${id}`}
        className="sn-table-head-menu-item"
        onClick={handleOnClick}
        disabled={!enabled}
        autoFocus={autoFocus}
        onKeyDown={handleHeadCellMenuKeyDown}
      >
        <StyledMenuItemLabel>
          <StyledListItemIcon>{icon}</StyledListItemIcon>
          <Typography variant="body2">{itemTitle}</Typography>
        </StyledMenuItemLabel>
        {subMenus?.length ? <ArrowRight /> : null}
      </StyledMenuItem>

      {subMenus?.length && (
        <RecursiveMenuList
          anchorEl={anchorRef.current}
          open={openMenu}
          onClose={() => setOpenMenu(false)}
          menuGroups={interceptClickOnMenuItems(subMenus, subMenusOpenStatusCache)}
          transformOrigin={{ horizontal: "left", vertical: "top" }}
          anchorOrigin={{ horizontal: "right", vertical: "top" }}
        />
      )}
    </>
  );
};

const MenuGroup = ({ menuGroup }: { menuGroup: HeadCellMenuItem[] }) =>
  menuGroup.map((groupItem) => <MenuGroupItems key={groupItem.id} {...groupItem} />);

export default MenuGroup;