@backstage/plugin-search-react 0.1.1-next.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # @backstage/plugin-search-react
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bdbe620797: **BREAKING**: `SearchContextProviderForStorybook` and `SearchApiProviderForStorybook` has been deleted. New mock implementation of the `SearchApi` introduced. If you need to mock the api we recommend you to do the following:
8
+
9
+ ```tsx
10
+ import {
11
+ searchApiRef,
12
+ MockSearchApi,
13
+ SearchContextProvider,
14
+ } from '@backstage/plugin-search-react';
15
+ import { TestApiProvider } from '@backstage/test-utils';
16
+
17
+ <TestApiProvider apis={[[searchApiRef, new MockSearchApi()]]}>
18
+ <SearchContextProvider>
19
+ <Component />
20
+ </SearchContextProvider>
21
+ </TestApiProvider>;
22
+ ```
23
+
24
+ ### Patch Changes
25
+
26
+ - 11a46863de: Export `useSearchContextCheck` hook to check if the search context is available
27
+ - a307a14be0: Removed dependency on `@backstage/core-app-api`.
28
+ - 3a74e203a8: Updated search result components to support rendering content with highlighted matched terms
29
+ - Updated dependencies
30
+ - @backstage/core-plugin-api@1.0.2
31
+ - @backstage/plugin-search-common@0.3.4
32
+
33
+ ## 0.2.0-next.2
34
+
35
+ ### Patch Changes
36
+
37
+ - 3a74e203a8: Updated search result components to support rendering content with highlighted matched terms
38
+ - Updated dependencies
39
+ - @backstage/plugin-search-common@0.3.4-next.0
40
+ - @backstage/core-plugin-api@1.0.2-next.1
41
+
42
+ ## 0.2.0-next.1
43
+
44
+ ### Minor Changes
45
+
46
+ - bdbe620797: **BREAKING**: `SearchContextProviderForStorybook` and `SearchApiProviderForStorybook` has been deleted. New mock implementation of the `SearchApi` introduced. If you need to mock the api we recommend you to do the following:
47
+
48
+ ```tsx
49
+ import {
50
+ searchApiRef,
51
+ MockSearchApi,
52
+ SearchContextProvider,
53
+ } from '@backstage/plugin-search-react';
54
+ import { TestApiProvider } from '@backstage/test-utils';
55
+
56
+ <TestApiProvider apis={[[searchApiRef, new MockSearchApi()]]}>
57
+ <SearchContextProvider>
58
+ <Component />
59
+ </SearchContextProvider>
60
+ </TestApiProvider>;
61
+ ```
62
+
63
+ ### Patch Changes
64
+
65
+ - Updated dependencies
66
+ - @backstage/core-plugin-api@1.0.2-next.0
67
+
3
68
  ## 0.1.1-next.0
4
69
 
