diff --git a/.changeset/great-bulldogs-provide.md b/.changeset/great-bulldogs-provide.md index f076dfa545..3b51ea9bdf 100644 --- a/.changeset/great-bulldogs-provide.md +++ b/.changeset/great-bulldogs-provide.md @@ -6,6 +6,6 @@ The `Bar` component will now render a `MobileSidebar` instead of the current sid --- -**Add MobileSidebar:** A navigation component, which sticks to the bottom. If there is no content in the Sidebar, it won't be rendered. If there are `children ` in the `Sidebar`, but no `SidebarGroups` as `children`, it will render all `children` into a default overlay menu, which can be displayed by clicking a menu item. If `SidebarGroups` are provided, it will render them in the bottom navigation. Additionally, a `MobileSidebarContext`, which wraps the component, will save the selected menu item. +**Add MobileSidebar:** A navigation component, which sticks to the bottom. If there is no content in the Sidebar, it won't be rendered. If there are `children ` in the `Sidebar`, but no `SidebarGroup`s as `children`, it will render all `children` into a default overlay menu, which can be displayed by clicking a menu item. If `SidebarGroup`s are provided, it will render them in the bottom navigation. Additionally, a `MobileSidebarContext`, which wraps the component, will save the selected menu item. **Add SidebarGroup:** Groups items of the `Sidebar` together. On bigger screens, this won't have any effect at the moment. On smaller screens, it will render a given icon into the `MobileSidebar`. If a route is provided, clicking the `SidebarGroup` in the `MobileSidebar` will route to the page. If no route is provided, it will add a provided icon to the `MobileSidebar` as a menu item & will render the children into an overlay menu, which will be displayed when the menu item is clicked. diff --git a/.changeset/stale-brooms-fry.md b/.changeset/stale-brooms-fry.md index c98a427e80..18c847973e 100644 --- a/.changeset/stale-brooms-fry.md +++ b/.changeset/stale-brooms-fry.md @@ -2,7 +2,7 @@ '@backstage/create-app': patch --- -You can now add `SidebarGroups` to the current `Sidebar`. This will not affect how the current sidebar is displayed, but allows a customization on how the `MobileSidebar` on smaller screens will look like. A `SidebarGroup` will be displayed with the given icon in the `MobileSidebar`. +You can now add `SidebarGroup`s to the current `Sidebar`. This will not affect how the current sidebar is displayed, but allows a customization on how the `MobileSidebar` on smaller screens will look like. A `SidebarGroup` will be displayed with the given icon in the `MobileSidebar`. A `SidebarGroup` can either link to an existing page (e.g. `/search` or `/settings`) or wrap components, which will be displayed in a full-screen overlay menu (e.g. `Menu`). @@ -46,6 +46,6 @@ Additionally, you can order the groups differently in the `MobileSidebar` than i ``` -If you decide against adding `SidebarGroups` to your `Sidebar` the `MobileSidebar` will contain one default menu item, which will open a full-screen overlay menu displaying all the content of the current `Sidebar`. +If you decide against adding `SidebarGroup`s to your `Sidebar` the `MobileSidebar` will contain one default menu item, which will open a full-screen overlay menu displaying all the content of the current `Sidebar`. More information on the `SidebarGroup` & the `MobileSidebar` component can be found in the changeset for the `core-components`. diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index 7f522437da..1bfabc335c 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -94,7 +94,7 @@ import InternalToolIcon from './internal-tool.icon.svg'; On mobile devices the `Sidebar` is displayed at the bottom of the screen. For customizing the experience you can group `SidebarItems` in a `SidebarGroup` (Example 1) or create a `SidebarGroup` with a link (Example 2). All -`SidebarGroups` are displayed in the bottom navigation with an icon. +`SidebarGroup`s are displayed in the bottom navigation with an icon. ```ts // Example 1 diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 2f4a1fb107..c2244e686d 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -701,9 +701,7 @@ export function MissingAnnotationEmptyState(props: Props_3): JSX.Element; export type MissingAnnotationEmptyStateClassKey = 'code'; // @public -export const MobileSidebar: ( - props: React_2.PropsWithChildren<{}>, -) => JSX.Element | null; +export const MobileSidebar: (props: MobileSidebarProps) => JSX.Element | null; // @public export const MobileSidebarContext: React_2.Context; @@ -714,6 +712,11 @@ export type MobileSidebarContextType = { setSelectedMenuItemIndex: React_2.Dispatch>; }; +// @public +export type MobileSidebarProps = { + children?: React_2.ReactNode; +}; + // Warning: (ae-missing-release-tag) "OAuthRequestDialog" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -854,9 +857,7 @@ export type SelectItem = { }; // @public -export const Sidebar: ( - props: React_2.PropsWithChildren, -) => JSX.Element; +export const Sidebar: (props: SidebarProps) => JSX.Element; // Warning: (ae-missing-release-tag) "SIDEBAR_INTRO_LOCAL_STORAGE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1177,12 +1178,11 @@ export type SidebarDividerClassKey = 'root'; export const SidebarExpandButton: () => JSX.Element | null; // @public -export const SidebarGroup: ( - props: React_2.PropsWithChildren, -) => JSX.Element; +export const SidebarGroup: (props: SidebarGroupProps) => JSX.Element; // @public export interface SidebarGroupProps extends BottomNavigationActionProps { + children?: React_2.ReactNode; priority?: number; to?: string; } @@ -1232,18 +1232,24 @@ export type SidebarItemClassKey = // Warning: (ae-missing-release-tag) "SidebarPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function SidebarPage(props: PropsWithChildren<{}>): JSX.Element; +export function SidebarPage(props: SidebarPageProps): JSX.Element; // Warning: (ae-missing-release-tag) "SidebarPageClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export type SidebarPageClassKey = 'root'; +// @public +export type SidebarPageProps = { + children?: React_2.ReactNode; +}; + // @public (undocumented) export type SidebarProps = { openDelayMs?: number; closeDelayMs?: number; disableExpandOnHover?: boolean; + children?: React_2.ReactNode; }; // Warning: (ae-missing-release-tag) "SidebarScrollWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -2076,7 +2082,7 @@ export const SidebarStateContext: React_2.Context; export type SidebarStateContextType = { isPinned: boolean; toggleSidebarPinState: () => any; - isMobile: boolean; + isMobile?: boolean; }; // @public diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index c3eddfe218..fe3964b745 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -17,7 +17,7 @@ import { makeStyles } from '@material-ui/core/styles'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import classnames from 'classnames'; -import React, { useState, useContext, PropsWithChildren, useRef } from 'react'; +import React, { useState, useContext, useRef } from 'react'; import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarStateContext } from './Page'; @@ -75,6 +75,7 @@ export type SidebarProps = { openDelayMs?: number; closeDelayMs?: number; disableExpandOnHover?: boolean; + children?: React.ReactNode; }; /** @@ -87,7 +88,7 @@ export type SidebarProps = { * @returns * @internal */ -const DesktopSidebar = (props: PropsWithChildren) => { +const DesktopSidebar = (props: SidebarProps) => { const { openDelayMs = sidebarConfig.defaultOpenDelayMs, closeDelayMs = sidebarConfig.defaultCloseDelayMs, @@ -182,7 +183,7 @@ const DesktopSidebar = (props: PropsWithChildren) => { * * @public */ -export const Sidebar = (props: React.PropsWithChildren) => { +export const Sidebar = (props: SidebarProps) => { const { children, openDelayMs, closeDelayMs, disableExpandOnHover } = props; const { isMobile } = useContext(SidebarStateContext); diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index af66dcc322..0761199c76 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -41,6 +41,25 @@ export type MobileSidebarContextType = { setSelectedMenuItemIndex: React.Dispatch>; }; +/** + * Props of MobileSidebar + * + * @public + */ +export type MobileSidebarProps = { + children?: React.ReactNode; +}; + +/** + * @internal + */ +type OverlayMenuProps = { + label?: string; + onClose: () => void; + open: boolean; + children?: React.ReactNode; +}; + const useStyles = makeStyles(theme => ({ root: { position: 'fixed', @@ -88,11 +107,7 @@ const OverlayMenu = ({ label = 'Menu', open, onClose, -}: React.PropsWithChildren<{ - label?: string; - onClose: () => void; - open: boolean; -}>) => { +}: OverlayMenuProps) => { const classes = useStyles(); return ( @@ -129,13 +144,13 @@ export const MobileSidebarContext = createContext({ /** * A navigation component for mobile screens, which sticks to the bottom. * - * It alternates the normal sidebar by grouping the `SidebarItems` based on provided `SidebarGroups` + * It alternates the normal sidebar by grouping the `SidebarItems` based on provided `SidebarGroup`s * either rendering them as a link or an overlay menu. - * If no `SidebarGroups` are provided the sidebar content is wrapped in an default overlay menu. + * If no `SidebarGroup`s are provided the sidebar content is wrapped in an default overlay menu. * * @public */ -export const MobileSidebar = (props: React.PropsWithChildren<{}>) => { +export const MobileSidebar = (props: MobileSidebarProps) => { const { children } = props; const classes = useStyles(); const location = useLocation(); diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 2bc4ed195b..9e5d897de6 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -15,12 +15,7 @@ */ import { makeStyles } from '@material-ui/core/styles'; -import React, { - createContext, - PropsWithChildren, - useEffect, - useState, -} from 'react'; +import React, { createContext, useEffect, useState } from 'react'; import { sidebarConfig } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; @@ -55,7 +50,16 @@ const useStyles = makeStyles( export type SidebarStateContextType = { isPinned: boolean; toggleSidebarPinState: () => any; - isMobile: boolean; + isMobile?: boolean; +}; + +/** + * Props for SidebarPage + * + * @public + */ +export type SidebarPageProps = { + children?: React.ReactNode; }; /** @@ -69,7 +73,7 @@ export const SidebarStateContext = createContext({ isMobile: false, }); -export function SidebarPage(props: PropsWithChildren<{}>) { +export function SidebarPage(props: SidebarPageProps) { const [isPinned, setIsPinned] = useState(() => LocalStorage.getSidebarPinState(), ); diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index f80af385c8..fc451cd779 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -38,10 +38,14 @@ export interface SidebarGroupProps extends BottomNavigationActionProps { */ to?: string; /** - * If the `SidebarGroups` should be in a different order than in the normal `Sidebar`, you can provide + * If the `SidebarGroup`s should be in a different order than in the normal `Sidebar`, you can provide * each `SidebarGroup` it's own priority to reorder them. */ priority?: number; + /** + * React children + */ + children?: React.ReactNode; } const useStyles = makeStyles(theme => ({ @@ -114,9 +118,7 @@ const MobileSidebarGroup = (props: SidebarGroupProps) => { * * @public */ -export const SidebarGroup = ( - props: React.PropsWithChildren, -) => { +export const SidebarGroup = (props: SidebarGroupProps) => { const { children, to, label, icon, value } = props; const { isMobile } = useContext(SidebarStateContext); diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index a9d31f465b..61fbcd25ab 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -16,7 +16,10 @@ export { Sidebar } from './Bar'; export { MobileSidebar, MobileSidebarContext } from './MobileSidebar'; -export type { MobileSidebarContextType } from './MobileSidebar'; +export type { + MobileSidebarContextType, + MobileSidebarProps, +} from './MobileSidebar'; export { SidebarGroup } from './SidebarGroup'; export type { SidebarGroupProps } from './SidebarGroup'; export { SidebarSubmenuItem } from './SidebarSubmenuItem'; @@ -34,6 +37,7 @@ export { export type { SidebarStateContextType as SidebarStateContextType, SidebarPageClassKey, + SidebarPageProps, } from './Page'; export { SidebarDivider,