From 8bb0f4bc8a1852cde1c83a167c3a95dc6ae6a083 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Sun, 19 Sep 2021 00:59:45 +0200 Subject: [PATCH 01/11] add LayoutProvider Signed-off-by: Juan Pablo Garcia Ripa --- .changeset/eight-insects-tan.md | 5 ++ packages/core-components/api-report.md | 22 +++++ .../src/layout/Content/Content.tsx | 6 ++ .../layout/LayoutProvider/LayoutProvider.tsx | 58 +++++++++++++ .../src/layout/LayoutProvider/index.ts | 16 ++++ .../src/layout/Sidebar/Bar.tsx | 81 ++++++++++++++----- .../src/layout/Sidebar/Page.tsx | 17 +++- .../layout/Sidebar/SidebarPage.stories.tsx | 72 +++++++++++++++++ .../src/layout/Sidebar/index.ts | 2 + .../SidebarSearch/SidebarSearch.tsx | 7 +- 10 files changed, 263 insertions(+), 23 deletions(-) create mode 100644 .changeset/eight-insects-tan.md create mode 100644 packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx create mode 100644 packages/core-components/src/layout/LayoutProvider/index.ts create mode 100644 packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx diff --git a/.changeset/eight-insects-tan.md b/.changeset/eight-insects-tan.md new file mode 100644 index 0000000000..0223b0d275 --- /dev/null +++ b/.changeset/eight-insects-tan.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Add SidebarPageContent component and useContenRef hook to have a reference to content wrapper element diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 8b5d1c61a7..296c1ad011 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1243,6 +1243,21 @@ export type SidebarPageProps = { }; // @public +// Warning: (ae-missing-release-tag) "SidebarPageContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function SidebarPageContent(props: PropsWithChildren<{}>): JSX.Element; + +// Warning: (ae-missing-release-tag) "SidebarPageContextType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SidebarPageContextType = { + contentRef?: React_2.MutableRefObject; +}; + +// Warning: (ae-missing-release-tag) "SidebarPinStateContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) export const SidebarPinStateContext: React_2.Context; // @public @@ -2404,6 +2419,13 @@ export function TrendLine( }, ): JSX.Element | null; +// Warning: (ae-missing-release-tag) "useContentRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function useContentRef(): + | React_2.MutableRefObject + | undefined; + // Warning: (ae-forgotten-export) The symbol "SetQueryParams" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "useQueryParamState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/core-components/src/layout/Content/Content.tsx b/packages/core-components/src/layout/Content/Content.tsx index 1d91556663..8d91d335be 100644 --- a/packages/core-components/src/layout/Content/Content.tsx +++ b/packages/core-components/src/layout/Content/Content.tsx @@ -17,6 +17,7 @@ import { makeStyles, Theme } from '@material-ui/core/styles'; import classNames from 'classnames'; import React, { PropsWithChildren } from 'react'; +import { useLayoutContent } from '../LayoutProvider/LayoutProvider'; /** @public */ export type BackstageContentClassKey = 'root' | 'stretch' | 'noPadding'; @@ -62,9 +63,14 @@ type Props = { export function Content(props: PropsWithChildren) { const { className, stretch, noPadding, children, ...restProps } = props; + + const { contentRef } = useLayoutContent(); + const classes = useStyles(); return (
; + }; +}; + +const LayoutContext = createContext({ + content: { + contentRef: undefined, + }, +}); + +export function LayoutProvider(props: PropsWithChildren<{}>) { + const contentRef = useRef(null); + + const content = { + contentRef, + }; + + return ( + + {props.children} + + ); +} + +export function useLayoutContent() { + const { content } = useContext(LayoutContext); + + const focusContent = () => { + content.contentRef?.current?.focus(); + }; + + return { focusContent, contentRef: content.contentRef }; +} diff --git a/packages/core-components/src/layout/LayoutProvider/index.ts b/packages/core-components/src/layout/LayoutProvider/index.ts new file mode 100644 index 0000000000..4f8b38f7e9 --- /dev/null +++ b/packages/core-components/src/layout/LayoutProvider/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { LayoutProvider, useLayoutContent } from './LayoutProvider'; diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index ff907cdda3..e134703f50 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -17,11 +17,17 @@ import { makeStyles } from '@material-ui/core/styles'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import classnames from 'classnames'; -import React, { useState, useContext, useRef } from 'react'; + +import React, { useState, useContext, PropsWithChildren, useRef } from 'react'; +import Button from '@material-ui/core/Button'; + import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext } from './Page'; import { MobileSidebar } from './MobileSidebar'; +import DoubleArrowRight from './icons/DoubleArrowRight'; +import DoubleArrowLeft from './icons/DoubleArrowLeft'; +import { useLayoutContent } from '../LayoutProvider/LayoutProvider'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; @@ -60,6 +66,15 @@ const useStyles = makeStyles( duration: theme.transitions.duration.shorter, }), }, + visuallyHidden: { + top: 0, + position: 'absolute', + zIndex: 2, + transform: 'translateY(-200%)', + '&:focus': { + transform: 'translateY(5px)', + }, + }, }), { name: 'BackstageSidebar' }, ); @@ -105,6 +120,7 @@ const DesktopSidebar = (props: SidebarProps) => { const { isPinned, toggleSidebarPinState } = useContext( SidebarPinStateContext, ); + const { focusContent } = useLayoutContent(); const handleOpen = () => { if (isPinned || disableExpandOnHover) { @@ -128,6 +144,7 @@ const DesktopSidebar = (props: SidebarProps) => { if (isPinned || disableExpandOnHover) { return; } + focusContent(); if (hoverTimerRef.current) { clearTimeout(hoverTimerRef.current); hoverTimerRef.current = undefined; @@ -158,25 +175,42 @@ const DesktopSidebar = (props: SidebarProps) => { }; return ( - -
+
-
+ Skip to content + + +
{} : handleOpen} + onFocus={ + disableExpandOnHover ? () => {} : ignoreChildEvent(handleOpen) + } + onMouseLeave={disableExpandOnHover ? () => {} : handleClose} + onBlur={ + disableExpandOnHover ? () => {} : ignoreChildEvent(handleClose) + } + > +
+ {children} +
+
+
+ ); }; @@ -201,3 +235,12 @@ export const Sidebar = (props: SidebarProps) => { ); }; +function ignoreChildEvent(handlerFn: (e?: any) => void) { + // TODO type the event + return (event: any) => { + const currentTarget = event?.currentTarget as HTMLElement; + if (!currentTarget?.contains(event.relatedTarget as HTMLElement)) { + handlerFn(event); + } + }; +} diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index f23a6fa3b6..3dc31a5d52 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -15,7 +15,14 @@ */ import { makeStyles } from '@material-ui/core/styles'; -import React, { createContext, useEffect, useState } from 'react'; + +import React, { + createContext, + PropsWithChildren, + useEffect, + useState, +} from 'react'; + import { sidebarConfig } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; @@ -28,6 +35,7 @@ const useStyles = makeStyles( root: { width: '100%', transition: 'padding-left 0.1s ease-out', + isolation: 'isolate', [theme.breakpoints.up('sm')]: { paddingLeft: ({ isPinned }) => isPinned @@ -38,6 +46,13 @@ const useStyles = makeStyles( paddingBottom: sidebarConfig.mobileSidebarHeight, }, }, + content: { + zIndex: 0, + isolation: 'isolate', + '&:focus': { + outline: 0, + }, + }, }), { name: 'BackstageSidebarPage' }, ); diff --git a/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx b/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx new file mode 100644 index 0000000000..ca769e63cd --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx @@ -0,0 +1,72 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; +import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined'; +import React, { useCallback } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { + Sidebar, + SidebarDivider, + SidebarIntro, + SidebarItem, + SidebarSearchField, + SidebarSpace, + SidebarPage, +} from '.'; +import { useLayoutContent } from '../LayoutProvider'; +import { PluginWithTable } from '../Page/Page.stories'; + +export default { + title: 'Layout/SidebarPage', + component: SidebarPage, + decorators: [ + (storyFn: () => JSX.Element) => ( + {storyFn()} + ), + ], +}; + +export const SampleSidebarPage = () => { + return ( + + + + + ); +}; + +function CustomSidebar() { + const { focusContent } = useLayoutContent(); + const handleSearch = (input: string) => { + focusContent(); + // eslint-disable-next-line no-console + console.log(input); + }; + + return ( + + + + + + + + + + + ); +} diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index d175b364da..99ce966d0a 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -26,6 +26,7 @@ export type { SidebarSubmenuItemProps, SidebarSubmenuItemDropdownItem, } from './SidebarSubmenuItem'; + export type { SidebarClassKey, SidebarProps } from './Bar'; export { SidebarPage, @@ -36,6 +37,7 @@ export type { SidebarPageClassKey, SidebarPageProps, } from './Page'; + export { SidebarDivider, SidebarItem, diff --git a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx index 9f6be2333f..26b9583660 100644 --- a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx +++ b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx @@ -18,8 +18,8 @@ import React, { useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { rootRouteRef } from '../../plugin'; -import { SidebarSearchField } from '@backstage/core-components'; import { useRouteRef, IconComponent } from '@backstage/core-plugin-api'; +import { SidebarSearchField, useContentRef } from '@backstage/core-components'; export type SidebarSearchProps = { icon?: IconComponent; @@ -27,14 +27,15 @@ export type SidebarSearchProps = { export const SidebarSearch = (props: SidebarSearchProps) => { const searchRoute = useRouteRef(rootRouteRef); + const contentRef = useContentRef(); const navigate = useNavigate(); const handleSearch = useCallback( (query: string): void => { const queryString = qs.stringify({ query }, { addQueryPrefix: true }); - + contentRef?.current?.focus(); navigate(`${searchRoute()}${queryString}`); }, - [navigate, searchRoute], + [navigate, searchRoute, contentRef], ); return ( From af7608e58dbcaf7bc1c12b1ba917b2232b6ee9fd Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Thu, 9 Dec 2021 16:32:23 +0100 Subject: [PATCH 02/11] dont show skip if there is no content ref Signed-off-by: Juan Pablo Garcia Ripa --- .../layout/LayoutProvider/LayoutProvider.tsx | 5 ++-- .../src/layout/Sidebar/Bar.tsx | 29 ++++++++++++++----- packages/core-components/src/layout/index.ts | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx b/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx index 53fc0aee59..1dcc91d817 100644 --- a/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx +++ b/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx @@ -17,6 +17,7 @@ import React, { createContext, PropsWithChildren, + useCallback, useContext, useRef, } from 'react'; @@ -50,9 +51,9 @@ export function LayoutProvider(props: PropsWithChildren<{}>) { export function useLayoutContent() { const { content } = useContext(LayoutContext); - const focusContent = () => { + const focusContent = useCallback(() => { content.contentRef?.current?.focus(); - }; + }, [content]); return { focusContent, contentRef: content.contentRef }; } diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index e134703f50..2243cfc10c 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -69,7 +69,7 @@ const useStyles = makeStyles( visuallyHidden: { top: 0, position: 'absolute', - zIndex: 2, + zIndex: 1000, transform: 'translateY(-200%)', '&:focus': { transform: 'translateY(5px)', @@ -176,13 +176,7 @@ const DesktopSidebar = (props: SidebarProps) => { return (
- + { ); }; + +function A11ySkipSidebar() { + const { focusContent, contentRef } = useLayoutContent(); + const classes = useStyles(); + + if (!contentRef?.current) { + return null; + } + return ( + + ); +} + function ignoreChildEvent(handlerFn: (e?: any) => void) { // TODO type the event return (event: any) => { diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts index 9bb7fbaa26..06ee5d1d4c 100644 --- a/packages/core-components/src/layout/index.ts +++ b/packages/core-components/src/layout/index.ts @@ -31,3 +31,4 @@ export * from './Sidebar'; export * from './SignInPage'; export * from './TabbedCard'; export * from './Breadcrumbs'; +export * from './LayoutProvider'; From 8a0c363862ca0643ecb2c91b690a0458cdd6c492 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Thu, 9 Dec 2021 16:37:50 +0100 Subject: [PATCH 03/11] update app Signed-off-by: Juan Pablo Garcia Ripa --- packages/app/src/App.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 59f107c70d..421b21790c 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -30,6 +30,7 @@ import { createApp } from '@backstage/app-defaults'; import { FlatRoutes } from '@backstage/core-app-api'; import { AlertDisplay, + LayoutProvider, OAuthRequestDialog, SignInPage, } from '@backstage/core-components'; @@ -225,11 +226,13 @@ const routes = ( const App = () => ( - - - - {routes} - + + + + + {routes} + + ); From eae85fecaccfec53d7068a76674914ea00b09746 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Sat, 11 Dec 2021 00:52:41 +0100 Subject: [PATCH 04/11] add focus after search Signed-off-by: Juan Pablo Garcia Ripa add provider to report Signed-off-by: Juan Pablo Garcia Ripa --- .changeset/eight-insects-tan.md | 2 +- packages/core-components/api-report.md | 32 +++------ .../src/layout/Sidebar/Bar.tsx | 1 - .../src/layout/Sidebar/Page.tsx | 1 - .../layout/Sidebar/SidebarPage.stories.tsx | 72 ------------------- .../src/layout/Sidebar/index.ts | 1 - .../components/SearchModal/SearchModal.tsx | 30 +++++++- .../SidebarSearch/SidebarSearch.tsx | 11 +-- 8 files changed, 45 insertions(+), 105 deletions(-) delete mode 100644 packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx diff --git a/.changeset/eight-insects-tan.md b/.changeset/eight-insects-tan.md index 0223b0d275..6f4d65275f 100644 --- a/.changeset/eight-insects-tan.md +++ b/.changeset/eight-insects-tan.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Add SidebarPageContent component and useContenRef hook to have a reference to content wrapper element +Add `LayoutProvider` component and `useLayoutContent` hook to have a reference to current main content element diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 296c1ad011..11eefcf8b4 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -571,6 +571,11 @@ enum LabelPosition { RIGHT = 'r', } +// Warning: (ae-missing-release-tag) "LayoutProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function LayoutProvider(props: PropsWithChildren<{}>): JSX.Element; + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Lifecycle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1237,24 +1242,6 @@ export function SidebarPage(props: SidebarPageProps): JSX.Element; // @public (undocumented) export type SidebarPageClassKey = 'root'; -// @public -export type SidebarPageProps = { - children?: React_2.ReactNode; -}; - -// @public -// Warning: (ae-missing-release-tag) "SidebarPageContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export function SidebarPageContent(props: PropsWithChildren<{}>): JSX.Element; - -// Warning: (ae-missing-release-tag) "SidebarPageContextType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type SidebarPageContextType = { - contentRef?: React_2.MutableRefObject; -}; - // Warning: (ae-missing-release-tag) "SidebarPinStateContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -2419,12 +2406,13 @@ export function TrendLine( }, ): JSX.Element | null; -// Warning: (ae-missing-release-tag) "useContentRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useLayoutContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function useContentRef(): - | React_2.MutableRefObject - | undefined; +export function useLayoutContent(): { + focusContent: () => void; + contentRef: React_2.MutableRefObject | undefined; +}; // Warning: (ae-forgotten-export) The symbol "SetQueryParams" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "useQueryParamState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 2243cfc10c..477aad9fc9 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -144,7 +144,6 @@ const DesktopSidebar = (props: SidebarProps) => { if (isPinned || disableExpandOnHover) { return; } - focusContent(); if (hoverTimerRef.current) { clearTimeout(hoverTimerRef.current); hoverTimerRef.current = undefined; diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 3dc31a5d52..665468231b 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -22,7 +22,6 @@ import React, { useEffect, useState, } from 'react'; - import { sidebarConfig } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; diff --git a/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx b/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx deleted file mode 100644 index ca769e63cd..0000000000 --- a/packages/core-components/src/layout/Sidebar/SidebarPage.stories.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; -import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined'; -import React, { useCallback } from 'react'; -import { MemoryRouter } from 'react-router-dom'; -import { - Sidebar, - SidebarDivider, - SidebarIntro, - SidebarItem, - SidebarSearchField, - SidebarSpace, - SidebarPage, -} from '.'; -import { useLayoutContent } from '../LayoutProvider'; -import { PluginWithTable } from '../Page/Page.stories'; - -export default { - title: 'Layout/SidebarPage', - component: SidebarPage, - decorators: [ - (storyFn: () => JSX.Element) => ( - {storyFn()} - ), - ], -}; - -export const SampleSidebarPage = () => { - return ( - - - - - ); -}; - -function CustomSidebar() { - const { focusContent } = useLayoutContent(); - const handleSearch = (input: string) => { - focusContent(); - // eslint-disable-next-line no-console - console.log(input); - }; - - return ( - - - - - - - - - - - ); -} diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 99ce966d0a..2ee84199de 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -26,7 +26,6 @@ export type { SidebarSubmenuItemProps, SidebarSubmenuItemDropdownItem, } from './SidebarSubmenuItem'; - export type { SidebarClassKey, SidebarProps } from './Bar'; export { SidebarPage, diff --git a/plugins/search/src/components/SearchModal/SearchModal.tsx b/plugins/search/src/components/SearchModal/SearchModal.tsx index c7ca33005d..841e7e0fe8 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.tsx @@ -24,6 +24,7 @@ import { Grid, List, Paper, + useTheme, } from '@material-ui/core'; import LaunchIcon from '@material-ui/icons/Launch'; import { makeStyles } from '@material-ui/core/styles'; @@ -33,7 +34,7 @@ import { SearchResult } from '../SearchResult'; import { SearchContextProvider, useSearch } from '../SearchContext'; import { SearchResultPager } from '../SearchResultPager'; import { useRouteRef } from '@backstage/core-plugin-api'; -import { Link } from '@backstage/core-components'; +import { Link, useLayoutContent } from '@backstage/core-components'; import { rootRouteRef } from '../../plugin'; export interface SearchModalProps { @@ -60,10 +61,27 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { const getSearchLink = useRouteRef(rootRouteRef); const classes = useStyles(); - const { term } = useSearch(); + const { focusContent } = useLayoutContent(); + const { transitions } = useTheme(); + const { term, setTerm } = useSearch(); + const [value, setValue] = useState(term); + + useEffect(() => { + setValue(prevValue => (prevValue !== term ? term : prevValue)); + }, [term]); + + useDebounce(() => setTerm(value), 500, [value]); + + const handleQuery = (newValue: string) => { + setValue(newValue); + }; + + const handleClear = () => setValue(''); const handleResultClick = () => { toggleModal(); + handleClear(); + setTimeout(focusContent, transitions.duration.leavingScreen); }; const handleKeyPress = () => { @@ -94,7 +112,13 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { alignItems="center" > - + { + toggleModal(); + setTimeout(focusContent, transitions.duration.leavingScreen); + }} + to={`${getSearchLink()}?query=${value}`} + > View Full Results diff --git a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx index 26b9583660..16fd6deb36 100644 --- a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx +++ b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx @@ -19,7 +19,10 @@ import { useNavigate } from 'react-router-dom'; import { rootRouteRef } from '../../plugin'; import { useRouteRef, IconComponent } from '@backstage/core-plugin-api'; -import { SidebarSearchField, useContentRef } from '@backstage/core-components'; +import { + SidebarSearchField, + useLayoutContent, +} from '@backstage/core-components'; export type SidebarSearchProps = { icon?: IconComponent; @@ -27,15 +30,15 @@ export type SidebarSearchProps = { export const SidebarSearch = (props: SidebarSearchProps) => { const searchRoute = useRouteRef(rootRouteRef); - const contentRef = useContentRef(); + const { focusContent } = useLayoutContent(); const navigate = useNavigate(); const handleSearch = useCallback( (query: string): void => { const queryString = qs.stringify({ query }, { addQueryPrefix: true }); - contentRef?.current?.focus(); + focusContent(); navigate(`${searchRoute()}${queryString}`); }, - [navigate, searchRoute, contentRef], + [focusContent, navigate, searchRoute], ); return ( From 5bd03f03be84f7128659de5a61085c7099b90aa3 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Mon, 10 Jan 2022 17:51:55 +0100 Subject: [PATCH 05/11] fix conflict resolution Signed-off-by: Juan Pablo Garcia Ripa --- .../src/components/SearchModal/SearchModal.tsx | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/plugins/search/src/components/SearchModal/SearchModal.tsx b/plugins/search/src/components/SearchModal/SearchModal.tsx index 841e7e0fe8..101b58c334 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.tsx @@ -61,26 +61,12 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { const getSearchLink = useRouteRef(rootRouteRef); const classes = useStyles(); + const { term } = useSearch(); const { focusContent } = useLayoutContent(); const { transitions } = useTheme(); - const { term, setTerm } = useSearch(); - const [value, setValue] = useState(term); - - useEffect(() => { - setValue(prevValue => (prevValue !== term ? term : prevValue)); - }, [term]); - - useDebounce(() => setTerm(value), 500, [value]); - - const handleQuery = (newValue: string) => { - setValue(newValue); - }; - - const handleClear = () => setValue(''); const handleResultClick = () => { toggleModal(); - handleClear(); setTimeout(focusContent, transitions.duration.leavingScreen); }; @@ -117,7 +103,7 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { toggleModal(); setTimeout(focusContent, transitions.duration.leavingScreen); }} - to={`${getSearchLink()}?query=${value}`} + to={`${getSearchLink()}?query=${term}`} > View Full Results From 14b882a6968560f1cb8c2d21ab57b6955c35f573 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Mon, 10 Jan 2022 18:14:46 +0100 Subject: [PATCH 06/11] Move layout context to SidabarPage Signed-off-by: Juan Pablo Garcia Ripa --- .../src/layout/Content/Content.tsx | 4 +- .../layout/LayoutProvider/LayoutProvider.tsx | 59 ------------------- .../src/layout/LayoutProvider/index.ts | 16 ----- .../src/layout/Sidebar/Page.tsx | 34 ++++++++++- .../src/layout/Sidebar/index.ts | 2 +- .../components/SearchModal/SearchModal.tsx | 4 +- .../SidebarSearch/SidebarSearch.tsx | 7 +-- 7 files changed, 40 insertions(+), 86 deletions(-) delete mode 100644 packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx delete mode 100644 packages/core-components/src/layout/LayoutProvider/index.ts diff --git a/packages/core-components/src/layout/Content/Content.tsx b/packages/core-components/src/layout/Content/Content.tsx index 8d91d335be..a26f74710d 100644 --- a/packages/core-components/src/layout/Content/Content.tsx +++ b/packages/core-components/src/layout/Content/Content.tsx @@ -17,7 +17,7 @@ import { makeStyles, Theme } from '@material-ui/core/styles'; import classNames from 'classnames'; import React, { PropsWithChildren } from 'react'; -import { useLayoutContent } from '../LayoutProvider/LayoutProvider'; +import { useContent } from '../Sidebar'; /** @public */ export type BackstageContentClassKey = 'root' | 'stretch' | 'noPadding'; @@ -64,7 +64,7 @@ type Props = { export function Content(props: PropsWithChildren) { const { className, stretch, noPadding, children, ...restProps } = props; - const { contentRef } = useLayoutContent(); + const { contentRef } = useContent(); const classes = useStyles(); return ( diff --git a/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx b/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx deleted file mode 100644 index 1dcc91d817..0000000000 --- a/packages/core-components/src/layout/LayoutProvider/LayoutProvider.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React, { - createContext, - PropsWithChildren, - useCallback, - useContext, - useRef, -} from 'react'; - -export type LayoutContextType = { - content: { - contentRef?: React.MutableRefObject; - }; -}; - -const LayoutContext = createContext({ - content: { - contentRef: undefined, - }, -}); - -export function LayoutProvider(props: PropsWithChildren<{}>) { - const contentRef = useRef(null); - - const content = { - contentRef, - }; - - return ( - - {props.children} - - ); -} - -export function useLayoutContent() { - const { content } = useContext(LayoutContext); - - const focusContent = useCallback(() => { - content.contentRef?.current?.focus(); - }, [content]); - - return { focusContent, contentRef: content.contentRef }; -} diff --git a/packages/core-components/src/layout/LayoutProvider/index.ts b/packages/core-components/src/layout/LayoutProvider/index.ts deleted file mode 100644 index 4f8b38f7e9..0000000000 --- a/packages/core-components/src/layout/LayoutProvider/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { LayoutProvider, useLayoutContent } from './LayoutProvider'; diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 665468231b..7192bbf4fa 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -19,7 +19,10 @@ import { makeStyles } from '@material-ui/core/styles'; import React, { createContext, PropsWithChildren, + useCallback, + useContext, useEffect, + useRef, useState, } from 'react'; import { sidebarConfig } from './config'; @@ -89,11 +92,28 @@ export const SidebarPinStateContext = createContext( }, ); +type PageContextType = { + content: { + contentRef?: React.MutableRefObject; + }; +}; + +const PageContext = createContext({ + content: { + contentRef: undefined, + }, +}); export function SidebarPage(props: SidebarPageProps) { const [isPinned, setIsPinned] = useState(() => LocalStorage.getSidebarPinState(), ); + const contentRef = useRef(null); + + const content = { + contentRef, + }; + useEffect(() => { LocalStorage.setSidebarPinState(isPinned); }, [isPinned]); @@ -114,7 +134,19 @@ export function SidebarPage(props: SidebarPageProps) { isMobile, }} > -
{props.children}
+ +
{props.children}
+
); } + +export function useContent() { + const { content } = useContext(PageContext); + + const focusContent = useCallback(() => { + content?.contentRef?.current?.focus(); + }, [content]); + + return { focusContent, contentRef: content?.contentRef }; +} diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 2ee84199de..96fedaa75a 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -30,13 +30,13 @@ export type { SidebarClassKey, SidebarProps } from './Bar'; export { SidebarPage, SidebarPinStateContext as SidebarPinStateContext, + useContent, } from './Page'; export type { SidebarPinStateContextType as SidebarPinStateContextType, SidebarPageClassKey, SidebarPageProps, } from './Page'; - export { SidebarDivider, SidebarItem, diff --git a/plugins/search/src/components/SearchModal/SearchModal.tsx b/plugins/search/src/components/SearchModal/SearchModal.tsx index 101b58c334..1f0a879f96 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.tsx @@ -34,7 +34,7 @@ import { SearchResult } from '../SearchResult'; import { SearchContextProvider, useSearch } from '../SearchContext'; import { SearchResultPager } from '../SearchResultPager'; import { useRouteRef } from '@backstage/core-plugin-api'; -import { Link, useLayoutContent } from '@backstage/core-components'; +import { Link, useContent } from '@backstage/core-components'; import { rootRouteRef } from '../../plugin'; export interface SearchModalProps { @@ -62,7 +62,7 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { const classes = useStyles(); const { term } = useSearch(); - const { focusContent } = useLayoutContent(); + const { focusContent } = useContent(); const { transitions } = useTheme(); const handleResultClick = () => { diff --git a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx index 16fd6deb36..25d41fa10f 100644 --- a/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx +++ b/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx @@ -19,10 +19,7 @@ import { useNavigate } from 'react-router-dom'; import { rootRouteRef } from '../../plugin'; import { useRouteRef, IconComponent } from '@backstage/core-plugin-api'; -import { - SidebarSearchField, - useLayoutContent, -} from '@backstage/core-components'; +import { SidebarSearchField, useContent } from '@backstage/core-components'; export type SidebarSearchProps = { icon?: IconComponent; @@ -30,7 +27,7 @@ export type SidebarSearchProps = { export const SidebarSearch = (props: SidebarSearchProps) => { const searchRoute = useRouteRef(rootRouteRef); - const { focusContent } = useLayoutContent(); + const { focusContent } = useContent(); const navigate = useNavigate(); const handleSearch = useCallback( (query: string): void => { From ec67d27cb21d1a4943b5c333039d30798956dbbd Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Tue, 11 Jan 2022 18:13:09 +0100 Subject: [PATCH 07/11] remove layoutProvider references Signed-off-by: Juan Pablo Garcia Ripa --- .changeset/eight-insects-tan.md | 2 +- packages/app/src/App.tsx | 13 +++++-------- packages/core-components/api-report.md | 9 ++------- packages/core-components/src/layout/Sidebar/Bar.tsx | 5 ++--- packages/core-components/src/layout/index.ts | 1 - 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/.changeset/eight-insects-tan.md b/.changeset/eight-insects-tan.md index 6f4d65275f..d9bb899225 100644 --- a/.changeset/eight-insects-tan.md +++ b/.changeset/eight-insects-tan.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Add `LayoutProvider` component and `useLayoutContent` hook to have a reference to current main content element +Add `useContent` hook to have a reference to the current main content element diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 421b21790c..59f107c70d 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -30,7 +30,6 @@ import { createApp } from '@backstage/app-defaults'; import { FlatRoutes } from '@backstage/core-app-api'; import { AlertDisplay, - LayoutProvider, OAuthRequestDialog, SignInPage, } from '@backstage/core-components'; @@ -226,13 +225,11 @@ const routes = ( const App = () => ( - - - - - {routes} - - + + + + {routes} + ); diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 11eefcf8b4..19c8a737ec 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -571,11 +571,6 @@ enum LabelPosition { RIGHT = 'r', } -// Warning: (ae-missing-release-tag) "LayoutProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export function LayoutProvider(props: PropsWithChildren<{}>): JSX.Element; - // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Lifecycle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2406,10 +2401,10 @@ export function TrendLine( }, ): JSX.Element | null; -// Warning: (ae-missing-release-tag) "useLayoutContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "useContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function useLayoutContent(): { +export function useContent(): { focusContent: () => void; contentRef: React_2.MutableRefObject | undefined; }; diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 477aad9fc9..c5384c323d 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -23,11 +23,10 @@ import Button from '@material-ui/core/Button'; import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; -import { SidebarPinStateContext } from './Page'; +import { SidebarPinStateContext, useContent } from './Page'; import { MobileSidebar } from './MobileSidebar'; import DoubleArrowRight from './icons/DoubleArrowRight'; import DoubleArrowLeft from './icons/DoubleArrowLeft'; -import { useLayoutContent } from '../LayoutProvider/LayoutProvider'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; @@ -230,7 +229,7 @@ export const Sidebar = (props: SidebarProps) => { }; function A11ySkipSidebar() { - const { focusContent, contentRef } = useLayoutContent(); + const { focusContent, contentRef } = useContent(); const classes = useStyles(); if (!contentRef?.current) { diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts index 06ee5d1d4c..9bb7fbaa26 100644 --- a/packages/core-components/src/layout/index.ts +++ b/packages/core-components/src/layout/index.ts @@ -31,4 +31,3 @@ export * from './Sidebar'; export * from './SignInPage'; export * from './TabbedCard'; export * from './Breadcrumbs'; -export * from './LayoutProvider'; From 9f0d178a51facc8753cff5c84735e14edbe059bb Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Fri, 14 Jan 2022 18:46:52 +0100 Subject: [PATCH 08/11] apply last feedback Signed-off-by: Juan Pablo Garcia Ripa --- packages/core-components/api-report.md | 11 +++++++---- .../core-components/src/layout/Sidebar/Bar.tsx | 5 +---- .../src/layout/Sidebar/Page.tsx | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 19c8a737ec..cce663b8d0 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1237,9 +1237,12 @@ export function SidebarPage(props: SidebarPageProps): JSX.Element; // @public (undocumented) export type SidebarPageClassKey = 'root'; -// Warning: (ae-missing-release-tag) "SidebarPinStateContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public +export type SidebarPageProps = { + children?: React_2.ReactNode; +}; + +// @public export const SidebarPinStateContext: React_2.Context; // @public @@ -2406,7 +2409,7 @@ export function TrendLine( // @public (undocumented) export function useContent(): { focusContent: () => void; - contentRef: React_2.MutableRefObject | undefined; + contentRef: React_2.MutableRefObject | undefined; }; // Warning: (ae-forgotten-export) The symbol "SetQueryParams" needs to be exported by the entry point index.d.ts diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index c5384c323d..e87f6f7613 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -18,15 +18,13 @@ 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 Button from '@material-ui/core/Button'; import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext, useContent } from './Page'; import { MobileSidebar } from './MobileSidebar'; -import DoubleArrowRight from './icons/DoubleArrowRight'; -import DoubleArrowLeft from './icons/DoubleArrowLeft'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; @@ -119,7 +117,6 @@ const DesktopSidebar = (props: SidebarProps) => { const { isPinned, toggleSidebarPinState } = useContext( SidebarPinStateContext, ); - const { focusContent } = useLayoutContent(); const handleOpen = () => { if (isPinned || disableExpandOnHover) { diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 7192bbf4fa..00377d8786 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -18,10 +18,10 @@ import { makeStyles } from '@material-ui/core/styles'; import React, { createContext, - PropsWithChildren, useCallback, useContext, useEffect, + useMemo, useRef, useState, } from 'react'; @@ -94,7 +94,7 @@ export const SidebarPinStateContext = createContext( type PageContextType = { content: { - contentRef?: React.MutableRefObject; + contentRef?: React.MutableRefObject; }; }; @@ -110,9 +110,14 @@ export function SidebarPage(props: SidebarPageProps) { const contentRef = useRef(null); - const content = { - contentRef, - }; + const pageContext = useMemo( + () => ({ + content: { + contentRef, + }, + }), + [contentRef], + ); useEffect(() => { LocalStorage.setSidebarPinState(isPinned); @@ -126,6 +131,7 @@ export function SidebarPage(props: SidebarPageProps) { const toggleSidebarPinState = () => setIsPinned(!isPinned); const classes = useStyles({ isPinned }); + return ( - +
{props.children}
From 1523926507ea155442532ff0a5d67b10a8a312fe Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Tue, 18 Jan 2022 18:58:51 +0100 Subject: [PATCH 09/11] add documentation and changeset Signed-off-by: Juan Pablo Garcia Ripa --- .changeset/eight-insects-tan.md | 3 ++- .changeset/eleven-sloths-shake.md | 5 +++++ .../src/layout/Sidebar/Page.tsx | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .changeset/eleven-sloths-shake.md diff --git a/.changeset/eight-insects-tan.md b/.changeset/eight-insects-tan.md index d9bb899225..13a53b227a 100644 --- a/.changeset/eight-insects-tan.md +++ b/.changeset/eight-insects-tan.md @@ -2,4 +2,5 @@ '@backstage/core-components': patch --- -Add `useContent` hook to have a reference to the current main content element +- Add `useContent` hook to have a reference to the current main content element +- Sets the main content reference on `Content` component diff --git a/.changeset/eleven-sloths-shake.md b/.changeset/eleven-sloths-shake.md new file mode 100644 index 0000000000..64602b561d --- /dev/null +++ b/.changeset/eleven-sloths-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Removes the focus from the sidebar and focus the main content after select one search result or navigate to the search result list diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 00377d8786..2a851b0a5c 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -147,6 +147,25 @@ export function SidebarPage(props: SidebarPageProps) { ); } +/** + * This hook provides a react ref to the main content. + * Allows to set an element as the main content and focus on that component. + * + * *Note: If `contentRef` is not set `focusContent` is noop. `Content` component sets this ref automaticaly* + * + * @public + * @example + * const { focusContent} = useContent(); + * ... + * + * + * @example + * const { contentRef } = useContent(); + * ... + *
Main Content
+ */ export function useContent() { const { content } = useContext(PageContext); From 48d75dcc2adc2c0b6510d2387b28917a59494036 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Tue, 18 Jan 2022 19:11:33 +0100 Subject: [PATCH 10/11] fix api report Signed-off-by: Juan Pablo Garcia Ripa --- packages/core-components/api-report.md | 12 +++++------- packages/core-components/src/layout/Sidebar/Page.tsx | 7 ++++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index cce663b8d0..8bf3f4b92d 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -916,7 +916,6 @@ export const SidebarDivider: React_2.ComponentType< | 'translate' | 'prefix' | 'children' - | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -925,6 +924,7 @@ export const SidebarDivider: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' + | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1278,7 +1278,6 @@ export const SidebarScrollWrapper: React_2.ComponentType< | 'translate' | 'prefix' | 'children' - | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1287,6 +1286,7 @@ export const SidebarScrollWrapper: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' + | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1553,7 +1553,6 @@ export const SidebarSpace: React_2.ComponentType< | 'translate' | 'prefix' | 'children' - | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1562,6 +1561,7 @@ export const SidebarSpace: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' + | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1827,7 +1827,6 @@ export const SidebarSpacer: React_2.ComponentType< | 'translate' | 'prefix' | 'children' - | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1836,6 +1835,7 @@ export const SidebarSpacer: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' + | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -2404,9 +2404,7 @@ export function TrendLine( }, ): JSX.Element | null; -// Warning: (ae-missing-release-tag) "useContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export function useContent(): { focusContent: () => void; contentRef: React_2.MutableRefObject | undefined; diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 2a851b0a5c..3b0efb62c1 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -155,16 +155,21 @@ export function SidebarPage(props: SidebarPageProps) { * * @public * @example + * Focus current content + * ```tsx * const { focusContent} = useContent(); * ... * - * + * ``` * @example + * Set the reference to an Html element + * ``` * const { contentRef } = useContent(); * ... *
Main Content
+ * ``` */ export function useContent() { const { content } = useContext(PageContext); From 59732bb11f46b5cbf89f5d6131938cf097174d87 Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Tue, 18 Jan 2022 19:20:55 +0100 Subject: [PATCH 11/11] fix api-report changes Signed-off-by: Juan Pablo Garcia Ripa --- packages/core-components/api-report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 8bf3f4b92d..eba86f65d1 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -916,6 +916,7 @@ export const SidebarDivider: React_2.ComponentType< | 'translate' | 'prefix' | 'children' + | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -924,7 +925,6 @@ export const SidebarDivider: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' - | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1278,6 +1278,7 @@ export const SidebarScrollWrapper: React_2.ComponentType< | 'translate' | 'prefix' | 'children' + | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1286,7 +1287,6 @@ export const SidebarScrollWrapper: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' - | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1553,6 +1553,7 @@ export const SidebarSpace: React_2.ComponentType< | 'translate' | 'prefix' | 'children' + | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1561,7 +1562,6 @@ export const SidebarSpace: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' - | 'id' | 'lang' | 'placeholder' | 'spellCheck' @@ -1827,6 +1827,7 @@ export const SidebarSpacer: React_2.ComponentType< | 'translate' | 'prefix' | 'children' + | 'id' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' @@ -1835,7 +1836,6 @@ export const SidebarSpacer: React_2.ComponentType< | 'contentEditable' | 'contextMenu' | 'draggable' - | 'id' | 'lang' | 'placeholder' | 'spellCheck'