5
70
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
+ /// <reference types="react" />
1
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
2
3
  import { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';
3
4
  import { JsonObject } from '@backstage/types';
4
- import React, { PropsWithChildren, ComponentProps } from 'react';
5
+ import React, { PropsWithChildren } from 'react';
5
6
  import { AsyncState } from 'react-use/lib/useAsync';
6
7
 
7
8
  /**
@@ -14,6 +15,29 @@ declare const searchApiRef: _backstage_core_plugin_api.ApiRef<SearchApi>;
14
15
  interface SearchApi {
15
16
  query(query: SearchQuery): Promise<SearchResultSet>;
16
17
  }
18
+ /**
19
+ * @public
20
+ *
21
+ * Search Api Mock that can be used in tests and storybooks
22
+ */
23
+ declare class MockSearchApi implements SearchApi {
24
+ mockedResults?: SearchResultSet | undefined;
25
+ constructor(mockedResults?: SearchResultSet | undefined);
26
+ query(): Promise<SearchResultSet>;
27
+ }
28
+
29
+ /**
30
+ * @public
31
+ */
32
+ declare type HighlightedSearchResultTextProps = {
33
+ text: string;
34
+ preTag: string;
35
+ postTag: string;
36
+ };
37
+ /**
38
+ * @public
39
+ */
40
+ declare const HighlightedSearchResultText: ({ text, preTag, postTag, }: HighlightedSearchResultTextProps) => JSX.Element;
17
41
 
18
42
  /**
19
43
  *
@@ -65,34 +89,4 @@ declare type SearchContextProviderProps = PropsWithChildren<{
65
89
  */
66
90
  declare const SearchContextProvider: (props: SearchContextProviderProps) => JSX.Element;
67
91
 
68
- /**
69
- * Props for {@link SearchApiProviderForStorybook}
70
- * @public
71
- */
72
- declare type SearchApiProviderForStorybookProps = ComponentProps<typeof SearchContextProvider> & {
73
- mockedResults?: SearchResultSet;
74
- };
75
- /**
76
- * Props for {@link SearchContextProviderForStorybook}
77
- * @public
78
- */
79
- declare type SearchContextProviderForStorybookProps = PropsWithChildren<{
80
- mockedResults?: SearchResultSet;
81
- }>;
82
- /**
83
- * Utility api provider only for use in Storybook stories.
84
- *
85
- * @public
86
- */
87
- declare function SearchApiProviderForStorybook(props: SearchApiProviderForStorybookProps): JSX.Element;
88
- /**
89
- * Utility context provider only for use in Storybook stories. You should use
90
- * the real `<SearchContextProvider>` exported by `@backstage/plugin-search-react` in
91
- * your app instead of this! In some cases (like the search page) it may
92
- * already be provided on your behalf.
93
- *
94
- * @public
95
- */
96
- declare const SearchContextProviderForStorybook: (props: SearchContextProviderForStorybookProps) => JSX.Element;
97
-
98
- export { SearchApi, SearchApiProviderForStorybook, SearchApiProviderForStorybookProps, SearchContextProvider, SearchContextProviderForStorybook, SearchContextProviderForStorybookProps, SearchContextProviderProps, SearchContextState, SearchContextValue, searchApiRef, useSearch, useSearchContextCheck };
92
+ export { HighlightedSearchResultText, HighlightedSearchResultTextProps, MockSearchApi, SearchApi, SearchContextProvider, SearchContextProviderProps, SearchContextState, SearchContextValue, searchApiRef, useSearch, useSearchContextCheck };
package/dist/index.esm.js CHANGED
@@ -1,14 +1,37 @@
1
1
  import { createApiRef, useApi, AnalyticsContext } from '@backstage/core-plugin-api';
2
+ import React, { useMemo, useContext, useState, useCallback, useEffect } from 'react';
3
+ import { makeStyles } from '@material-ui/core';
2
4
  import { createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
3
- import React, { useContext, useState, useCallback, useEffect } from 'react';
4
5
  import useAsync from 'react-use/lib/useAsync';
5
6
  import usePrevious from 'react-use/lib/usePrevious';
6
- import { ApiProvider } from '@backstage/core-app-api';
7
- import { TestApiRegistry } from '@backstage/test-utils';
8
7
 
9
8
  const searchApiRef = createApiRef({
10
9
  id: "plugin.search.queryservice"
11
10
  });
11
+ class MockSearchApi {
12
+ constructor(mockedResults) {
13
+ this.mockedResults = mockedResults;
14
+ }
15
+ query() {
16
+ return Promise.resolve(this.mockedResults || { results: [] });
17
+ }
18
+ }
19
+
20
+ const useStyles = makeStyles(() => ({
21
+ highlight: {}
22
+ }), { name: "BackstageHighlightedSearchResultText" });
23
+ const HighlightedSearchResultText = ({
24
+ text,
25
+ preTag,
26
+ postTag
27
+ }) => {
28
+ const classes = useStyles();
29
+ const terms = useMemo(() => text.split(new RegExp(`(${preTag}.+?${postTag})`)), [postTag, preTag, text]);
30
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, terms.map((t, idx) => t.includes(preTag) ? /* @__PURE__ */ React.createElement("mark", {
31
+ className: classes.highlight,
32
+ key: idx
33
+ }, t.replace(new RegExp(`${preTag}|${postTag}`, "g"), "")) : t));
34
+ };
12
35
 
13
36
  const SearchContext = createVersionedContext("search-context");
14
37
  const useSearch = () => {
@@ -84,22 +107,5 @@ const SearchContextProvider = (props) => {
84
107
  }));
