Merge pull request #26060 from joshjung/jjung/custom-modal-search-items
Add ability to customize SearchResult children via SidebarSearchModal component
This commit is contained in:
@@ -30,7 +30,7 @@ This search plugin is primarily responsible for the following:
|
||||
|
||||
- Providing a `<SearchPage />` routable extension.
|
||||
- Exposing various search-related components (like `<SearchModal />`,
|
||||
`<SidebarSearch />`, etc), which can be composed by a Backstage App or by
|
||||
`<SidebarSearch />`, etc.), which can be composed by a Backstage App or by
|
||||
other Backstage Plugins to power search experiences of all kinds.
|
||||
|
||||
Don't forget, a lot of functionality is available in web libraries and backend plugins:
|
||||
|
||||
@@ -12,6 +12,7 @@ import { default as React_2 } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { SearchBarBaseProps } from '@backstage/plugin-search-react';
|
||||
import { SearchResultSet } from '@backstage/plugin-search-common';
|
||||
|
||||
// @public (undocumented)
|
||||
export const HomePageSearchBar: (
|
||||
@@ -31,6 +32,9 @@ export const SearchModal: (props: SearchModalProps) => React_2.JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SearchModalChildrenProps {
|
||||
resultItemComponents?:
|
||||
| ReactNode
|
||||
| ((resultSet: SearchResultSet) => JSX.Element);
|
||||
toggleModal: () => void;
|
||||
}
|
||||
|
||||
@@ -39,6 +43,7 @@ export interface SearchModalProps {
|
||||
children?: (props: SearchModalChildrenProps) => JSX.Element;
|
||||
hidden?: boolean;
|
||||
open?: boolean;
|
||||
resultItemComponents?: SearchModalChildrenProps['resultItemComponents'];
|
||||
toggleModal: () => void;
|
||||
}
|
||||
|
||||
@@ -118,12 +123,14 @@ export const SidebarSearch: (props: SidebarSearchProps) => React_2.JSX.Element;
|
||||
// @public (undocumented)
|
||||
export const SidebarSearchModal: (
|
||||
props: SidebarSearchModalProps,
|
||||
) => JSX_2.Element;
|
||||
) => JSX.Element | null;
|
||||
|
||||
// @public
|
||||
export type SidebarSearchModalProps = {
|
||||
export type SidebarSearchModalProps = Pick<
|
||||
SearchModalProps,
|
||||
'children' | 'resultItemComponents'
|
||||
> & {
|
||||
icon?: IconComponent;
|
||||
children?: (props: SearchModalChildrenProps) => JSX.Element;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -34,10 +34,11 @@ import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import React, { ReactNode, useCallback, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { rootRouteRef } from '../../plugin';
|
||||
import { SearchResultSet } from '@backstage/plugin-search-common';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -47,6 +48,13 @@ export interface SearchModalChildrenProps {
|
||||
* A function that should be invoked when navigating away from the modal.
|
||||
*/
|
||||
toggleModal: () => void;
|
||||
|
||||
/**
|
||||
* Ability to provide custom components to render the result items
|
||||
*/
|
||||
resultItemComponents?:
|
||||
| ReactNode
|
||||
| ((resultSet: SearchResultSet) => JSX.Element);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +82,11 @@ export interface SearchModalProps {
|
||||
* place of the default.
|
||||
*/
|
||||
children?: (props: SearchModalChildrenProps) => JSX.Element;
|
||||
|
||||
/**
|
||||
* Optional ability to pass in result item component renderers.
|
||||
*/
|
||||
resultItemComponents?: SearchModalChildrenProps['resultItemComponents'];
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
@@ -100,7 +113,10 @@ const useStyles = makeStyles(theme => ({
|
||||
viewResultsLink: { verticalAlign: '0.5em' },
|
||||
}));
|
||||
|
||||
export const Modal = ({ toggleModal }: SearchModalChildrenProps) => {
|
||||
export const Modal = ({
|
||||
toggleModal,
|
||||
resultItemComponents,
|
||||
}: SearchModalChildrenProps) => {
|
||||
const classes = useStyles();
|
||||
const navigate = useNavigate();
|
||||
const { transitions } = useTheme();
|
||||
@@ -163,7 +179,9 @@ export const Modal = ({ toggleModal }: SearchModalChildrenProps) => {
|
||||
<SearchResult
|
||||
onClick={handleSearchResultClick}
|
||||
onKeyDown={handleSearchResultClick}
|
||||
/>
|
||||
>
|
||||
{resultItemComponents}
|
||||
</SearchResult>
|
||||
</DialogContent>
|
||||
<DialogActions className={classes.dialogActionsContainer}>
|
||||
<Grid container direction="row">
|
||||
@@ -180,7 +198,13 @@ export const Modal = ({ toggleModal }: SearchModalChildrenProps) => {
|
||||
* @public
|
||||
*/
|
||||
export const SearchModal = (props: SearchModalProps) => {
|
||||
const { open = true, hidden, toggleModal, children } = props;
|
||||
const {
|
||||
open = true,
|
||||
hidden,
|
||||
toggleModal,
|
||||
children,
|
||||
resultItemComponents,
|
||||
} = props;
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
@@ -199,8 +223,15 @@ export const SearchModal = (props: SearchModalProps) => {
|
||||
>
|
||||
{open && (
|
||||
<SearchContextProvider inheritParentContextIfAvailable>
|
||||
{(children && children({ toggleModal })) ?? (
|
||||
<Modal toggleModal={toggleModal} />
|
||||
{(children &&
|
||||
children({
|
||||
toggleModal,
|
||||
resultItemComponents: resultItemComponents || [],
|
||||
})) ?? (
|
||||
<Modal
|
||||
toggleModal={toggleModal}
|
||||
resultItemComponents={resultItemComponents}
|
||||
/>
|
||||
)}
|
||||
</SearchContextProvider>
|
||||
)}
|
||||
|
||||
@@ -19,8 +19,9 @@ import { useSearch } from '@backstage/plugin-search-react';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Theme } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
tabs: {
|
||||
borderBottom: `1px solid ${theme.palette.textVerySubtle}`,
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ import { SidebarItem } from '@backstage/core-components';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
SearchModal,
|
||||
SearchModalChildrenProps,
|
||||
SearchModalProps,
|
||||
SearchModalProvider,
|
||||
useSearchModal,
|
||||
} from '../SearchModal';
|
||||
@@ -29,9 +29,11 @@ import {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SidebarSearchModalProps = {
|
||||
export type SidebarSearchModalProps = Pick<
|
||||
SearchModalProps,
|
||||
'children' | 'resultItemComponents'
|
||||
> & {
|
||||
icon?: IconComponent;
|
||||
children?: (props: SearchModalChildrenProps) => JSX.Element;
|
||||
};
|
||||
|
||||
const SidebarSearchModalContent = (props: SidebarSearchModalProps) => {
|
||||
@@ -49,6 +51,7 @@ const SidebarSearchModalContent = (props: SidebarSearchModalProps) => {
|
||||
<SearchModal
|
||||
{...state}
|
||||
toggleModal={toggleModal}
|
||||
resultItemComponents={props.resultItemComponents}
|
||||
children={props.children}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
createComponentExtension,
|
||||
fetchApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { SidebarSearchModalProps } from './components/SidebarSearchModal';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
id: 'search',
|
||||
@@ -63,7 +64,9 @@ export const SearchPage = searchPlugin.provide(
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const SidebarSearchModal = searchPlugin.provide(
|
||||
export const SidebarSearchModal = searchPlugin.provide<
|
||||
(props: SidebarSearchModalProps) => JSX.Element | null
|
||||
>(
|
||||
createComponentExtension({
|
||||
name: 'SidebarSearchModal',
|
||||
component: {
|
||||
|
||||
Reference in New Issue
Block a user