[Search] Standardizes input search components (#8532)
* refactor(plugin-search): customize search bar components Signed-off-by: Camila Belo <camilaibs@gmail.com> * refactor(plugin-search): use search bar in search modal Signed-off-by: Camila Belo <camilaibs@gmail.com> * refactor(plugin-search): customize home page search bar Signed-off-by: Camila Belo <camilaibs@gmail.com> * chore(plugin-search): update api reports Signed-off-by: Camila Belo <camilaibs@gmail.com> * chore: add changeset file Signed-off-by: Camila Belo <camilaibs@gmail.com> * apply review suggestions Signed-off-by: Camila Belo <camilaibs@gmail.com> * increase default debounceTime and remove prop from SearchBar in SearchModal + SearchPage in app Signed-off-by: Emma Indal <emmai@spotify.com> * update test using default debounce time Signed-off-by: Emma Indal <emmai@spotify.com> * add changeset for create-app Signed-off-by: Emma Indal <emmai@spotify.com> * fix exports after rebase Signed-off-by: Emma Indal <emmai@spotify.com> Co-authored-by: Emma Indal <emmai@spotify.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
debounceTime prop is removed from the SearchBar component in the SearchPage as the default is set to 200. The prop is safe to remove and makes it easier to stay up to date with any changes in the future.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Standardizes the component used as a search box in the search modal and in the composable home page.
|
||||
|
||||
After these changes, all search boxes exported by the search plugin are based on the `<SearchBarBase />` component, and this one is based on the `<InputBase />` component of the Material UI. This means that when you use SearchBarBase or one of its derived components (like `SearchBar` and `HomePageSearchBar`) you can pass all properties accepted by InputBase that have not been replaced by the props type of those components.
|
||||
|
||||
For example:
|
||||
|
||||
```jsx
|
||||
<SearchInputBase color="secondary" debouceTime={500} />
|
||||
```
|
||||
|
||||
The `color` property is inherited from `InputBaseProps` type and `debouceTime` defined by `SearchBarBaseProps`.
|
||||
+1
-1
@@ -37,7 +37,7 @@ const SearchPage = () => {
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.bar}>
|
||||
<SearchBar debounceTime={100} />
|
||||
<SearchBar />
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AsyncState } from 'react-use/lib/useAsync';
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { IndexableDocument } from '@backstage/search-common';
|
||||
import { InputBaseProps } from '@material-ui/core';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactElement } from 'react';
|
||||
@@ -65,10 +66,14 @@ export type FiltersState = {
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const HomePageSearchBar: ({
|
||||
placeholder,
|
||||
}: {
|
||||
placeholder?: string | undefined;
|
||||
}) => JSX.Element;
|
||||
className: defaultClassName,
|
||||
...props
|
||||
}: Partial<Omit<SearchBarBaseProps, 'onChange' | 'onSubmit'>>) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export type HomePageSearchBarProps = Partial<
|
||||
Omit<SearchBarBaseProps, 'onChange' | 'onSubmit'>
|
||||
>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -88,34 +93,42 @@ export interface SearchApi {
|
||||
// @public (undocumented)
|
||||
export const searchApiRef: ApiRef<SearchApi>;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const SearchBar: ({
|
||||
autoFocus,
|
||||
className,
|
||||
// @public
|
||||
export const SearchBar: ({ onChange, ...props }: SearchBarProps) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export const SearchBarBase: ({
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onSubmit,
|
||||
debounceTime,
|
||||
placeholder,
|
||||
clearButton,
|
||||
}: Props) => JSX.Element;
|
||||
fullWidth,
|
||||
value: defaultValue,
|
||||
inputProps: defaultInputProps,
|
||||
endAdornment: defaultEndAdornment,
|
||||
...props
|
||||
}: SearchBarBaseProps) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export type SearchBarBaseProps = Omit<InputBaseProps, 'onChange'> & {
|
||||
debounceTime?: number;
|
||||
clearButton?: boolean;
|
||||
onClear?: () => void;
|
||||
onSubmit?: () => void;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchBarNext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export const SearchBarNext: ({
|
||||
autoFocus,
|
||||
className,
|
||||
debounceTime,
|
||||
placeholder,
|
||||
clearButton,
|
||||
}: {
|
||||
autoFocus?: boolean | undefined;
|
||||
className?: string | undefined;
|
||||
debounceTime?: number | undefined;
|
||||
placeholder?: string | undefined;
|
||||
clearButton?: boolean | undefined;
|
||||
}) => JSX.Element;
|
||||
onChange,
|
||||
...props
|
||||
}: Partial<SearchBarBaseProps>) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export type SearchBarProps = Partial<SearchBarBaseProps>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchContextProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -131,18 +144,18 @@ export const SearchContextProvider: ({
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const SearchFilter: {
|
||||
({ component: Element, ...props }: Props_2): JSX.Element;
|
||||
Checkbox(props: Omit<Props_2, 'component'> & Component): JSX.Element;
|
||||
Select(props: Omit<Props_2, 'component'> & Component): JSX.Element;
|
||||
({ component: Element, ...props }: Props): JSX.Element;
|
||||
Checkbox(props: Omit<Props, 'component'> & Component): JSX.Element;
|
||||
Select(props: Omit<Props, 'component'> & Component): JSX.Element;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchFilterNext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export const SearchFilterNext: {
|
||||
({ component: Element, ...props }: Props_2): JSX.Element;
|
||||
Checkbox(props: Omit<Props_2, 'component'> & Component): JSX.Element;
|
||||
Select(props: Omit<Props_2, 'component'> & Component): JSX.Element;
|
||||
({ component: Element, ...props }: Props): JSX.Element;
|
||||
Checkbox(props: Omit<Props, 'component'> & Component): JSX.Element;
|
||||
Select(props: Omit<Props, 'component'> & Component): JSX.Element;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchModal" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
import { SearchBarBase } from '../SearchBar';
|
||||
import { SearchBarBase, SearchBarBaseProps } from '../SearchBar';
|
||||
import { useNavigateToQuery } from '../util';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -28,20 +28,37 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
placeholder?: string;
|
||||
};
|
||||
/**
|
||||
* Props for {@link HomePageSearchBar}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type HomePageSearchBarProps = Partial<
|
||||
Omit<SearchBarBaseProps, 'onChange' | 'onSubmit'>
|
||||
>;
|
||||
|
||||
export const HomePageSearchBar = ({ placeholder }: Props) => {
|
||||
const [query, setQuery] = React.useState('');
|
||||
const handleSearch = useNavigateToQuery();
|
||||
/**
|
||||
* The search bar created specifically for the composable home page
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const HomePageSearchBar = ({
|
||||
className: defaultClassName,
|
||||
...props
|
||||
}: HomePageSearchBarProps) => {
|
||||
const classes = useStyles();
|
||||
const [query, setQuery] = useState('');
|
||||
const handleSearch = useNavigateToQuery();
|
||||
|
||||
const className = defaultClassName
|
||||
? `${classes.searchBar} ${defaultClassName}`
|
||||
: classes.searchBar;
|
||||
|
||||
const handleSubmit = () => {
|
||||
handleSearch({ query });
|
||||
};
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
const handleChange = useCallback(
|
||||
value => {
|
||||
setQuery(value);
|
||||
},
|
||||
@@ -50,11 +67,11 @@ export const HomePageSearchBar = ({ placeholder }: Props) => {
|
||||
|
||||
return (
|
||||
<SearchBarBase
|
||||
className={className}
|
||||
value={query}
|
||||
onSubmit={handleSubmit}
|
||||
onChange={handleChange}
|
||||
value={query}
|
||||
className={classes.searchBar}
|
||||
placeholder={placeholder}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { HomePageSearchBar } from './HomePageSearchBar';
|
||||
export type { HomePageSearchBarProps } from './HomePageSearchBar';
|
||||
|
||||
@@ -101,6 +101,9 @@ describe('SearchBar', () => {
|
||||
});
|
||||
|
||||
it('Updates term state when text is entered', async () => {
|
||||
jest.useFakeTimers();
|
||||
const defaultDebounceTime = 200;
|
||||
|
||||
render(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<SearchContextProvider initialState={initialState}>
|
||||
@@ -116,6 +119,10 @@ describe('SearchBar', () => {
|
||||
|
||||
userEvent.type(textbox, value);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(defaultDebounceTime);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(textbox).toHaveValue(value);
|
||||
});
|
||||
|
||||
@@ -14,128 +14,145 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, KeyboardEvent, useState } from 'react';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import React, {
|
||||
ChangeEvent,
|
||||
KeyboardEvent,
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import { useDebounce } from 'react-use';
|
||||
import { InputBase, InputAdornment, IconButton } from '@material-ui/core';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
InputBase,
|
||||
InputBaseProps,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
} from '@material-ui/core';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import ClearButton from '@material-ui/icons/Clear';
|
||||
|
||||
import { useSearch } from '../SearchContext';
|
||||
|
||||
type PresenterProps = {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
/**
|
||||
* Props for {@link SearchBarBase}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchBarBaseProps = Omit<InputBaseProps, 'onChange'> & {
|
||||
debounceTime?: number;
|
||||
clearButton?: boolean;
|
||||
onClear?: () => void;
|
||||
onSubmit?: () => void;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
autoFocus?: boolean;
|
||||
clearButton?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* All search boxes exported by the search plugin are based on the <SearchBarBase />,
|
||||
* and this one is based on the <InputBase /> component from Material UI.
|
||||
* Recommended if you don't use Search Provider or Search Context.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const SearchBarBase = ({
|
||||
autoFocus,
|
||||
value,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onSubmit,
|
||||
className,
|
||||
placeholder: overridePlaceholder,
|
||||
debounceTime = 200,
|
||||
clearButton = true,
|
||||
}: PresenterProps) => {
|
||||
fullWidth = true,
|
||||
value: defaultValue,
|
||||
inputProps: defaultInputProps = {},
|
||||
endAdornment: defaultEndAdornment,
|
||||
...props
|
||||
}: SearchBarBaseProps) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const [value, setValue] = useState<string>(defaultValue as string);
|
||||
|
||||
const onKeyDown = React.useCallback(
|
||||
useEffect(() => {
|
||||
setValue(prevValue =>
|
||||
prevValue !== defaultValue ? (defaultValue as string) : prevValue,
|
||||
);
|
||||
}, [defaultValue]);
|
||||
|
||||
useDebounce(() => onChange(value), debounceTime, [value]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(e.target.value);
|
||||
},
|
||||
[setValue],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (onKeyDown) onKeyDown(e);
|
||||
if (onSubmit && e.key === 'Enter') {
|
||||
onSubmit();
|
||||
}
|
||||
},
|
||||
[onSubmit],
|
||||
[onKeyDown, onSubmit],
|
||||
);
|
||||
|
||||
const handleClear = React.useCallback(() => {
|
||||
const handleClear = useCallback(() => {
|
||||
onChange('');
|
||||
}, [onChange]);
|
||||
|
||||
const placeholder =
|
||||
overridePlaceholder ??
|
||||
`Search in ${configApi.getOptionalString('app.title') || 'Backstage'}`;
|
||||
const placeholder = `Search in ${
|
||||
configApi.getOptionalString('app.title') || 'Backstage'
|
||||
}`;
|
||||
|
||||
const startAdornment = (
|
||||
<InputAdornment position="start">
|
||||
<IconButton aria-label="Query" disabled>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
);
|
||||
|
||||
const endAdornment = (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label="Clear" onClick={handleClear}>
|
||||
<ClearButton />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
);
|
||||
|
||||
return (
|
||||
<InputBase
|
||||
// decision up to adopter, read https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md#no-autofocus
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={autoFocus}
|
||||
data-testid="search-bar-next"
|
||||
fullWidth
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
inputProps={{ 'aria-label': 'Search' }}
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<IconButton aria-label="Query" disabled>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
endAdornment={
|
||||
clearButton && (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label="Clear" onClick={handleClear}>
|
||||
<ClearButton />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
)
|
||||
}
|
||||
{...(className && { className })}
|
||||
{...(onSubmit && { onKeyDown })}
|
||||
placeholder={placeholder}
|
||||
startAdornment={startAdornment}
|
||||
endAdornment={clearButton ? endAdornment : defaultEndAdornment}
|
||||
inputProps={{ 'aria-label': 'Search', ...defaultInputProps }}
|
||||
fullWidth={fullWidth}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {
|
||||
autoFocus?: boolean;
|
||||
className?: string;
|
||||
debounceTime?: number;
|
||||
placeholder?: string;
|
||||
clearButton?: boolean;
|
||||
};
|
||||
/**
|
||||
* Props for {@link SearchBar}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchBarProps = Partial<SearchBarBaseProps>;
|
||||
|
||||
export const SearchBar = ({
|
||||
autoFocus,
|
||||
className,
|
||||
debounceTime = 0,
|
||||
placeholder,
|
||||
clearButton = true,
|
||||
}: Props) => {
|
||||
/**
|
||||
* Recommended search bar when you use the Search Provider or Search Context.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const SearchBar = ({ onChange, ...props }: SearchBarProps) => {
|
||||
const { term, setTerm } = useSearch();
|
||||
const [value, setValue] = useState<string>(term);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(prevValue => (prevValue !== term ? term : prevValue));
|
||||
}, [term]);
|
||||
|
||||
useDebounce(() => setTerm(value), debounceTime, [value]);
|
||||
|
||||
const handleQuery = (newValue: string) => {
|
||||
setValue(newValue);
|
||||
const handleChange = (newValue: string) => {
|
||||
setTerm(newValue);
|
||||
if (onChange) onChange(newValue);
|
||||
};
|
||||
|
||||
const handleClear = () => setValue('');
|
||||
|
||||
return (
|
||||
<SearchBarBase
|
||||
// decision up to adopter, read https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md#no-autofocus
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={autoFocus}
|
||||
className={className}
|
||||
value={value}
|
||||
onChange={handleQuery}
|
||||
onClear={handleClear}
|
||||
placeholder={placeholder}
|
||||
clearButton={clearButton}
|
||||
/>
|
||||
);
|
||||
return <SearchBarBase value={term} onChange={handleChange} {...props} />;
|
||||
};
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { SearchBar, SearchBarBase } from './SearchBar';
|
||||
export type { SearchBarProps, SearchBarBaseProps } from './SearchBar';
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogActions,
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from '@material-ui/core';
|
||||
import { Launch } from '@material-ui/icons/';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { SearchBarBase } from '../SearchBar';
|
||||
import { SearchBar } from '../SearchBar';
|
||||
import { DefaultResultListItem } from '../DefaultResultListItem';
|
||||
import { SearchResult } from '../SearchResult';
|
||||
import { SearchContextProvider, useSearch } from '../SearchContext';
|
||||
@@ -35,8 +35,6 @@ import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { rootRouteRef } from '../../plugin';
|
||||
|
||||
import { useDebounce } from 'react-use';
|
||||
|
||||
export interface SearchModalProps {
|
||||
open?: boolean;
|
||||
toggleModal: () => void;
|
||||
@@ -61,24 +59,10 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => {
|
||||
const getSearchLink = useRouteRef(rootRouteRef);
|
||||
const classes = useStyles();
|
||||
|
||||
const { term, setTerm } = useSearch();
|
||||
const [value, setValue] = useState<string>(term);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(prevValue => (prevValue !== term ? term : prevValue));
|
||||
}, [term]);
|
||||
|
||||
useDebounce(() => setTerm(value), 500, [value]);
|
||||
|
||||
const handleQuery = (newValue: string) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const handleClear = () => setValue('');
|
||||
const { term } = useSearch();
|
||||
|
||||
const handleResultClick = () => {
|
||||
toggleModal();
|
||||
handleClear();
|
||||
};
|
||||
|
||||
const handleKeyPress = () => {
|
||||
@@ -98,12 +82,7 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => {
|
||||
>
|
||||
<DialogTitle>
|
||||
<Paper className={classes.container}>
|
||||
<SearchBarBase
|
||||
className={classes.input}
|
||||
value={value}
|
||||
onChange={handleQuery}
|
||||
onClear={handleClear}
|
||||
/>
|
||||
<SearchBar className={classes.input} />
|
||||
</Paper>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
@@ -114,10 +93,7 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Grid item>
|
||||
<Link
|
||||
onClick={toggleModal}
|
||||
to={`${getSearchLink()}?query=${value}`}
|
||||
>
|
||||
<Link onClick={toggleModal} to={`${getSearchLink()}?query=${term}`}>
|
||||
<span className={classes.viewResultsLink}>View Full Results</span>
|
||||
<Launch color="primary" />
|
||||
</Link>
|
||||
|
||||
@@ -26,3 +26,4 @@ export * from './SearchResultPager';
|
||||
export * from './SearchType';
|
||||
export * from './SidebarSearch';
|
||||
export * from './SidebarSearchModal';
|
||||
export * from './HomePageComponent';
|
||||
|
||||
@@ -26,6 +26,7 @@ export {
|
||||
Filters,
|
||||
FiltersButton,
|
||||
SearchBar,
|
||||
SearchBarBase,
|
||||
SearchContextProvider,
|
||||
SearchFilter,
|
||||
SearchFilterNext,
|
||||
@@ -39,9 +40,12 @@ export {
|
||||
export type {
|
||||
SearchModalProps,
|
||||
SidebarSearchModalProps,
|
||||
HomePageSearchBarProps,
|
||||
SidebarSearchProps,
|
||||
FiltersState,
|
||||
SearchBarProps,
|
||||
SearchBarBaseProps,
|
||||
} from './components';
|
||||
export type { FiltersState } from './components';
|
||||
export {
|
||||
DefaultResultListItem,
|
||||
HomePageSearchBar,
|
||||
|
||||
Reference in New Issue
Block a user