85
108
  };
86
109
 
87
- function SearchApiProviderForStorybook(props) {
88
- const { mockedResults, children } = props;
89
- const query = () => Promise.resolve(mockedResults || {});
90
- const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]);
91
- return /* @__PURE__ */ React.createElement(ApiProvider, {
92
- apis: apiRegistry,
93
- children
94
- });
95
- }
96
- const SearchContextProviderForStorybook = (props) => {
97
- return /* @__PURE__ */ React.createElement(SearchApiProviderForStorybook, {
98
- ...props
99
- }, /* @__PURE__ */ React.createElement(SearchContextProvider, {
100
- children: props.children
101
- }));
102
- };
103
-
104
- export { SearchApiProviderForStorybook, SearchContextProvider, SearchContextProviderForStorybook, searchApiRef, useSearch, useSearchContextCheck };
110
+ export { HighlightedSearchResultText, MockSearchApi, SearchContextProvider, searchApiRef, useSearch, useSearchContextCheck };
105
111
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/api.ts","../src/context/SearchContext.tsx","../src/context/SearchContextForStorybook.stories.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * @public\n */\nexport const searchApiRef = createApiRef<SearchApi>({\n id: 'plugin.search.queryservice',\n});\n\n/**\n * @public\n */\nexport interface SearchApi {\n query(query: SearchQuery): Promise<SearchResultSet>;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n} from '@backstage/version-bridge';\nimport React, {\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport useAsync, { AsyncState } from 'react-use/lib/useAsync';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport { searchApiRef } from '../api';\n\n/**\n *\n * @public\n */\nexport type SearchContextValue = {\n result: AsyncState<SearchResultSet>;\n setTerm: React.Dispatch<React.SetStateAction<string>>;\n setTypes: React.Dispatch<React.SetStateAction<string[]>>;\n setFilters: React.Dispatch<React.SetStateAction<JsonObject>>;\n setPageCursor: React.Dispatch<React.SetStateAction<string | undefined>>;\n fetchNextPage?: React.DispatchWithoutAction;\n fetchPreviousPage?: React.DispatchWithoutAction;\n} & SearchContextState;\n\n/**\n *\n * @public\n */\nexport type SearchContextState = {\n term: string;\n types: string[];\n filters: JsonObject;\n pageCursor?: string;\n};\n\nconst SearchContext = createVersionedContext<{\n 1: SearchContextValue;\n}>('search-context');\n\n/**\n * @public\n *\n * React hook which provides the search context\n */\nexport const useSearch = () => {\n const context = useContext(SearchContext);\n if (!context) {\n throw new Error('useSearch must be used within a SearchContextProvider');\n }\n\n const value = context.atVersion(1);\n if (!value) {\n throw new Error('No SearchContext v1 found');\n }\n return value;\n};\n\n/**\n * @public\n *\n * React hook which checks for an existing search context\n */\nexport const useSearchContextCheck = () => {\n const context = useContext(SearchContext);\n return context !== undefined;\n};\n\n/**\n * The initial state of `SearchContextProvider`.\n *\n */\nconst searchInitialState: SearchContextState = {\n term: '',\n pageCursor: undefined,\n filters: {},\n types: [],\n};\n\n/**\n * Props for {@link SearchContextProvider}\n *\n * @public\n */\nexport type SearchContextProviderProps = PropsWithChildren<{\n initialState?: SearchContextState;\n}>;\n\n/**\n * @public\n *\n * Search context provider which gives you access to shared state between search components\n */\nexport const SearchContextProvider = (props: SearchContextProviderProps) => {\n const { initialState = searchInitialState, children } = props;\n const searchApi = useApi(searchApiRef);\n const [pageCursor, setPageCursor] = useState<string | undefined>(\n initialState.pageCursor,\n );\n const [filters, setFilters] = useState<JsonObject>(initialState.filters);\n const [term, setTerm] = useState<string>(initialState.term);\n const [types, setTypes] = useState<string[]>(initialState.types);\n\n const prevTerm = usePrevious(term);\n\n const result = useAsync(\n () =>\n searchApi.query({\n term,\n filters,\n pageCursor,\n types,\n }),\n [term, filters, types, pageCursor],\n );\n\n const hasNextPage =\n !result.loading && !result.error && result.value?.nextPageCursor;\n const hasPreviousPage =\n !result.loading && !result.error && result.value?.previousPageCursor;\n const fetchNextPage = useCallback(() => {\n setPageCursor(result.value?.nextPageCursor);\n }, [result.value?.nextPageCursor]);\n const fetchPreviousPage = useCallback(() => {\n setPageCursor(result.value?.previousPageCursor);\n }, [result.value?.previousPageCursor]);\n\n useEffect(() => {\n // Any time a term is reset, we want to start from page 0.\n if (term && prevTerm && term !== prevTerm) {\n setPageCursor(undefined);\n }\n }, [term, prevTerm, initialState.pageCursor]);\n\n const value: SearchContextValue = {\n result,\n filters,\n setFilters,\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n fetchNextPage: hasNextPage ? fetchNextPage : undefined,\n fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,\n };\n\n const versionedValue = createVersionedValueMap({ 1: value });\n\n return (\n <AnalyticsContext attributes={{ searchTypes: types.sort().join(',') }}>\n <SearchContext.Provider value={versionedValue} children={children} />\n </AnalyticsContext>\n );\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ApiProvider } from '@backstage/core-app-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport { TestApiRegistry } from '@backstage/test-utils';\nimport React, { ComponentProps, PropsWithChildren } from 'react';\nimport { searchApiRef } from '../api';\nimport { SearchContextProvider } from './SearchContext';\n\n/**\n * Props for {@link SearchApiProviderForStorybook}\n * @public\n */\nexport type SearchApiProviderForStorybookProps = ComponentProps<\n typeof SearchContextProvider\n> & {\n mockedResults?: SearchResultSet;\n};\n\n/**\n * Props for {@link SearchContextProviderForStorybook}\n * @public\n */\nexport type SearchContextProviderForStorybookProps = PropsWithChildren<{\n mockedResults?: SearchResultSet;\n}>;\n\n/**\n * Utility api provider only for use in Storybook stories.\n *\n * @public\n */\nexport function SearchApiProviderForStorybook(\n props: SearchApiProviderForStorybookProps,\n) {\n const { mockedResults, children } = props;\n const query: any = () => Promise.resolve(mockedResults || {});\n const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]);\n return <ApiProvider apis={apiRegistry} children={children} />;\n}\n\n/**\n * Utility context provider only for use in Storybook stories. You should use\n * the real `<SearchContextProvider>` exported by `@backstage/plugin-search-react` in\n * your app instead of this! In some cases (like the search page) it may\n * already be provided on your behalf.\n *\n * @public\n */\nexport const SearchContextProviderForStorybook = (\n props: SearchContextProviderForStorybookProps,\n) => {\n return (\n <SearchApiProviderForStorybook {...props}>\n <SearchContextProvider children={props.children} />\n </SearchApiProviderForStorybook>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/api.ts","../src/components/HighlightedSearchResultText/HighlightedSearchResultText.tsx","../src/context/SearchContext.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * @public\n */\nexport const searchApiRef = createApiRef<SearchApi>({\n id: 'plugin.search.queryservice',\n});\n\n/**\n * @public\n */\nexport interface SearchApi {\n query(query: SearchQuery): Promise<SearchResultSet>;\n}\n\n/**\n * @public\n *\n * Search Api Mock that can be used in tests and storybooks\n */\nexport class MockSearchApi implements SearchApi {\n constructor(public mockedResults?: SearchResultSet) {}\n\n query(): Promise<SearchResultSet> {\n return Promise.resolve(this.mockedResults || { results: [] });\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { makeStyles } from '@material-ui/core';\n\nconst useStyles = makeStyles(\n () => ({\n highlight: {},\n }),\n { name: 'BackstageHighlightedSearchResultText' },\n);\n\n/**\n * @public\n */\nexport type HighlightedSearchResultTextProps = {\n text: string;\n preTag: string;\n postTag: string;\n};\n\n/**\n * @public\n */\nexport const HighlightedSearchResultText = ({\n text,\n preTag,\n postTag,\n}: HighlightedSearchResultTextProps) => {\n const classes = useStyles();\n const terms = useMemo(\n () => text.split(new RegExp(`(${preTag}.+?${postTag})`)),\n [postTag, preTag, text],\n );\n return (\n <>\n {terms.map((t, idx) =>\n t.includes(preTag) ? (\n <mark className={classes.highlight} key={idx}>\n {t.replace(new RegExp(`${preTag}|${postTag}`, 'g'), '')}\n </mark>\n ) : (\n t\n ),\n )}\n </>\n );\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n} from '@backstage/version-bridge';\nimport React, {\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport useAsync, { AsyncState } from 'react-use/lib/useAsync';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport { searchApiRef } from '../api';\n\n/**\n *\n * @public\n */\nexport type SearchContextValue = {\n result: AsyncState<SearchResultSet>;\n setTerm: React.Dispatch<React.SetStateAction<string>>;\n setTypes: React.Dispatch<React.SetStateAction<string[]>>;\n setFilters: React.Dispatch<React.SetStateAction<JsonObject>>;\n setPageCursor: React.Dispatch<React.SetStateAction<string | undefined>>;\n fetchNextPage?: React.DispatchWithoutAction;\n fetchPreviousPage?: React.DispatchWithoutAction;\n} & SearchContextState;\n\n/**\n *\n * @public\n */\nexport type SearchContextState = {\n term: string;\n types: string[];\n filters: JsonObject;\n pageCursor?: string;\n};\n\nconst SearchContext = createVersionedContext<{\n 1: SearchContextValue;\n}>('search-context');\n\n/**\n * @public\n *\n * React hook which provides the search context\n */\nexport const useSearch = () => {\n const context = useContext(SearchContext);\n if (!context) {\n throw new Error('useSearch must be used within a SearchContextProvider');\n }\n\n const value = context.atVersion(1);\n if (!value) {\n throw new Error('No SearchContext v1 found');\n }\n return value;\n};\n\n/**\n * @public\n *\n * React hook which checks for an existing search context\n */\nexport const useSearchContextCheck = () => {\n const context = useContext(SearchContext);\n return context !== undefined;\n};\n\n/**\n * The initial state of `SearchContextProvider`.\n *\n */\nconst searchInitialState: SearchContextState = {\n term: '',\n pageCursor: undefined,\n filters: {},\n types: [],\n};\n\n/**\n * Props for {@link SearchContextProvider}\n *\n * @public\n */\nexport type SearchContextProviderProps = PropsWithChildren<{\n initialState?: SearchContextState;\n}>;\n\n/**\n * @public\n *\n * Search context provider which gives you access to shared state between search components\n */\nexport const SearchContextProvider = (props: SearchContextProviderProps) => {\n const { initialState = searchInitialState, children } = props;\n const searchApi = useApi(searchApiRef);\n const [pageCursor, setPageCursor] = useState<string | undefined>(\n initialState.pageCursor,\n );\n const [filters, setFilters] = useState<JsonObject>(initialState.filters);\n const [term, setTerm] = useState<string>(initialState.term);\n const [types, setTypes] = useState<string[]>(initialState.types);\n\n const prevTerm = usePrevious(term);\n\n const result = useAsync(\n () =>\n searchApi.query({\n term,\n filters,\n pageCursor,\n types,\n }),\n [term, filters, types, pageCursor],\n );\n\n const hasNextPage =\n !result.loading && !result.error && result.value?.nextPageCursor;\n const hasPreviousPage =\n !result.loading && !result.error && result.value?.previousPageCursor;\n const fetchNextPage = useCallback(() => {\n setPageCursor(result.value?.nextPageCursor);\n }, [result.value?.nextPageCursor]);\n const fetchPreviousPage = useCallback(() => {\n setPageCursor(result.value?.previousPageCursor);\n }, [result.value?.previousPageCursor]);\n\n useEffect(() => {\n // Any time a term is reset, we want to start from page 0.\n if (term && prevTerm && term !== prevTerm) {\n setPageCursor(undefined);\n }\n }, [term, prevTerm, initialState.pageCursor]);\n\n const value: SearchContextValue = {\n result,\n filters,\n setFilters,\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n fetchNextPage: hasNextPage ? fetchNextPage : undefined,\n fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,\n };\n\n const versionedValue = createVersionedValueMap({ 1: value });\n\n return (\n <AnalyticsContext attributes={{ searchTypes: types.sort().join(',') }}>\n <SearchContext.Provider value={versionedValue} children={children} />\n </AnalyticsContext>\n );\n};\n"],"names":[],"mappings":";;;;;;;AACY,MAAC,YAAY,GAAG,YAAY,CAAC;AACzC,EAAE,EAAE,EAAE,4BAA4B;AAClC,CAAC,EAAE;AACI,MAAM,aAAa,CAAC;AAC3B,EAAE,WAAW,CAAC,aAAa,EAAE;AAC7B,IAAI,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;AACvC,GAAG;AACH,EAAE,KAAK,GAAG;AACV,IAAI,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAClE,GAAG;AACH;;ACTA,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO;AACpC,EAAE,SAAS,EAAE,EAAE;AACf,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,sCAAsC,EAAE,CAAC,CAAC;AAC1C,MAAC,2BAA2B,GAAG,CAAC;AAC5C,EAAE,IAAI;AACN,EAAE,MAAM;AACR,EAAE,OAAO;AACT,CAAC,KAAK;AACN,EAAE,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;AAC9B,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAC3G,EAAE,uBAAuB,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE;AAC1J,IAAI,SAAS,EAAE,OAAO,CAAC,SAAS;AAChC,IAAI,GAAG,EAAE,GAAG;AACZ,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnE;;ACFA,MAAM,aAAa,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;AACnD,MAAC,SAAS,GAAG,MAAM;AAC/B,EAAE,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;AAC5C,EAAE,IAAI,CAAC,OAAO,EAAE;AAChB,IAAI,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;AAC7E,GAAG;AACH,EAAE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrC,EAAE,IAAI,CAAC,KAAK,EAAE;AACd,IAAI,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACjD,GAAG;AACH,EAAE,OAAO,KAAK,CAAC;AACf,EAAE;AACU,MAAC,qBAAqB,GAAG,MAAM;AAC3C,EAAE,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;AAC5C,EAAE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC;AAC5B,EAAE;AACF,MAAM,kBAAkB,GAAG;AAC3B,EAAE,IAAI,EAAE,EAAE;AACV,EAAE,UAAU,EAAE,KAAK,CAAC;AACpB,EAAE,OAAO,EAAE,EAAE;AACb,EAAE,KAAK,EAAE,EAAE;AACX,CAAC,CAAC;AACU,MAAC,qBAAqB,GAAG,CAAC,KAAK,KAAK;AAChD,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACrB,EAAE,MAAM,EAAE,YAAY,GAAG,kBAAkB,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;AAChE,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AACzC,EAAE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;AACxE,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/D,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AACtD,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AACzD,EAAE,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AACrC,EAAE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC;AAChD,IAAI,IAAI;AACR,IAAI,OAAO;AACX,IAAI,UAAU;AACd,IAAI,KAAK;AACT,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;AAC1C,EAAE,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;AACrH,EAAE,MAAM,eAAe,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC;AAC7H,EAAE,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM;AAC1C,IAAI,IAAI,GAAG,CAAC;AACZ,IAAI,aAAa,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;AAC9E,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACjE,EAAE,MAAM,iBAAiB,GAAG,WAAW,CAAC,MAAM;AAC9C,IAAI,IAAI,GAAG,CAAC;AACZ,IAAI,aAAa,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAClF,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACrE,EAAE,SAAS,CAAC,MAAM;AAClB,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,KAAK,QAAQ,EAAE;AAC/C,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,KAAK;AACL,GAAG,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;AAChD,EAAE,MAAM,KAAK,GAAG;AAChB,IAAI,MAAM;AACV,IAAI,OAAO;AACX,IAAI,UAAU;AACd,IAAI,IAAI;AACR,IAAI,OAAO;AACX,IAAI,KAAK;AACT,IAAI,QAAQ;AACZ,IAAI,UAAU;AACd,IAAI,aAAa;AACjB,IAAI,aAAa,EAAE,WAAW,GAAG,aAAa,GAAG,KAAK,CAAC;AACvD,IAAI,iBAAiB,EAAE,eAAe,GAAG,iBAAiB,GAAG,KAAK,CAAC;AACnE,GAAG,CAAC;AACJ,EAAE,MAAM,cAAc,GAAG,uBAAuB,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/D,EAAE,uBAAuB,KAAK,CAAC,aAAa,CAAC,gBAAgB,EAAE;AAC/D,IAAI,UAAU,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACvD,GAAG,kBAAkB,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,EAAE;AACjE,IAAI,KAAK,EAAE,cAAc;AACzB,IAAI,QAAQ;AACZ,GAAG,CAAC,CAAC,CAAC;AACN;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-search-react",
3
- "version": "0.1.1-next.0",
3
+ "version": "0.2.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -31,10 +31,11 @@
31
31
  "start": "backstage-cli package start"
32
32
  },
33
33
  "dependencies": {
34
- "@backstage/core-plugin-api": "^1.0.1",
35
- "@backstage/plugin-search-common": "^0.3.3",
34
+ "@backstage/core-plugin-api": "^1.0.2",
35
+ "@backstage/plugin-search-common": "^0.3.4",
36
36
  "@backstage/types": "^1.0.0",
37
37
  "@backstage/version-bridge": "^1.0.1",
38
+ "@material-ui/core": "^4.12.2",
38
39
  "react-use": "^17.3.2"
39
40
  },
40
41
  "peerDependencies": {
@@ -42,8 +43,8 @@
42
43
  "react": "^16.13.1 || ^17.0.0"
43
44
  },
44
45
  "devDependencies": {
45
- "@backstage/core-app-api": "^1.0.1",
46
- "@backstage/test-utils": "^1.0.2-next.0",
46
+ "@backstage/core-app-api": "^1.0.2",
47
+ "@backstage/test-utils": "^1.1.0",
47
48
  "@testing-library/jest-dom": "^5.10.1",
48
49
  "@testing-library/react": "^12.1.3",
49
50
  "@testing-library/react-hooks": "^8.0.0"
@@ -51,5 +52,5 @@
51
52
  "files": [
52
53
  "dist"
53
54
  ],
54
- "gitHead": "88ee375f5ee44b7a7917297785ddf88691fe3381"
55
+ "gitHead": "96323f280ba32ee526c5b151cda42260aee927c9"
55
56
  }