diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 16cdda0f81..701a608ece 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1090,18 +1090,24 @@ export const SidebarDivider: React_2.ComponentType< } >; -// Warning: (ae-forgotten-export) The symbol "SidebarGroupProps" needs to be exported by the entry point index.d.ts // 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) export const SidebarGroup: ({ - to, - label, - icon, - value, children, + ...props }: React_2.PropsWithChildren) => JSX.Element; +// Warning: (ae-missing-release-tag) "SidebarGroupProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface SidebarGroupProps extends BottomNavigationActionProps { + // (undocumented) + priority?: number; + // (undocumented) + to?: string; +} + // 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) diff --git a/packages/core-components/src/layout/Header/Header.tsx b/packages/core-components/src/layout/Header/Header.tsx index 40495ca0e0..92f28c1d07 100644 --- a/packages/core-components/src/layout/Header/Header.tsx +++ b/packages/core-components/src/layout/Header/Header.tsx @@ -64,7 +64,7 @@ const useStyles = makeStyles( }, title: { color: theme.palette.bursts.fontColor, - wordBreak: 'break-all', + // ? fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))', marginBottom: 0, }, diff --git a/packages/core-components/src/layout/Page/Page.tsx b/packages/core-components/src/layout/Page/Page.tsx index 1810ef8177..ba3c8bfff7 100644 --- a/packages/core-components/src/layout/Page/Page.tsx +++ b/packages/core-components/src/layout/Page/Page.tsx @@ -14,26 +14,20 @@ * limitations under the License. */ -import React, { PropsWithChildren } from 'react'; import { BackstageTheme } from '@backstage/theme'; import { makeStyles, ThemeProvider } from '@material-ui/core/styles'; -import { sidebarConfig } from '../Sidebar'; +import React, { PropsWithChildren } from 'react'; export type PageClassKey = 'root'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(() => ({ root: { display: 'grid', gridTemplateAreas: "'pageHeader pageHeader pageHeader' 'pageSubheader pageSubheader pageSubheader' 'pageNav pageContent pageSidebar'", gridTemplateRows: 'max-content auto 1fr', gridTemplateColumns: 'auto 1fr auto', - [theme.breakpoints.up('sm')]: { - height: '100vh', - }, - [theme.breakpoints.down('xs')]: { - height: `calc(100vh - ${sidebarConfig.mobileSidebarHeight}px)`, - }, + height: '100vh', overflowY: 'auto', }, })); diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 25202c12b0..247c191dee 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ +import { useElementFilter } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import BottomNavigation from '@material-ui/core/BottomNavigation'; import Box from '@material-ui/core/Box'; @@ -22,6 +23,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import MenuIcon from '@material-ui/icons/Menu'; +import { orderBy } from 'lodash'; import React, { createContext, useEffect, useState } from 'react'; import { useLocation } from 'react-router'; import { sidebarConfig } from './config'; @@ -68,27 +70,18 @@ const useStyles = makeStyles(theme => ({ }, })); -const sortSidebarGroupsForPriority = ( - childA: React.ReactElement, - childB: React.ReactElement, -) => { - const priorityADefined = childA.props.priority !== undefined; - const priorityBDefined = childB.props.priority !== undefined; - if (priorityADefined && !priorityBDefined) { - return -1; - } else if (priorityBDefined && !priorityADefined) { - return 1; - } else if (priorityADefined && priorityBDefined) { - return childA.props.priority - childB.props.priority; - } - return 0; -}; +const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => + orderBy( + children, + ({ props: { priority } }) => (priority ? priority : -1), + 'desc', + ); const OverlayMenu = ({ children, - label, + label = 'Menu', onClose, -}: React.PropsWithChildren<{ label: string; onClose: () => void }>) => { +}: React.PropsWithChildren<{ label?: string; onClose: () => void }>) => { const classes = useStyles(); return ( @@ -117,22 +110,19 @@ export const MobileSidebar = ({ children }: React.PropsWithChildren<{}>) => { const location = useLocation(); const [selectedMenuItemIndex, setSelectedMenuItemIndex] = useState(-1); - let shouldSortSidebarGroups = false; useEffect(() => { setSelectedMenuItemIndex(-1); }, [location.pathname]); - // Filter children for SidebarGroups & set `shouldSortSidebarGroups` if priorities are set for one or more SidebarGroups - let sidebarGroups = React.Children.map(children, child => { - if (React.isValidElement(child) && child.type === SidebarGroup) { - if (child.props.priority !== undefined) { - shouldSortSidebarGroups = true; - } - return child; - } - return null; - }); + // Filter children for SidebarGroups + let sidebarGroups = useElementFilter(children, elements => + elements + .getElements() + .filter( + child => React.isValidElement(child) && child.type === SidebarGroup, + ), + ); if (!sidebarGroups) { // If Sidebar has no children the MobileSidebar won't be rendered @@ -141,13 +131,11 @@ export const MobileSidebar = ({ children }: React.PropsWithChildren<{}>) => { // If Sidebar has no SidebarGroup as a children a default // SidebarGroup with the complete Sidebar content will be created sidebarGroups.push( - }> - {children} - , + }>{children}, ); - } else if (shouldSortSidebarGroups) { - // If a SidebarGroup has a given priority the SidebarGroups are sorted for prioirty - sidebarGroups = sidebarGroups.sort(sortSidebarGroupsForPriority); + } else { + // Sort SidebarGroups for the given Priority + sidebarGroups = sortSidebarGroupsForPriority(sidebarGroups); } const shouldShowGroupChildren = diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index d99b96aebf..e487f9758b 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -13,19 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// We don't want to export RoutingProvider from core-app-api, but it's way easier to -// use here. This hack only works in storybook stories. -// TODO: Export a nicer to user routing provider, perhaps from test-utils -// eslint-disable-next-line monorepo/no-internal-import -import { RoutingProvider } from '@backstage/core-app-api/src/routing/RoutingProvider'; import { createRouteRef } from '@backstage/core-plugin-api'; +import { wrapInTestApp } from '@backstage/test-utils'; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import ExtensionIcon from '@material-ui/icons/Extension'; import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined'; import MenuIcon from '@material-ui/icons/Menu'; import React, { ComponentType } from 'react'; -import { MemoryRouter, useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { Sidebar, SidebarDivider, @@ -50,35 +45,27 @@ export default { title: 'Layout/Sidebar', component: Sidebar, decorators: [ - (Story: ComponentType<{}>) => ( - - - - - - ), + (Story: ComponentType<{}>) => + wrapInTestApp(, { mountedRoutes: { '/': routeRef } }), ], }; -export const SampleSidebar = () => ( - - - - {}} /> - - - - - - - - - - - -); +export const SampleSidebar = () => { + return ( + + + + {}} /> + + + + + + + + + + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index 2c971c7941..d71657ac5a 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -27,7 +27,7 @@ import { Link } from '../../components'; import { sidebarConfig } from './config'; import { MobileSidebarContext } from './MobileSidebar'; -interface SidebarGroupProps extends BottomNavigationActionProps { +export interface SidebarGroupProps extends BottomNavigationActionProps { to?: string; priority?: number; } @@ -50,20 +50,11 @@ const useStyles = makeStyles(theme => ({ }, })); -export const SidebarGroup = ({ - to, - label, - icon, - value, - children, -}: React.PropsWithChildren) => { +const MobileSidebarGroup = ({ to, label, icon, value }: SidebarGroupProps) => { const classes = useStyles(); const location = useLocation(); const { selectedMenuItemIndex, setSelectedMenuItemIndex } = useContext(MobileSidebarContext); - const isMobileScreen = useMediaQuery(theme => - theme.breakpoints.down('xs'), - ); const onChange = (_: React.ChangeEvent<{}>, value: number) => { if (value === selectedMenuItemIndex) { @@ -79,7 +70,7 @@ export const SidebarGroup = ({ !(selectedMenuItemIndex >= 0) && to === location.pathname); - return isMobileScreen ? ( + return ( // Material UI issue: https://github.com/mui-org/material-ui/issues/27820 // @ts-ignore - ) : ( - <>{children} ); }; + +export const SidebarGroup = ({ + children, + ...props +}: React.PropsWithChildren) => { + const isMobileScreen = useMediaQuery(theme => + theme.breakpoints.down('xs'), + ); + + return isMobileScreen ? : <>{children}; +}; diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 26a4c0e8a5..14d8d35b48 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -17,6 +17,7 @@ export { Sidebar } from './Bar'; export { MobileSidebar } from './MobileSidebar'; export { SidebarGroup } from './SidebarGroup'; +export type { SidebarGroupProps } from './SidebarGroup'; export { SidebarPage, SidebarPinStateContext } from './Page'; export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page'; export {