Add basic support for submenus to mobile sidebar

Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
Philipp Hugenroth
2021-12-07 16:49:24 +01:00
parent 856a6f5b62
commit 7d9913fc43
7 changed files with 50 additions and 62 deletions
+9 -4
View File
@@ -809,6 +809,11 @@ export const Sidebar: ({
export const SIDEBAR_INTRO_LOCAL_STORAGE =
'@backstage/core/sidebar-intro-dismissed';
// Warning: (ae-missing-release-tag) "SidebarClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type SidebarClassKey = 'drawer' | 'drawerOpen';
// Warning: (ae-missing-release-tag) "sidebarConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -838,7 +843,7 @@ export const SidebarContext: Context<SidebarContextType>;
// @public (undocumented)
export type SidebarContextType = {
isOpen: boolean;
setOpen: (open: boolean) => void;
setOpen?: (open: boolean) => void;
};
// Warning: (ae-missing-release-tag) "SidebarDivider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -1110,6 +1115,9 @@ export const SidebarDivider: React_2.ComponentType<
}
>;
// @public
export const SidebarExpandButton: () => JSX.Element | null;
// Warning: (ae-missing-release-tag) "SidebarGroup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -1131,9 +1139,6 @@ export interface SidebarGroupProps extends BottomNavigationActionProps {
to?: string;
}
// @public
export const SidebarExpandButton: () => JSX.Element | null;
// Warning: (ae-missing-release-tag) "SidebarIntro" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -178,18 +178,8 @@ export const Sidebar = ({ children }: React.PropsWithChildren<Props>) => {
theme.breakpoints.down('xs'),
);
// TODO: Generalize
const setOpen = () => {};
return isMobileScreen ? (
<SidebarContext.Provider
value={{
isOpen: true,
setOpen,
}}
>
<MobileSidebar>{children}</MobileSidebar>
</SidebarContext.Provider>
<MobileSidebar>{children}</MobileSidebar>
) : (
<DesktopSidebar>{children}</DesktopSidebar>
);
@@ -209,14 +199,14 @@ export const SidebarExpandButton = () => {
theme.breakpoints.down('md'),
);
if (isPinned || isSmallScreen || !setOpen) {
return null;
}
const handleClick = () => {
setOpen(!isOpen);
};
if (isPinned || isSmallScreen) {
return null;
}
return (
<button
onClick={handleClick}
@@ -307,7 +307,6 @@ const SidebarItemWithSubmenu = ({
<div className={classes.secondaryAction}>{}</div>
</>
);
const closedContent = itemIcon;
return (
<SidebarItemWithSubmenuContext.Provider
@@ -316,12 +315,8 @@ const SidebarItemWithSubmenu = ({
setIsHoveredOn,
}}
>
<div
onMouseLeave={handleMouseLeave}
className={clsx(isHoveredOn && classes.highlighted)}
>
<div onMouseLeave={handleMouseLeave} onMouseEnter={handleMouseEnter}>
<div
onMouseEnter={handleMouseEnter}
data-testid="item-with-submenu"
className={clsx(
classes.root,
@@ -331,7 +326,7 @@ const SidebarItemWithSubmenu = ({
isHoveredOn && classes.highlighted,
)}
>
{isOpen ? openContent : closedContent}
{isOpen ? openContent : itemIcon}
{!isHoveredOn && (
<ArrowRightIcon fontSize="small" className={classes.submenuArrow} />
)}
@@ -488,28 +483,12 @@ export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
),
};
let hasSubmenu = false;
let submenu: ReactNode;
const componentType = (
<SidebarSubmenu>
<></>
</SidebarSubmenu>
).type;
// Filter children for SidebarSubmenu components
const submenus = useElementFilter(children, elements =>
elements.getElements().filter(child => child.type === componentType),
const [submenu] = useElementFilter(children, elements =>
elements.getElements().filter(child => child.type === SidebarSubmenu),
);
// Error thrown if more than one SidebarSubmenu in a SidebarItem
if (submenus.length > 1) {
throw new Error(
'Cannot render more than one SidebarSubmenu inside a SidebarItem',
);
} else if (submenus.length === 1) {
hasSubmenu = true;
submenu = submenus[0];
}
if (hasSubmenu) {
if (submenu) {
return (
<SidebarItemWithSubmenu
text={text}
@@ -26,6 +26,7 @@ import MenuIcon from '@material-ui/icons/Menu';
import { orderBy } from 'lodash';
import React, { createContext, useEffect, useState } from 'react';
import { useLocation } from 'react-router';
import { SidebarContext } from '.';
import { sidebarConfig } from './config';
import { SidebarGroup } from './SidebarGroup';
@@ -143,21 +144,23 @@ export const MobileSidebar = ({ children }: React.PropsWithChildren<{}>) => {
!sidebarGroups[selectedMenuItemIndex].props.to;
return (
<MobileSidebarContext.Provider
value={{ selectedMenuItemIndex, setSelectedMenuItemIndex }}
>
{shouldShowGroupChildren && (
<OverlayMenu
{...sidebarGroups[selectedMenuItemIndex].props}
onClose={() => setSelectedMenuItemIndex(-1)}
/>
)}
<BottomNavigation
className={classes.root}
data-testid="mobile-sidebar-root"
<SidebarContext.Provider value={{ isOpen: true }}>
<MobileSidebarContext.Provider
value={{ selectedMenuItemIndex, setSelectedMenuItemIndex }}
>
{sidebarGroups}
</BottomNavigation>
</MobileSidebarContext.Provider>
{shouldShowGroupChildren && (
<OverlayMenu
{...sidebarGroups[selectedMenuItemIndex].props}
onClose={() => setSelectedMenuItemIndex(-1)}
/>
)}
<BottomNavigation
className={classes.root}
data-testid="mobile-sidebar-root"
>
{sidebarGroups}
</BottomNavigation>
</MobileSidebarContext.Provider>
</SidebarContext.Provider>
);
};
@@ -58,12 +58,20 @@ const useStyles = (props: { left: number }) =>
},
drawerOpen: {
width: submenuConfig.drawerWidthOpen,
[theme.breakpoints.down('sm')]: {
width: '100%',
position: 'relative',
paddingLeft: theme.spacing(3),
left: 0,
top: 0,
},
},
title: {
fontSize: 24,
fontWeight: 500,
color: '#FFF',
padding: 20,
display: 'none',
},
}));
@@ -76,6 +76,10 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
color: theme.palette.navigation.color,
display: 'flex',
justifyContent: 'center',
[theme.breakpoints.down('xs')]: {
display: 'block',
paddingLeft: theme.spacing(4),
},
fontSize: '14px',
},
}));
@@ -60,12 +60,11 @@ export const SIDEBAR_INTRO_LOCAL_STORAGE =
export type SidebarContextType = {
isOpen: boolean;
setOpen: (open: boolean) => void;
setOpen?: (open: boolean) => void;
};
export const SidebarContext = createContext<SidebarContextType>({
isOpen: false,
setOpen: _open => {},
});
export type SidebarItemWithSubmenuContextType = {