@backstage/plugin-search-react 0.2.1-next.0 → 0.2.2-next.1

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,31 @@
1
1
  # @backstage/plugin-search-react
2
2
 
3
+ ## 0.2.2-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/core-components@0.9.6-next.1
9
+ - @backstage/theme@0.2.16-next.0
10
+ - @backstage/plugin-search-common@0.3.6-next.0
11
+
12
+ ## 0.2.2-next.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies
17
+ - @backstage/core-components@0.9.6-next.0
18
+
19
+ ## 0.2.1
20
+
21
+ ### Patch Changes
22
+
23
+ - 8809159148: Components `<DefaultResultListItem>`, `<SearchBar>` (including `<SearchBarBase>`), `<SearchFilter>` (including `.Checkbox`, `.Select`, and `.Autocomplete` static prop components), `<SearchResult>`, and `<SearchResultPager>` are now exported from `@backstage/plugin-search-react`. They are now deprecated in `@backstage/plugin-search` and will be removed in a future release.
24
+ - Updated dependencies
25
+ - @backstage/plugin-search-common@0.3.5
26
+ - @backstage/core-components@0.9.5
27
+ - @backstage/core-plugin-api@1.0.3
28
+
3
29
  ## 0.2.1-next.0
4
30
 
5
31
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  /// <reference types="react" />
2
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
- import { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';
3
+ import { SearchQuery, SearchResultSet, SearchResult, SearchDocument, ResultHighlight } from '@backstage/plugin-search-common';
4
+ import React, { ReactElement, ReactNode, PropsWithChildren } from 'react';
5
+ import { InputBaseProps } from '@material-ui/core';
4
6
  import { JsonObject } from '@backstage/types';
5
- import React, { PropsWithChildren } from 'react';
6
7
  import { AsyncState } from 'react-use/lib/useAsync';
7
8
 
8
9
  /**
@@ -27,6 +28,8 @@ declare class MockSearchApi implements SearchApi {
27
28
  }
28
29
 
29
30
  /**
31
+ * Props for {@link HighlightedSearchResultText}.
32
+ *
30
33
  * @public
31
34
  */
32
35
  declare type HighlightedSearchResultTextProps = {
@@ -39,6 +42,149 @@ declare type HighlightedSearchResultTextProps = {
39
42
  */
40
43
  declare const HighlightedSearchResultText: ({ text, preTag, postTag, }: HighlightedSearchResultTextProps) => JSX.Element;
41
44
 
45
+ /**
46
+ * @public
47
+ */
48
+ declare type SearchAutocompleteFilterProps = SearchFilterComponentProps & {
49
+ filterSelectedOptions?: boolean;
50
+ limitTags?: number;
51
+ multiple?: boolean;
52
+ };
53
+ /**
54
+ * @public
55
+ */
56
+ declare const AutocompleteFilter: (props: SearchAutocompleteFilterProps) => JSX.Element;
57
+
58
+ /**
59
+ * @public
60
+ */
61
+ declare type SearchFilterComponentProps = {
62
+ className?: string;
63
+ name: string;
64
+ label?: string;
65
+ /**
66
+ * Either an array of values directly, or an async function to return a list
67
+ * of values to be used in the filter. In the autocomplete filter, the last
68
+ * input value is provided as an input to allow values to be filtered. This
69
+ * function is debounced and values cached.
70
+ */
71
+ values?: string[] | ((partial: string) => Promise<string[]>);
72
+ defaultValue?: string[] | string | null;
73
+ /**
74
+ * Debounce time in milliseconds, used when values is an async callback.
75
+ * Defaults to 250ms.
76
+ */
77
+ valuesDebounceMs?: number;
78
+ };
79
+ /**
80
+ * @public
81
+ */
82
+ declare type SearchFilterWrapperProps = SearchFilterComponentProps & {
83
+ component: (props: SearchFilterComponentProps) => ReactElement;
84
+ debug?: boolean;
85
+ };
86
+ /**
87
+ * @public
88
+ */
89
+ declare const CheckboxFilter: (props: SearchFilterComponentProps) => JSX.Element;
90
+ /**
91
+ * @public
92
+ */
93
+ declare const SelectFilter: (props: SearchFilterComponentProps) => JSX.Element;
94
+ /**
95
+ * @public
96
+ */
97
+ declare const SearchFilter: {
98
+ ({ component: Element, ...props }: SearchFilterWrapperProps): JSX.Element;
99
+ Checkbox(props: Omit<SearchFilterWrapperProps, 'component'> & SearchFilterComponentProps): JSX.Element;
100
+ Select(props: Omit<SearchFilterWrapperProps, 'component'> & SearchFilterComponentProps): JSX.Element;
101
+ /**
102
+ * A control surface for a given filter field name, rendered as an autocomplete
103
+ * textfield. A hard-coded list of values may be provided, or an async function
104
+ * which returns values may be provided instead.
105
+ *
106
+ * @public
107
+ */
108
+ Autocomplete(props: SearchAutocompleteFilterProps): JSX.Element;
109
+ };
110
+
111
+ /**
112
+ * Props for {@link SearchResultComponent}
113
+ *
114
+ * @public
115
+ */
116
+ declare type SearchResultProps = {
117
+ children: (results: {
118
+ results: SearchResult[];
119
+ }) => JSX.Element;
120
+ };
121
+ /**
122
+ * A component returning the search result.
123
+ *
124
+ * @public
125
+ */
126
+ declare const SearchResultComponent: ({ children }: SearchResultProps) => JSX.Element;
127
+ /**
128
+ * @public
129
+ */
130
+ declare const HigherOrderSearchResult: (props: SearchResultProps) => JSX.Element;
131
+
132
+ /**
133
+ * @public
134
+ */
135
+ declare const SearchResultPager: () => JSX.Element;
136
+
137
+ /**
138
+ * Props for {@link SearchBarBase}.
139
+ *
140
+ * @public
141
+ */
142
+ declare type SearchBarBaseProps = Omit<InputBaseProps, 'onChange'> & {
143
+ debounceTime?: number;
144
+ clearButton?: boolean;
145
+ onClear?: () => void;
146
+ onSubmit?: () => void;
147
+ onChange: (value: string) => void;
148
+ };
149
+ /**
150
+ * All search boxes exported by the search plugin are based on the <SearchBarBase />,
151
+ * and this one is based on the <InputBase /> component from Material UI.
152
+ * Recommended if you don't use Search Provider or Search Context.
153
+ *
154
+ * @public
155
+ */
156
+ declare const SearchBarBase: ({ onChange, onKeyDown, onSubmit, debounceTime, clearButton, fullWidth, value: defaultValue, inputProps: defaultInputProps, endAdornment: defaultEndAdornment, ...props }: SearchBarBaseProps) => JSX.Element;
157
+ /**
158
+ * Props for {@link SearchBar}.
159
+ *
160
+ * @public
161
+ */
162
+ declare type SearchBarProps = Partial<SearchBarBaseProps>;
163
+ /**
164
+ * Recommended search bar when you use the Search Provider or Search Context.
165
+ *
166
+ * @public
167
+ */
168
+ declare const SearchBar: ({ onChange, ...props }: SearchBarProps) => JSX.Element;
169
+
170
+ /**
171
+ * Props for {@link DefaultResultListItem}
172
+ *
173
+ * @public
174
+ */
175
+ declare type DefaultResultListItemProps = {
176
+ icon?: ReactNode;
177
+ secondaryAction?: ReactNode;
178
+ result: SearchDocument;
179
+ highlight?: ResultHighlight;
180
+ rank?: number;
181
+ lineClamp?: number;
182
+ };
183
+ /**
184
+ * @public
185
+ */
186
+ declare const HigherOrderDefaultResultListItem: (props: DefaultResultListItemProps) => JSX.Element;
187
+
42
188
  /**
43
189
  *
44
190
  * @public
@@ -89,4 +235,4 @@ declare type SearchContextProviderProps = PropsWithChildren<{
89
235
  */
90
236
  declare const SearchContextProvider: (props: SearchContextProviderProps) => JSX.Element;
91
237
 
92
- export { HighlightedSearchResultText, HighlightedSearchResultTextProps, MockSearchApi, SearchApi, SearchContextProvider, SearchContextProviderProps, SearchContextState, SearchContextValue, searchApiRef, useSearch, useSearchContextCheck };
238
+ export { AutocompleteFilter, CheckboxFilter, HigherOrderDefaultResultListItem as DefaultResultListItem, DefaultResultListItemProps, HighlightedSearchResultText, HighlightedSearchResultTextProps, MockSearchApi, SearchApi, SearchAutocompleteFilterProps, SearchBar, SearchBarBase, SearchBarBaseProps, SearchBarProps, SearchContextProvider, SearchContextProviderProps, SearchContextState, SearchContextValue, SearchFilter, SearchFilterComponentProps, SearchFilterWrapperProps, HigherOrderSearchResult as SearchResult, SearchResultComponent, SearchResultPager, SearchResultProps, SelectFilter, searchApiRef, useSearch, useSearchContextCheck };
package/dist/index.esm.js CHANGED
@@ -1,9 +1,17 @@
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';
1
+ import { createApiRef, useApi, AnalyticsContext, useAnalytics, configApiRef } from '@backstage/core-plugin-api';
2
+ import React, { useMemo, useContext, useState, useCallback, useEffect, useRef } from 'react';
3
+ import { makeStyles, TextField, Chip, FormControl, FormLabel, FormControlLabel, Checkbox, InputLabel, Select, MenuItem, Button, InputBase, InputAdornment, IconButton, ListItem, ListItemIcon, ListItemText, Box, Divider } from '@material-ui/core';
4
4
  import { createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
5
5
  import useAsync from 'react-use/lib/useAsync';
6
6
  import usePrevious from 'react-use/lib/usePrevious';
7
+ import { Autocomplete } from '@material-ui/lab';
8
+ import useAsyncFn from 'react-use/lib/useAsyncFn';
9
+ import useDebounce from 'react-use/lib/useDebounce';
10
+ import { Progress, ResponseErrorPanel, EmptyState, Link } from '@backstage/core-components';
11
+ import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';
12
+ import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
13
+ import SearchIcon from '@material-ui/icons/Search';
14
+ import ClearButton from '@material-ui/icons/Clear';
7
15
 
8
16
  const searchApiRef = createApiRef({
9
17
  id: "plugin.search.queryservice"
@@ -17,7 +25,7 @@ class MockSearchApi {
17
25
  }
18
26
  }
19
27
 
20
- const useStyles = makeStyles(() => ({
28
+ const useStyles$2 = makeStyles(() => ({
21
29
  highlight: {}
22
30
  }), { name: "BackstageHighlightedSearchResultText" });
23
31
  const HighlightedSearchResultText = ({
@@ -25,7 +33,7 @@ const HighlightedSearchResultText = ({
25
33
  preTag,
26
34
  postTag
27
35
  }) => {
28
- const classes = useStyles();
36
+ const classes = useStyles$2();
29
37
  const terms = useMemo(() => text.split(new RegExp(`(${preTag}.+?${postTag})`)), [postTag, preTag, text]);
30
38
  return /* @__PURE__ */ React.createElement(React.Fragment, null, terms.map((t, idx) => t.includes(preTag) ? /* @__PURE__ */ React.createElement("mark", {
31
39
  className: classes.highlight,
@@ -107,5 +115,425 @@ const SearchContextProvider = (props) => {
107
115
  }));
108
116
  };
109
117
 
110
- export { HighlightedSearchResultText, MockSearchApi, SearchContextProvider, searchApiRef, useSearch, useSearchContextCheck };
118
+ const useAsyncFilterValues = (fn, inputValue, defaultValues = [], debounce = 250) => {
119
+ const valuesMemo = useRef({});
120
+ const definiteFn = fn || (() => Promise.resolve([]));
121
+ const [state, callback] = useAsyncFn(definiteFn, [inputValue], {
122
+ loading: true
123
+ });
124
+ useDebounce(() => {
125
+ if (valuesMemo.current[inputValue] === void 0) {
126
+ valuesMemo.current[inputValue] = callback(inputValue).then((values) => {
127
+ valuesMemo.current[inputValue] = values;
128
+ return values;
129
+ });
130
+ }
131
+ }, debounce, [callback, inputValue]);
132
+ if (defaultValues.length) {
133
+ return {
134
+ loading: false,
135
+ value: defaultValues
136
+ };
137
+ }
138
+ const possibleValue = valuesMemo.current[inputValue];
139
+ if (Array.isArray(possibleValue)) {
140
+ return {
141
+ loading: false,
142
+ value: possibleValue
143
+ };
144
+ }
145
+ return state;
146
+ };
147
+ const useDefaultFilterValue = (name, defaultValue) => {
148
+ const { setFilters } = useSearch();
149
+ useEffect(() => {
150
+ if (defaultValue && [defaultValue].flat().length > 0) {
151
+ setFilters((prevFilters) => ({
152
+ ...prevFilters,
153
+ [name]: defaultValue
154
+ }));
155
+ }
156
+ }, []);
157
+ };
158
+
159
+ const AutocompleteFilter = (props) => {
160
+ const {
161
+ className,
162
+ defaultValue,
163
+ name,
164
+ values: givenValues,
165
+ valuesDebounceMs,
166
+ label,
167
+ filterSelectedOptions,
168
+ limitTags,
169
+ multiple
170
+ } = props;
171
+ const [inputValue, setInputValue] = useState("");
172
+ useDefaultFilterValue(name, defaultValue);
173
+ const asyncValues = typeof givenValues === "function" ? givenValues : void 0;
174
+ const defaultValues = typeof givenValues === "function" ? void 0 : givenValues;
175
+ const { value: values, loading } = useAsyncFilterValues(asyncValues, inputValue, defaultValues, valuesDebounceMs);
176
+ const { filters, setFilters } = useSearch();
177
+ const filterValue = filters[name] || (multiple ? [] : null);
178
+ const handleChange = (_, newValue) => {
179
+ setFilters((prevState) => {
180
+ const { [name]: filter, ...others } = prevState;
181
+ if (newValue) {
182
+ return { ...others, [name]: newValue };
183
+ }
184
+ return { ...others };
185
+ });
186
+ };
187
+ const renderInput = (params) => /* @__PURE__ */ React.createElement(TextField, {
188
+ ...params,
189
+ name: "search",
190
+ variant: "outlined",
191
+ label,
192
+ fullWidth: true
193
+ });
194
+ const renderTags = (tagValue, getTagProps) => tagValue.map((option, index) => /* @__PURE__ */ React.createElement(Chip, {
195
+ label: option,
196
+ color: "primary",
197
+ ...getTagProps({ index })
198
+ }));
199
+ return /* @__PURE__ */ React.createElement(Autocomplete, {
200
+ filterSelectedOptions,
201
+ limitTags,
202
+ multiple,
203
+ className,
204
+ id: `${multiple ? "multi-" : ""}select-filter-${name}--select`,
205
+ options: values || [],
206
+ loading,
207
+ value: filterValue,
208
+ onChange: handleChange,
209
+ onInputChange: (_, newValue) => setInputValue(newValue),
210
+ renderInput,
211
+ renderTags
212
+ });
213
+ };
214
+
215
+ const useStyles$1 = makeStyles({
216
+ label: {
217
+ textTransform: "capitalize"
218
+ }
219
+ });
220
+ const CheckboxFilter = (props) => {
221
+ const {
222
+ className,
223
+ defaultValue,
224
+ label,
225
+ name,
226
+ values: givenValues = [],
227
+ valuesDebounceMs
228
+ } = props;
229
+ const classes = useStyles$1();
230
+ const { filters, setFilters } = useSearch();
231
+ useDefaultFilterValue(name, defaultValue);
232
+ const asyncValues = typeof givenValues === "function" ? givenValues : void 0;
233
+ const defaultValues = typeof givenValues === "function" ? void 0 : givenValues;
234
+ const { value: values = [], loading } = useAsyncFilterValues(asyncValues, "", defaultValues, valuesDebounceMs);
235
+ const handleChange = (e) => {
236
+ const {
237
+ target: { value, checked }
238
+ } = e;
239
+ setFilters((prevFilters) => {
240
+ const { [name]: filter, ...others } = prevFilters;
241
+ const rest = (filter || []).filter((i) => i !== value);
242
+ const items = checked ? [...rest, value] : rest;
243
+ return items.length ? { ...others, [name]: items } : others;
244
+ });
245
+ };
246
+ return /* @__PURE__ */ React.createElement(FormControl, {
247
+ className,
248
+ disabled: loading,
249
+ fullWidth: true,
250
+ "data-testid": "search-checkboxfilter-next"
251
+ }, label ? /* @__PURE__ */ React.createElement(FormLabel, {
252
+ className: classes.label
253
+ }, label) : null, values.map((value) => {
254
+ var _a;
255
+ return /* @__PURE__ */ React.createElement(FormControlLabel, {
256
+ key: value,
257
+ control: /* @__PURE__ */ React.createElement(Checkbox, {
258
+ color: "primary",
259
+ tabIndex: -1,
260
+ inputProps: { "aria-labelledby": value },
261
+ value,
262
+ name: value,
263
+ onChange: handleChange,
264
+ checked: ((_a = filters[name]) != null ? _a : []).includes(value)
265
+ }),
266
+ label: value
267
+ });
268
+ }));
269
+ };
270
+ const SelectFilter = (props) => {
271
+ const {
272
+ className,
273
+ defaultValue,
274
+ label,
275
+ name,
276
+ values: givenValues,
277
+ valuesDebounceMs
278
+ } = props;
279
+ const classes = useStyles$1();
280
+ useDefaultFilterValue(name, defaultValue);
281
+ const asyncValues = typeof givenValues === "function" ? givenValues : void 0;
282
+ const defaultValues = typeof givenValues === "function" ? void 0 : givenValues;
283
+ const { value: values = [], loading } = useAsyncFilterValues(asyncValues, "", defaultValues, valuesDebounceMs);
284
+ const { filters, setFilters } = useSearch();
285
+ const handleChange = (e) => {
286
+ const {
287
+ target: { value }
288
+ } = e;
289
+ setFilters((prevFilters) => {
290
+ const { [name]: filter, ...others } = prevFilters;
291
+ return value ? { ...others, [name]: value } : others;
292
+ });
293
+ };
294
+ return /* @__PURE__ */ React.createElement(FormControl, {
295
+ disabled: loading,
296
+ className,
297
+ variant: "filled",
298
+ fullWidth: true,
299
+ "data-testid": "search-selectfilter-next"
300
+ }, label ? /* @__PURE__ */ React.createElement(InputLabel, {
301
+ className: classes.label,
302
+ margin: "dense"
303
+ }, label) : null, /* @__PURE__ */ React.createElement(Select, {
304
+ variant: "outlined",
305
+ value: filters[name] || "",
306
+ onChange: handleChange
307
+ }, /* @__PURE__ */ React.createElement(MenuItem, {
308
+ value: ""
309
+ }, /* @__PURE__ */ React.createElement("em", null, "All")), values.map((value) => /* @__PURE__ */ React.createElement(MenuItem, {
310
+ key: value,
311
+ value
312
+ }, value))));
313
+ };
314
+ const SearchFilter = ({
315
+ component: Element,
316
+ ...props
317
+ }) => /* @__PURE__ */ React.createElement(Element, {
318
+ ...props
319
+ });
320
+ SearchFilter.Checkbox = (props) => /* @__PURE__ */ React.createElement(SearchFilter, {
321
+ ...props,
322
+ component: CheckboxFilter
323
+ });
324
+ SearchFilter.Select = (props) => /* @__PURE__ */ React.createElement(SearchFilter, {
325
+ ...props,
326
+ component: SelectFilter
327
+ });
328
+ SearchFilter.Autocomplete = (props) => /* @__PURE__ */ React.createElement(SearchFilter, {
329
+ ...props,
330
+ component: AutocompleteFilter
331
+ });
332
+
333
+ const SearchResultComponent = ({ children }) => {
334
+ const {
335
+ result: { loading, error, value }
336
+ } = useSearch();
337
+ if (loading) {
338
+ return /* @__PURE__ */ React.createElement(Progress, null);
339
+ }
340
+ if (error) {
341
+ return /* @__PURE__ */ React.createElement(ResponseErrorPanel, {
342
+ title: "Error encountered while fetching search results",
343
+ error
344
+ });
345
+ }
346
+ if (!(value == null ? void 0 : value.results.length)) {
347
+ return /* @__PURE__ */ React.createElement(EmptyState, {
348
+ missing: "data",
349
+ title: "Sorry, no results were found"
350
+ });
351
+ }
352
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children({ results: value.results }));
353
+ };
354
+ const HigherOrderSearchResult = (props) => {
355
+ return /* @__PURE__ */ React.createElement(AnalyticsContext, {
356
+ attributes: {
357
+ pluginId: "search",
358
+ extension: "SearchResult"
359
+ }
360
+ }, /* @__PURE__ */ React.createElement(SearchResultComponent, {
361
+ ...props
362
+ }));
363
+ };
364
+
365
+ const useStyles = makeStyles((theme) => ({
366
+ root: {
367
+ display: "flex",
368
+ justifyContent: "space-between",
369
+ gap: theme.spacing(2),
370
+ margin: theme.spacing(2, 0)
371
+ }
372
+ }));
373
+ const SearchResultPager = () => {
374
+ const { fetchNextPage, fetchPreviousPage } = useSearch();
375
+ const classes = useStyles();
376
+ if (!fetchNextPage && !fetchPreviousPage) {
377
+ return /* @__PURE__ */ React.createElement(React.Fragment, null);
378
+ }
379
+ return /* @__PURE__ */ React.createElement("nav", {
380
+ "arial-label": "pagination navigation",
381
+ className: classes.root
382
+ }, /* @__PURE__ */ React.createElement(Button, {
383
+ "aria-label": "previous page",
384
+ disabled: !fetchPreviousPage,
385
+ onClick: fetchPreviousPage,
386
+ startIcon: /* @__PURE__ */ React.createElement(ArrowBackIosIcon, null)
387
+ }, "Previous"), /* @__PURE__ */ React.createElement(Button, {
388
+ "aria-label": "next page",
389
+ disabled: !fetchNextPage,
390
+ onClick: fetchNextPage,
391
+ endIcon: /* @__PURE__ */ React.createElement(ArrowForwardIosIcon, null)
392
+ }, "Next"));
393
+ };
394
+
395
+ const TrackSearch = ({ children }) => {
396
+ const analytics = useAnalytics();
397
+ const { term } = useSearch();
398
+ useEffect(() => {
399
+ if (term) {
400
+ analytics.captureEvent("search", term);
401
+ }
402
+ }, [analytics, term]);
403
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
404
+ };
405
+
406
+ const SearchBarBase = ({
407
+ onChange,
408
+ onKeyDown,
409
+ onSubmit,
410
+ debounceTime = 200,
411
+ clearButton = true,
412
+ fullWidth = true,
413
+ value: defaultValue,
414
+ inputProps: defaultInputProps = {},
415
+ endAdornment: defaultEndAdornment,
416
+ ...props
417
+ }) => {
418
+ const configApi = useApi(configApiRef);
419
+ const [value, setValue] = useState(defaultValue);
420
+ const hasSearchContext = useSearchContextCheck();
421
+ useEffect(() => {
422
+ setValue((prevValue) => prevValue !== defaultValue ? defaultValue : prevValue);
423
+ }, [defaultValue]);
424
+ useDebounce(() => onChange(value), debounceTime, [value]);
425
+ const handleChange = useCallback((e) => {
426
+ setValue(e.target.value);
427
+ }, [setValue]);
428
+ const handleKeyDown = useCallback((e) => {
429
+ if (onKeyDown)
430
+ onKeyDown(e);
431
+ if (onSubmit && e.key === "Enter") {
432
+ onSubmit();
433
+ }
434
+ }, [onKeyDown, onSubmit]);
435
+ const handleClear = useCallback(() => {
436
+ onChange("");
437
+ }, [onChange]);
438
+ const placeholder = `Search in ${configApi.getOptionalString("app.title") || "Backstage"}`;
439
+ const startAdornment = /* @__PURE__ */ React.createElement(InputAdornment, {
440
+ position: "start"
441
+ }, /* @__PURE__ */ React.createElement(IconButton, {
442
+ "aria-label": "Query",
443
+ disabled: true
444
+ }, /* @__PURE__ */ React.createElement(SearchIcon, null)));
445
+ const endAdornment = /* @__PURE__ */ React.createElement(InputAdornment, {
446
+ position: "end"
447
+ }, /* @__PURE__ */ React.createElement(IconButton, {
448
+ "aria-label": "Clear",
449
+ onClick: handleClear
450
+ }, /* @__PURE__ */ React.createElement(ClearButton, null)));
451
+ const searchBar = /* @__PURE__ */ React.createElement(TrackSearch, null, /* @__PURE__ */ React.createElement(InputBase, {
452
+ "data-testid": "search-bar-next",
453
+ value,
454
+ placeholder,
455
+ startAdornment,
456
+ endAdornment: clearButton ? endAdornment : defaultEndAdornment,
457
+ inputProps: { "aria-label": "Search", ...defaultInputProps },
458
+ fullWidth,
459
+ onChange: handleChange,
460
+ onKeyDown: handleKeyDown,
461
+ ...props
462
+ }));
463
+ return hasSearchContext ? searchBar : /* @__PURE__ */ React.createElement(SearchContextProvider, null, searchBar);
464
+ };
465
+ const SearchBar = ({ onChange, ...props }) => {
466
+ const { term, setTerm } = useSearch();
467
+ const handleChange = useCallback((newValue) => {
468
+ if (onChange) {
469
+ onChange(newValue);
470
+ } else {
471
+ setTerm(newValue);
472
+ }
473
+ }, [onChange, setTerm]);
474
+ return /* @__PURE__ */ React.createElement(AnalyticsContext, {
475
+ attributes: { pluginId: "search", extension: "SearchBar" }
476
+ }, /* @__PURE__ */ React.createElement(SearchBarBase, {
477
+ value: term,
478
+ onChange: handleChange,
479
+ ...props
480
+ }));
481
+ };
482
+
483
+ const DefaultResultListItemComponent = ({
484
+ result,
485
+ highlight,
486
+ rank,
487
+ icon,
488
+ secondaryAction,
489
+ lineClamp = 5
490
+ }) => {
491
+ const analytics = useAnalytics();
492
+ const handleClick = () => {
493
+ analytics.captureEvent("discover", result.title, {
494
+ attributes: { to: result.location },
495
+ value: rank
496
+ });
497
+ };
498
+ return /* @__PURE__ */ React.createElement(Link, {
499
+ noTrack: true,
500
+ to: result.location,
501
+ onClick: handleClick
502
+ }, /* @__PURE__ */ React.createElement(ListItem, {
503
+ alignItems: "center"
504
+ }, icon && /* @__PURE__ */ React.createElement(ListItemIcon, null, icon), /* @__PURE__ */ React.createElement(ListItemText, {
505
+ primaryTypographyProps: { variant: "h6" },
506
+ primary: (highlight == null ? void 0 : highlight.fields.title) ? /* @__PURE__ */ React.createElement(HighlightedSearchResultText, {
507
+ text: highlight.fields.title,
508
+ preTag: highlight.preTag,
509
+ postTag: highlight.postTag
510
+ }) : result.title,
511
+ secondary: /* @__PURE__ */ React.createElement("span", {
512
+ style: {
513
+ display: "-webkit-box",
514
+ WebkitBoxOrient: "vertical",
515
+ WebkitLineClamp: lineClamp,
516
+ overflow: "hidden"
517
+ }
518
+ }, (highlight == null ? void 0 : highlight.fields.text) ? /* @__PURE__ */ React.createElement(HighlightedSearchResultText, {
519
+ text: highlight.fields.text,
520
+ preTag: highlight.preTag,
521
+ postTag: highlight.postTag
522
+ }) : result.text)
523
+ }), secondaryAction && /* @__PURE__ */ React.createElement(Box, {
524
+ alignItems: "flex-end"
525
+ }, secondaryAction)), /* @__PURE__ */ React.createElement(Divider, null));
526
+ };
527
+ const HigherOrderDefaultResultListItem = (props) => {
528
+ return /* @__PURE__ */ React.createElement(AnalyticsContext, {
529
+ attributes: {
530
+ pluginId: "search",
531
+ extension: "DefaultResultListItem"
532
+ }
533
+ }, /* @__PURE__ */ React.createElement(DefaultResultListItemComponent, {
534
+ ...props
535
+ }));
536
+ };
537
+
538
+ export { AutocompleteFilter, CheckboxFilter, HigherOrderDefaultResultListItem as DefaultResultListItem, HighlightedSearchResultText, MockSearchApi, SearchBar, SearchBarBase, SearchContextProvider, SearchFilter, HigherOrderSearchResult as SearchResult, SearchResultComponent, SearchResultPager, SelectFilter, searchApiRef, useSearch, useSearchContextCheck };
111
539
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
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":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/api.ts","../src/components/HighlightedSearchResultText/HighlightedSearchResultText.tsx","../src/context/SearchContext.tsx","../src/components/SearchFilter/hooks.ts","../src/components/SearchFilter/SearchFilter.Autocomplete.tsx","../src/components/SearchFilter/SearchFilter.tsx","../src/components/SearchResult/SearchResult.tsx","../src/components/SearchResultPager/SearchResultPager.tsx","../src/components/SearchTracker/SearchTracker.tsx","../src/components/SearchBar/SearchBar.tsx","../src/components/DefaultResultListItem/DefaultResultListItem.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 * Props for {@link HighlightedSearchResultText}.\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","/*\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 { useEffect, useRef } from 'react';\nimport useAsyncFn from 'react-use/lib/useAsyncFn';\nimport useDebounce from 'react-use/lib/useDebounce';\n\nimport { useSearch } from '../../context';\n\n/**\n * Utility hook for either asynchronously loading filter values from a given\n * function or synchronously providing a given list of default values.\n *\n * @public\n */\nexport const useAsyncFilterValues = (\n fn: ((partial: string) => Promise<string[]>) | undefined,\n inputValue: string,\n defaultValues: string[] = [],\n debounce: number = 250,\n) => {\n const valuesMemo = useRef<Record<string, string[] | Promise<string[]>>>({});\n const definiteFn = fn || (() => Promise.resolve([]));\n\n const [state, callback] = useAsyncFn(definiteFn, [inputValue], {\n loading: true,\n });\n\n // Do not invoke the given function more than necessary.\n useDebounce(\n () => {\n // Performance optimization: only invoke the callback once per inputValue\n // for the lifetime of the hook/component.\n if (valuesMemo.current[inputValue] === undefined) {\n valuesMemo.current[inputValue] = callback(inputValue).then(values => {\n // Override the value for future immediate returns.\n valuesMemo.current[inputValue] = values;\n return values;\n });\n }\n },\n debounce,\n [callback, inputValue],\n );\n\n // Immediately return the default values if they are provided.\n if (defaultValues.length) {\n return {\n loading: false,\n value: defaultValues,\n };\n }\n\n // Immediately return a memoized value if it is set (and not a promise).\n const possibleValue = valuesMemo.current[inputValue];\n if (Array.isArray(possibleValue)) {\n return {\n loading: false,\n value: possibleValue,\n };\n }\n\n return state;\n};\n\n/**\n * Utility hook for applying a given default value to the search context.\n *\n * @public\n */\nexport const useDefaultFilterValue = (\n name: string,\n defaultValue?: string | string[] | null,\n) => {\n const { setFilters } = useSearch();\n\n useEffect(() => {\n if (defaultValue && [defaultValue].flat().length > 0) {\n setFilters(prevFilters => ({\n ...prevFilters,\n [name]: defaultValue,\n }));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\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, { ChangeEvent, useState } from 'react';\nimport { Chip, TextField } from '@material-ui/core';\nimport {\n Autocomplete,\n AutocompleteGetTagProps,\n AutocompleteRenderInputParams,\n} from '@material-ui/lab';\n\nimport { useSearch } from '../../context';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\nimport { SearchFilterComponentProps } from './SearchFilter';\n\n/**\n * @public\n */\nexport type SearchAutocompleteFilterProps = SearchFilterComponentProps & {\n filterSelectedOptions?: boolean;\n limitTags?: number;\n multiple?: boolean;\n};\n\n/**\n * @public\n */\nexport const AutocompleteFilter = (props: SearchAutocompleteFilterProps) => {\n const {\n className,\n defaultValue,\n name,\n values: givenValues,\n valuesDebounceMs,\n label,\n filterSelectedOptions,\n limitTags,\n multiple,\n } = props;\n const [inputValue, setInputValue] = useState<string>('');\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values, loading } = useAsyncFilterValues(\n asyncValues,\n inputValue,\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n const filterValue =\n (filters[name] as string | string[] | undefined) || (multiple ? [] : null);\n\n // Set new filter values on input change.\n const handleChange = (\n _: ChangeEvent<{}>,\n newValue: string | string[] | null,\n ) => {\n setFilters(prevState => {\n const { [name]: filter, ...others } = prevState;\n\n if (newValue) {\n return { ...others, [name]: newValue };\n }\n return { ...others };\n });\n };\n\n // Provide the input field.\n const renderInput = (params: AutocompleteRenderInputParams) => (\n <TextField\n {...params}\n name=\"search\"\n variant=\"outlined\"\n label={label}\n fullWidth\n />\n );\n\n // Render tags as primary-colored chips.\n const renderTags = (\n tagValue: string[],\n getTagProps: AutocompleteGetTagProps,\n ) =>\n tagValue.map((option: string, index: number) => (\n <Chip label={option} color=\"primary\" {...getTagProps({ index })} />\n ));\n\n return (\n <Autocomplete\n filterSelectedOptions={filterSelectedOptions}\n limitTags={limitTags}\n multiple={multiple}\n className={className}\n id={`${multiple ? 'multi-' : ''}select-filter-${name}--select`}\n options={values || []}\n loading={loading}\n value={filterValue}\n onChange={handleChange}\n onInputChange={(_, newValue) => setInputValue(newValue)}\n renderInput={renderInput}\n renderTags={renderTags}\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 React, { ReactElement, ChangeEvent } from 'react';\nimport {\n makeStyles,\n FormControl,\n FormControlLabel,\n InputLabel,\n Checkbox,\n Select,\n MenuItem,\n FormLabel,\n} from '@material-ui/core';\n\nimport { useSearch } from '../../context';\nimport {\n AutocompleteFilter,\n SearchAutocompleteFilterProps,\n} from './SearchFilter.Autocomplete';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\n\nconst useStyles = makeStyles({\n label: {\n textTransform: 'capitalize',\n },\n});\n\n/**\n * @public\n */\nexport type SearchFilterComponentProps = {\n className?: string;\n name: string;\n label?: string;\n /**\n * Either an array of values directly, or an async function to return a list\n * of values to be used in the filter. In the autocomplete filter, the last\n * input value is provided as an input to allow values to be filtered. This\n * function is debounced and values cached.\n */\n values?: string[] | ((partial: string) => Promise<string[]>);\n defaultValue?: string[] | string | null;\n /**\n * Debounce time in milliseconds, used when values is an async callback.\n * Defaults to 250ms.\n */\n valuesDebounceMs?: number;\n};\n\n/**\n * @public\n */\nexport type SearchFilterWrapperProps = SearchFilterComponentProps & {\n component: (props: SearchFilterComponentProps) => ReactElement;\n debug?: boolean;\n};\n\n/**\n * @public\n */\nexport const CheckboxFilter = (props: SearchFilterComponentProps) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues = [],\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n const { filters, setFilters } = useSearch();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const {\n target: { value, checked },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n const rest = ((filter as string[]) || []).filter(i => i !== value);\n const items = checked ? [...rest, value] : rest;\n return items.length ? { ...others, [name]: items } : others;\n });\n };\n\n return (\n <FormControl\n className={className}\n disabled={loading}\n fullWidth\n data-testid=\"search-checkboxfilter-next\"\n >\n {label ? <FormLabel className={classes.label}>{label}</FormLabel> : null}\n {values.map((value: string) => (\n <FormControlLabel\n key={value}\n control={\n <Checkbox\n color=\"primary\"\n tabIndex={-1}\n inputProps={{ 'aria-labelledby': value }}\n value={value}\n name={value}\n onChange={handleChange}\n checked={((filters[name] as string[]) ?? []).includes(value)}\n />\n }\n label={value}\n />\n ))}\n </FormControl>\n );\n};\n\n/**\n * @public\n */\nexport const SelectFilter = (props: SearchFilterComponentProps) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues,\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n\n const handleChange = (e: ChangeEvent<{ value: unknown }>) => {\n const {\n target: { value },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n return value ? { ...others, [name]: value as string } : others;\n });\n };\n\n return (\n <FormControl\n disabled={loading}\n className={className}\n variant=\"filled\"\n fullWidth\n data-testid=\"search-selectfilter-next\"\n >\n {label ? (\n <InputLabel className={classes.label} margin=\"dense\">\n {label}\n </InputLabel>\n ) : null}\n <Select\n variant=\"outlined\"\n value={filters[name] || ''}\n onChange={handleChange}\n >\n <MenuItem value=\"\">\n <em>All</em>\n </MenuItem>\n {values.map((value: string) => (\n <MenuItem key={value} value={value}>\n {value}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n\n/**\n * @public\n */\nconst SearchFilter = ({\n component: Element,\n ...props\n}: SearchFilterWrapperProps) => <Element {...props} />;\n\nSearchFilter.Checkbox = (\n props: Omit<SearchFilterWrapperProps, 'component'> &\n SearchFilterComponentProps,\n) => <SearchFilter {...props} component={CheckboxFilter} />;\n\nSearchFilter.Select = (\n props: Omit<SearchFilterWrapperProps, 'component'> &\n SearchFilterComponentProps,\n) => <SearchFilter {...props} component={SelectFilter} />;\n\n/**\n * A control surface for a given filter field name, rendered as an autocomplete\n * textfield. A hard-coded list of values may be provided, or an async function\n * which returns values may be provided instead.\n *\n * @public\n */\nSearchFilter.Autocomplete = (props: SearchAutocompleteFilterProps) => (\n <SearchFilter {...props} component={AutocompleteFilter} />\n);\n\nexport { SearchFilter };\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 from 'react';\n\nimport {\n EmptyState,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchResult } from '@backstage/plugin-search-common';\n\nimport { useSearch } from '../../context';\n\n/**\n * Props for {@link SearchResultComponent}\n *\n * @public\n */\nexport type SearchResultProps = {\n children: (results: { results: SearchResult[] }) => JSX.Element;\n};\n\n/**\n * A component returning the search result.\n *\n * @public\n */\nexport const SearchResultComponent = ({ children }: SearchResultProps) => {\n const {\n result: { loading, error, value },\n } = useSearch();\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return (\n <ResponseErrorPanel\n title=\"Error encountered while fetching search results\"\n error={error}\n />\n );\n }\n\n if (!value?.results.length) {\n return <EmptyState missing=\"data\" title=\"Sorry, no results were found\" />;\n }\n\n return <>{children({ results: value.results })}</>;\n};\n\n/**\n * @public\n */\nconst HigherOrderSearchResult = (props: SearchResultProps) => {\n return (\n <AnalyticsContext\n attributes={{\n pluginId: 'search',\n extension: 'SearchResult',\n }}\n >\n <SearchResultComponent {...props} />\n </AnalyticsContext>\n );\n};\n\nexport { HigherOrderSearchResult as SearchResult };\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 from 'react';\n\nimport { Button, makeStyles } from '@material-ui/core';\nimport ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';\nimport ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';\n\nimport { useSearch } from '../../context';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n display: 'flex',\n justifyContent: 'space-between',\n gap: theme.spacing(2),\n margin: theme.spacing(2, 0),\n },\n}));\n\n/**\n * @public\n */\nexport const SearchResultPager = () => {\n const { fetchNextPage, fetchPreviousPage } = useSearch();\n const classes = useStyles();\n\n if (!fetchNextPage && !fetchPreviousPage) {\n return <></>;\n }\n\n return (\n <nav arial-label=\"pagination navigation\" className={classes.root}>\n <Button\n aria-label=\"previous page\"\n disabled={!fetchPreviousPage}\n onClick={fetchPreviousPage}\n startIcon={<ArrowBackIosIcon />}\n >\n Previous\n </Button>\n\n <Button\n aria-label=\"next page\"\n disabled={!fetchNextPage}\n onClick={fetchNextPage}\n endIcon={<ArrowForwardIosIcon />}\n >\n Next\n </Button>\n </nav>\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, { useEffect } from 'react';\nimport { useAnalytics } from '@backstage/core-plugin-api';\nimport { useSearch } from '../../context';\n\n/**\n * Capture search event on term change.\n */\nexport const TrackSearch = ({ children }: { children: React.ReactChild }) => {\n const analytics = useAnalytics();\n const { term } = useSearch();\n\n useEffect(() => {\n if (term) {\n // Capture analytics search event with search term provided as value\n analytics.captureEvent('search', term);\n }\n }, [analytics, term]);\n\n return <>{children}</>;\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, {\n ChangeEvent,\n KeyboardEvent,\n useState,\n useEffect,\n useCallback,\n} from 'react';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport {\n InputBase,\n InputBaseProps,\n InputAdornment,\n IconButton,\n} from '@material-ui/core';\nimport SearchIcon from '@material-ui/icons/Search';\nimport ClearButton from '@material-ui/icons/Clear';\n\nimport {\n AnalyticsContext,\n configApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\n\nimport {\n SearchContextProvider,\n useSearch,\n useSearchContextCheck,\n} from '../../context';\nimport { TrackSearch } from '../SearchTracker';\n\n/**\n * Props for {@link SearchBarBase}.\n *\n * @public\n */\nexport type SearchBarBaseProps = Omit<InputBaseProps, 'onChange'> & {\n debounceTime?: number;\n clearButton?: boolean;\n onClear?: () => void;\n onSubmit?: () => void;\n onChange: (value: string) => void;\n};\n\n/**\n * All search boxes exported by the search plugin are based on the <SearchBarBase />,\n * and this one is based on the <InputBase /> component from Material UI.\n * Recommended if you don't use Search Provider or Search Context.\n *\n * @public\n */\nexport const SearchBarBase = ({\n onChange,\n onKeyDown,\n onSubmit,\n debounceTime = 200,\n clearButton = true,\n fullWidth = true,\n value: defaultValue,\n inputProps: defaultInputProps = {},\n endAdornment: defaultEndAdornment,\n ...props\n}: SearchBarBaseProps) => {\n const configApi = useApi(configApiRef);\n const [value, setValue] = useState<string>(defaultValue as string);\n const hasSearchContext = useSearchContextCheck();\n\n useEffect(() => {\n setValue(prevValue =>\n prevValue !== defaultValue ? (defaultValue as string) : prevValue,\n );\n }, [defaultValue]);\n\n useDebounce(() => onChange(value), debounceTime, [value]);\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n },\n [setValue],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (onKeyDown) onKeyDown(e);\n if (onSubmit && e.key === 'Enter') {\n onSubmit();\n }\n },\n [onKeyDown, onSubmit],\n );\n\n const handleClear = useCallback(() => {\n onChange('');\n }, [onChange]);\n\n const placeholder = `Search in ${\n configApi.getOptionalString('app.title') || 'Backstage'\n }`;\n\n const startAdornment = (\n <InputAdornment position=\"start\">\n <IconButton aria-label=\"Query\" disabled>\n <SearchIcon />\n </IconButton>\n </InputAdornment>\n );\n\n const endAdornment = (\n <InputAdornment position=\"end\">\n <IconButton aria-label=\"Clear\" onClick={handleClear}>\n <ClearButton />\n </IconButton>\n </InputAdornment>\n );\n\n const searchBar = (\n <TrackSearch>\n <InputBase\n data-testid=\"search-bar-next\"\n value={value}\n placeholder={placeholder}\n startAdornment={startAdornment}\n endAdornment={clearButton ? endAdornment : defaultEndAdornment}\n inputProps={{ 'aria-label': 'Search', ...defaultInputProps }}\n fullWidth={fullWidth}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n {...props}\n />\n </TrackSearch>\n );\n\n return hasSearchContext ? (\n searchBar\n ) : (\n <SearchContextProvider>{searchBar}</SearchContextProvider>\n );\n};\n\n/**\n * Props for {@link SearchBar}.\n *\n * @public\n */\nexport type SearchBarProps = Partial<SearchBarBaseProps>;\n\n/**\n * Recommended search bar when you use the Search Provider or Search Context.\n *\n * @public\n */\nexport const SearchBar = ({ onChange, ...props }: SearchBarProps) => {\n const { term, setTerm } = useSearch();\n\n const handleChange = useCallback(\n (newValue: string) => {\n if (onChange) {\n onChange(newValue);\n } else {\n setTerm(newValue);\n }\n },\n [onChange, setTerm],\n );\n\n return (\n <AnalyticsContext\n attributes={{ pluginId: 'search', extension: 'SearchBar' }}\n >\n <SearchBarBase value={term} onChange={handleChange} {...props} />\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 */\n\nimport React, { ReactNode } from 'react';\nimport { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api';\nimport {\n ResultHighlight,\n SearchDocument,\n} from '@backstage/plugin-search-common';\nimport { HighlightedSearchResultText } from '../HighlightedSearchResultText';\nimport {\n ListItem,\n ListItemIcon,\n ListItemText,\n Box,\n Divider,\n} from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\n\n/**\n * Props for {@link DefaultResultListItem}\n *\n * @public\n */\nexport type DefaultResultListItemProps = {\n icon?: ReactNode;\n secondaryAction?: ReactNode;\n result: SearchDocument;\n highlight?: ResultHighlight;\n rank?: number;\n lineClamp?: number;\n};\n\n/**\n * A default result list item.\n *\n * @public\n */\nexport const DefaultResultListItemComponent = ({\n result,\n highlight,\n rank,\n icon,\n secondaryAction,\n lineClamp = 5,\n}: DefaultResultListItemProps) => {\n const analytics = useAnalytics();\n const handleClick = () => {\n analytics.captureEvent('discover', result.title, {\n attributes: { to: result.location },\n value: rank,\n });\n };\n\n return (\n <Link noTrack to={result.location} onClick={handleClick}>\n <ListItem alignItems=\"center\">\n {icon && <ListItemIcon>{icon}</ListItemIcon>}\n <ListItemText\n primaryTypographyProps={{ variant: 'h6' }}\n primary={\n highlight?.fields.title ? (\n <HighlightedSearchResultText\n text={highlight.fields.title}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.title\n )\n }\n secondary={\n <span\n style={{\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: lineClamp,\n overflow: 'hidden',\n }}\n >\n {highlight?.fields.text ? (\n <HighlightedSearchResultText\n text={highlight.fields.text}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.text\n )}\n </span>\n }\n />\n {secondaryAction && <Box alignItems=\"flex-end\">{secondaryAction}</Box>}\n </ListItem>\n <Divider />\n </Link>\n );\n};\n\n/**\n * @public\n */\nconst HigherOrderDefaultResultListItem = (\n props: DefaultResultListItemProps,\n) => {\n return (\n <AnalyticsContext\n attributes={{\n pluginId: 'search',\n extension: 'DefaultResultListItem',\n }}\n >\n <DefaultResultListItemComponent {...props} />\n </AnalyticsContext>\n );\n};\n\nexport { HigherOrderDefaultResultListItem as DefaultResultListItem };\n"],"names":["useStyles"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-search-react",
3
- "version": "0.2.1-next.0",
3
+ "version": "0.2.2-next.1",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -31,11 +31,16 @@
31
31
  "start": "backstage-cli package start"
32
32
  },
33
33
  "dependencies": {
34
- "@backstage/core-plugin-api": "^1.0.3-next.0",
35
- "@backstage/plugin-search-common": "^0.3.5-next.0",
34
+ "@backstage/core-components": "^0.9.6-next.1",
35
+ "@backstage/core-plugin-api": "^1.0.3",
36
+ "@backstage/plugin-search-common": "^0.3.6-next.0",
37
+ "@backstage/theme": "^0.2.16-next.0",
36
38
  "@backstage/types": "^1.0.0",
37
39
  "@backstage/version-bridge": "^1.0.1",
38
40
  "@material-ui/core": "^4.12.2",
41
+ "@material-ui/icons": "^4.9.1",
42
+ "@material-ui/lab": "4.0.0-alpha.57",
43
+ "react-router": "6.0.0-beta.0",
39
44
  "react-use": "^17.3.2"
40
45
  },
41
46
  "peerDependencies": {
@@ -43,14 +48,15 @@
43
48
  "react": "^16.13.1 || ^17.0.0"
44
49
  },
45
50
  "devDependencies": {
46
- "@backstage/core-app-api": "^1.0.3-next.0",
47
- "@backstage/test-utils": "^1.1.1-next.0",
51
+ "@backstage/core-app-api": "^1.0.4-next.0",
52
+ "@backstage/test-utils": "^1.1.2-next.1",
48
53
  "@testing-library/jest-dom": "^5.10.1",
49
54
  "@testing-library/react": "^12.1.3",
50
- "@testing-library/react-hooks": "^8.0.0"
55
+ "@testing-library/react-hooks": "^8.0.0",
56
+ "@testing-library/user-event": "^14.0.0"
51
57
  },
52
58
  "files": [
53
59
  "dist"
54
60
  ],
55
- "gitHead": "e15c24ddb5d14034629ced8a5a5d8f12b8f1a7dd"
61
+ "gitHead": "e0a993834c31487a97a1ae6878eaf3685f03fc1a"
56
62
  }