@redocly/theme 0.40.6 → 0.41.0-rc.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.
Files changed (101) hide show
  1. package/lib/components/Dropdown/DropdownMenu.d.ts +2 -0
  2. package/lib/components/Dropdown/DropdownMenu.js +3 -1
  3. package/lib/components/Loaders/SpinnerLoader.d.ts +5 -0
  4. package/lib/components/Loaders/SpinnerLoader.js +32 -0
  5. package/lib/components/Search/FilterFields/SearchFilterFieldSelect.d.ts +12 -0
  6. package/lib/components/Search/FilterFields/SearchFilterFieldSelect.js +113 -0
  7. package/lib/components/Search/FilterFields/SearchFilterFieldTags.d.ts +10 -0
  8. package/lib/components/Search/FilterFields/SearchFilterFieldTags.js +37 -0
  9. package/lib/components/Search/Search.js +1 -1
  10. package/lib/components/Search/SearchDialog.js +103 -26
  11. package/lib/components/Search/SearchFilter.d.ts +11 -0
  12. package/lib/components/Search/SearchFilter.js +71 -0
  13. package/lib/components/Search/SearchFilterField.d.ts +11 -0
  14. package/lib/components/Search/SearchFilterField.js +43 -0
  15. package/lib/components/Search/SearchGroups.d.ts +9 -0
  16. package/lib/components/Search/SearchGroups.js +69 -0
  17. package/lib/components/Search/SearchHighlight.d.ts +1 -1
  18. package/lib/components/Search/SearchHighlight.js +28 -5
  19. package/lib/components/Search/SearchInput.d.ts +3 -2
  20. package/lib/components/Search/SearchInput.js +11 -3
  21. package/lib/components/Search/SearchItem.d.ts +2 -2
  22. package/lib/components/Search/SearchItem.js +23 -15
  23. package/lib/components/Search/variables.js +48 -2
  24. package/lib/components/Segmented/Segmented.d.ts +2 -5
  25. package/lib/components/Select/Select.d.ts +2 -36
  26. package/lib/components/Select/Select.js +110 -98
  27. package/lib/components/Select/SelectInput.d.ts +22 -0
  28. package/lib/components/Select/SelectInput.js +118 -0
  29. package/lib/components/Select/variables.js +11 -1
  30. package/lib/components/Tag/Tag.d.ts +4 -2
  31. package/lib/components/Tag/Tag.js +40 -4
  32. package/lib/components/Tag/variables.dark.js +20 -5
  33. package/lib/components/Tag/variables.js +49 -17
  34. package/lib/components/VersionPicker/VersionPicker.d.ts +2 -3
  35. package/lib/components/VersionPicker/VersionPicker.js +13 -30
  36. package/lib/core/hooks/__mocks__/index.d.ts +1 -1
  37. package/lib/core/hooks/__mocks__/index.js +1 -1
  38. package/lib/core/hooks/__mocks__/use-theme-hooks.d.ts +1 -1
  39. package/lib/core/hooks/__mocks__/use-theme-hooks.js +1 -1
  40. package/lib/core/hooks/index.d.ts +2 -1
  41. package/lib/core/hooks/index.js +2 -1
  42. package/lib/core/hooks/search/use-recent-searches.js +2 -0
  43. package/lib/core/hooks/{use-search.d.ts → search/use-search-dialog.d.ts} +1 -1
  44. package/lib/core/hooks/{use-search.js → search/use-search-dialog.js} +5 -5
  45. package/lib/core/hooks/search/use-search-filter.d.ts +9 -0
  46. package/lib/core/hooks/search/use-search-filter.js +50 -0
  47. package/lib/core/types/hooks.d.ts +16 -4
  48. package/lib/core/types/index.d.ts +1 -1
  49. package/lib/core/types/index.js +1 -1
  50. package/lib/core/types/l10n.d.ts +1 -1
  51. package/lib/core/types/search.d.ts +43 -2
  52. package/lib/core/types/select.d.ts +29 -0
  53. package/lib/core/types/{select-option.js → select.js} +1 -1
  54. package/lib/icons/ResetIcon/ResetIcon.d.ts +9 -0
  55. package/lib/icons/ResetIcon/ResetIcon.js +22 -0
  56. package/lib/icons/SettingsIcon/SettingsIcon.d.ts +9 -0
  57. package/lib/icons/SettingsIcon/SettingsIcon.js +23 -0
  58. package/lib/index.d.ts +7 -1
  59. package/lib/index.js +7 -1
  60. package/package.json +2 -2
  61. package/src/components/Dropdown/DropdownMenu.tsx +2 -1
  62. package/src/components/Filter/FilterSelect.tsx +3 -3
  63. package/src/components/Loaders/SpinnerLoader.tsx +31 -0
  64. package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +134 -0
  65. package/src/components/Search/FilterFields/SearchFilterFieldTags.tsx +61 -0
  66. package/src/components/Search/Search.tsx +2 -2
  67. package/src/components/Search/SearchDialog.tsx +168 -42
  68. package/src/components/Search/SearchFilter.tsx +90 -0
  69. package/src/components/Search/SearchFilterField.tsx +84 -0
  70. package/src/components/Search/SearchGroups.tsx +80 -0
  71. package/src/components/Search/SearchHighlight.tsx +29 -2
  72. package/src/components/Search/SearchInput.tsx +17 -3
  73. package/src/components/Search/SearchItem.tsx +38 -24
  74. package/src/components/Search/variables.ts +48 -2
  75. package/src/components/Segmented/Segmented.tsx +2 -2
  76. package/src/components/Select/Select.tsx +170 -157
  77. package/src/components/Select/SelectInput.tsx +184 -0
  78. package/src/components/Select/variables.ts +11 -1
  79. package/src/components/Tag/Tag.tsx +57 -6
  80. package/src/components/Tag/variables.dark.ts +20 -5
  81. package/src/components/Tag/variables.ts +49 -17
  82. package/src/components/VersionPicker/VersionPicker.tsx +15 -39
  83. package/src/core/hooks/__mocks__/index.ts +1 -1
  84. package/src/core/hooks/__mocks__/use-theme-hooks.ts +1 -1
  85. package/src/core/hooks/index.ts +2 -1
  86. package/src/core/hooks/search/use-recent-searches.ts +3 -0
  87. package/src/core/hooks/{use-search.ts → search/use-search-dialog.ts} +1 -1
  88. package/src/core/hooks/search/use-search-filter.ts +57 -0
  89. package/src/core/types/hooks.ts +24 -4
  90. package/src/core/types/index.ts +1 -1
  91. package/src/core/types/l10n.ts +7 -1
  92. package/src/core/types/search.ts +54 -2
  93. package/src/core/types/select.ts +31 -0
  94. package/src/icons/ResetIcon/ResetIcon.tsx +26 -0
  95. package/src/icons/SettingsIcon/SettingsIcon.tsx +30 -0
  96. package/src/index.ts +7 -1
  97. package/lib/core/types/select-option.d.ts +0 -4
  98. package/src/core/types/select-option.ts +0 -4
  99. /package/lib/components/{Loading → Loaders}/Loading.d.ts +0 -0
  100. /package/lib/components/{Loading → Loaders}/Loading.js +0 -0
  101. /package/src/components/{Loading → Loaders}/Loading.tsx +0 -0
@@ -1,8 +1,10 @@
1
+ import React from 'react';
1
2
  import type { ReactNode } from 'react';
2
3
  import type { DropdownMenuItemProps } from '../../components/Dropdown/DropdownMenuItem';
3
4
  export type DropdownMenuProps = {
4
5
  className?: string;
5
6
  role?: string;
7
+ footer?: React.ReactNode;
6
8
  } & ({
7
9
  items: DropdownMenuItemProps[];
8
10
  } | {
@@ -15,7 +15,9 @@ function DropdownMenu(props) {
15
15
  if ('items' in props) {
16
16
  content = props.items.map((item, idx) => (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, Object.assign({ key: idx }, item), item.content)));
17
17
  }
18
- return (react_1.default.createElement(DropdownMenuWrapper, { "data-component-name": "Dropdown/DropdownMenu", "data-testid": "dropdown-menu", className: props.className, role: props.role || 'menu' }, content));
18
+ return (react_1.default.createElement(DropdownMenuWrapper, { "data-component-name": "Dropdown/DropdownMenu", "data-testid": "dropdown-menu", className: props.className, role: props.role || 'menu' },
19
+ content,
20
+ props.footer || null));
19
21
  }
20
22
  exports.DropdownMenu = DropdownMenu;
21
23
  const DropdownMenuWrapper = styled_components_1.default.ul `
@@ -0,0 +1,5 @@
1
+ export type LoadingProps = {
2
+ color: string;
3
+ size: string;
4
+ };
5
+ export declare function SpinnerLoader({ color, size }: LoadingProps): JSX.Element;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SpinnerLoader = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ function SpinnerLoader({ color, size }) {
10
+ return react_1.default.createElement(Spinner, { color: color, size: size });
11
+ }
12
+ exports.SpinnerLoader = SpinnerLoader;
13
+ const Spinner = styled_components_1.default.div `
14
+ width: ${({ size }) => size};
15
+ height: ${({ size }) => size};
16
+ border: 3px solid ${({ color }) => color};
17
+ border-bottom-color: transparent;
18
+ border-radius: 50%;
19
+ display: inline-block;
20
+ box-sizing: border-box;
21
+ animation: rotation 1s linear infinite;
22
+
23
+ @keyframes rotation {
24
+ 0% {
25
+ transform: rotate(0deg);
26
+ }
27
+ 100% {
28
+ transform: rotate(360deg);
29
+ }
30
+ }
31
+ `;
32
+ //# sourceMappingURL=SpinnerLoader.js.map
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { SearchFacet, SearchFilterItem } from '../../../core/types';
3
+ type SearchFilterFieldSelectProps = {
4
+ className?: string;
5
+ facet: SearchFacet;
6
+ filter: SearchFilterItem[];
7
+ query: string;
8
+ selectedValues: string[];
9
+ onChange: (value: string | string[]) => void;
10
+ };
11
+ export declare function SearchFilterFieldSelect({ facet, filter, query, selectedValues, onChange, }: SearchFilterFieldSelectProps): React.JSX.Element;
12
+ export {};
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.SearchFilterFieldSelect = void 0;
30
+ const react_1 = __importStar(require("react"));
31
+ const styled_components_1 = __importDefault(require("styled-components"));
32
+ const hooks_1 = require("../../../core/hooks");
33
+ const Select_1 = require("../../../components/Select/Select");
34
+ const CounterTag_1 = require("../../../components/Tags/CounterTag");
35
+ function SearchFilterFieldSelect({ facet, filter, query, selectedValues, onChange, }) {
36
+ const MAX_SELECT_OPTIONS = 20;
37
+ const { useFacetQuery, useTranslate } = (0, hooks_1.useThemeHooks)();
38
+ const { translate } = useTranslate();
39
+ const { searchFacet, setSearchFacet, setSearchFacetQuery } = useFacetQuery(facet.field);
40
+ const [selectOptions, setSelectOptions] = (0, react_1.useState)([]);
41
+ const isMultiple = facet.type === 'multi-select';
42
+ (0, react_1.useEffect)(() => {
43
+ setSelectOptions(getSelectOptions());
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [searchFacet, facet]);
46
+ const onSearch = (value) => {
47
+ if (value === null) {
48
+ setSearchFacet(null);
49
+ setSearchFacetQuery(null);
50
+ }
51
+ else if (typeof value === 'string') {
52
+ setSearchFacetQuery({
53
+ query,
54
+ filter,
55
+ facetQuery: value,
56
+ });
57
+ }
58
+ };
59
+ const getSelectOptions = () => {
60
+ return searchFacet
61
+ ? searchFacet.values.map(facetValueToSelectOption)
62
+ : facet.values.map(facetValueToSelectOption);
63
+ };
64
+ const facetValueToSelectOption = (facetValue) => {
65
+ if (!facetValue) {
66
+ return { element: null, value: '' };
67
+ }
68
+ if (typeof facetValue === 'string') {
69
+ return {
70
+ element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
71
+ react_1.default.createElement(FilterSelectOptionText, null, facetValue))),
72
+ value: facetValue,
73
+ };
74
+ }
75
+ else {
76
+ const { value, count, isCounterVisible } = facetValue;
77
+ return {
78
+ element: (react_1.default.createElement(FilterSelectOptionWrapper, null,
79
+ react_1.default.createElement(FilterSelectOptionText, null, value),
80
+ isCounterVisible && react_1.default.createElement(CounterTag_1.CounterTag, null, count))),
81
+ value: value,
82
+ };
83
+ }
84
+ };
85
+ return (react_1.default.createElement(Select_1.Select, { value: selectedValues.length
86
+ ? isMultiple
87
+ ? selectedValues.map((value) => facetValueToSelectOption(value))
88
+ : facetValueToSelectOption(selectedValues[0])
89
+ : undefined, options: selectOptions, onChange: onChange, placeholder: `${translate('theme.search.filter.field.placeholder', 'Search')} ${facet.name.toLowerCase()}...`, alignment: "start", multiple: isMultiple, searchable: true, footer: selectOptions.length === MAX_SELECT_OPTIONS ? (react_1.default.createElement(FilterSelectFooter, null, "Search to show more items...")) : null, onSearch: onSearch }));
90
+ }
91
+ exports.SearchFilterFieldSelect = SearchFilterFieldSelect;
92
+ const FilterSelectOptionWrapper = styled_components_1.default.div `
93
+ width: 100%;
94
+ display: flex;
95
+ justify-content: space-between;
96
+ align-items: center;
97
+ gap: var(--search-filter-field-select-option-gap);
98
+ `;
99
+ const FilterSelectOptionText = styled_components_1.default.span `
100
+ overflow: hidden;
101
+ text-overflow: ellipsis;
102
+ white-space: nowrap;
103
+ width: 100%;
104
+ padding: var(--search-filter-field-select-option-text-padding);
105
+ `;
106
+ const FilterSelectFooter = styled_components_1.default.div `
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ padding: var(--search-filter-field-select-footer-padding);
111
+ color: var(--search-filter-field-select-footer-text-color);
112
+ `;
113
+ //# sourceMappingURL=SearchFilterFieldSelect.js.map
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { SearchFacet } from '../../../core/types';
3
+ type SearchFilterFieldTagsProps = {
4
+ className?: string;
5
+ facet: SearchFacet;
6
+ selectedValues: string[];
7
+ onChange: (value: string | string[]) => void;
8
+ };
9
+ export declare function SearchFilterFieldTags({ className, facet, selectedValues, onChange, }: SearchFilterFieldTagsProps): React.JSX.Element;
10
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SearchFilterFieldTags = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const Tag_1 = require("../../../components/Tag/Tag");
10
+ function SearchFilterFieldTags({ className, facet, selectedValues, onChange, }) {
11
+ return (react_1.default.createElement(FilterTagsWrapper, { "data-component-name": "Search/FilterFields/SearchFilterFieldTags", className: className }, facet.values.map((facetCount, index) => {
12
+ const { value, count, isCounterVisible } = facetCount;
13
+ const active = selectedValues.includes(value);
14
+ return (react_1.default.createElement(FilterTagWrapper, { key: `${count}-${index}`, color: value, onClick: () => {
15
+ const values = active
16
+ ? selectedValues.filter((item) => item !== value)
17
+ : [...selectedValues, value];
18
+ onChange(values);
19
+ }, active: active, borderless: true },
20
+ value,
21
+ " ",
22
+ isCounterVisible && react_1.default.createElement("span", null, count)));
23
+ })));
24
+ }
25
+ exports.SearchFilterFieldTags = SearchFilterFieldTags;
26
+ const FilterTagsWrapper = styled_components_1.default.div `
27
+ display: flex;
28
+ flex-wrap: wrap;
29
+ gap: var(--search-filter-field-tags-gap);
30
+ `;
31
+ const FilterTagWrapper = (0, styled_components_1.default)(Tag_1.Tag) `
32
+ text-transform: uppercase;
33
+ cursor: pointer;
34
+ ${({ color }) => color && `background-color: var(--tag-operation-bg-color-${color});`}
35
+ margin: var(--search-filter-field-tags-tag-margin);
36
+ `;
37
+ //# sourceMappingURL=SearchFilterFieldTags.js.map
@@ -10,7 +10,7 @@ const SearchTrigger_1 = require("../../components/Search/SearchTrigger");
10
10
  const SearchDialog_1 = require("../../components/Search/SearchDialog");
11
11
  const hooks_1 = require("../../core/hooks");
12
12
  function Search({ className }) {
13
- const { isOpen, onOpen, onClose } = (0, hooks_1.useSearch)();
13
+ const { isOpen, onOpen, onClose } = (0, hooks_1.useSearchDialog)();
14
14
  return (react_1.default.createElement(SearchWrapper, { "data-component-name": "Search/Search", className: className },
15
15
  react_1.default.createElement(SearchTrigger_1.SearchTrigger, { onClick: onOpen }),
16
16
  isOpen && react_1.default.createElement(SearchDialog_1.SearchDialog, { onClose: onClose })));
@@ -39,12 +39,16 @@ const SearchSuggestedPages_1 = require("../../components/Search/SearchSuggestedP
39
39
  const hooks_1 = require("../../core/hooks");
40
40
  const Tag_1 = require("../../components/Tag/Tag");
41
41
  const CloseIcon_1 = require("../../icons/CloseIcon/CloseIcon");
42
+ const SearchFilter_1 = require("../../components/Search/SearchFilter");
43
+ const SearchGroups_1 = require("../../components/Search/SearchGroups");
44
+ const SpinnerLoader_1 = require("../../components/Loaders/SpinnerLoader");
42
45
  function SearchDialog({ onClose, className }) {
43
- const { useTranslate, useCurrentProduct, useFuseSearch, useProducts } = (0, hooks_1.useThemeHooks)();
46
+ const { useTranslate, useCurrentProduct, useSearch, useProducts } = (0, hooks_1.useThemeHooks)();
44
47
  const products = useProducts();
45
48
  const currentProduct = useCurrentProduct();
46
49
  const [product, setProduct] = (0, react_1.useState)(currentProduct);
47
- const { query, setQuery, items, isLoading } = useFuseSearch(product === null || product === void 0 ? void 0 : product.name);
50
+ const { query, setQuery, filter, setFilter, items, isSearchLoading, facets, setLoadMore } = useSearch(product === null || product === void 0 ? void 0 : product.name);
51
+ const { isFilterOpen, onFilterToggle, onFilterChange, onFilterReset, onFacetReset, onTopFacetsReset, } = (0, hooks_1.useSearchFilter)(filter, setFilter);
48
52
  const modalRef = (0, react_1.useRef)(null);
49
53
  const { translate } = useTranslate();
50
54
  (0, hooks_1.useDialogHotKeys)(modalRef, onClose);
@@ -59,29 +63,64 @@ function SearchDialog({ onClose, className }) {
59
63
  };
60
64
  const mapItem = (item) => {
61
65
  let itemProduct;
62
- if (!product && item.product) {
63
- const resolvedProduct = products.find((product) => { var _a; return product.slug.match(`/${(_a = item.product) === null || _a === void 0 ? void 0 : _a.folder}/`); });
66
+ if (!product && item.document.product) {
67
+ const resolvedProduct = products.find((product) => { var _a; return product.slug.match(`/${(_a = item.document.product) === null || _a === void 0 ? void 0 : _a.folder}/`); });
64
68
  itemProduct = resolvedProduct
65
69
  ? { name: resolvedProduct.name, icon: resolvedProduct.icon }
66
70
  : undefined;
67
71
  }
68
- return react_1.default.createElement(SearchItem_1.SearchItem, { key: item.id, item: item, product: itemProduct });
72
+ return react_1.default.createElement(SearchItem_1.SearchItem, { key: item.document.id, item: item, product: itemProduct });
69
73
  };
74
+ const showLoadMore = (groupKey, currentCount = 0) => {
75
+ const topFacet = facets.find((facet) => facet.isTop);
76
+ let needLoadMore = false;
77
+ if (topFacet) {
78
+ const groupValue = topFacet.values.find((value) => {
79
+ if (typeof value === 'object') {
80
+ return value.value === groupKey;
81
+ }
82
+ else
83
+ return false;
84
+ });
85
+ needLoadMore = groupValue ? groupValue.count > currentCount : false;
86
+ }
87
+ return needLoadMore;
88
+ };
89
+ const showResults = !!((filter && filter.length) || query);
70
90
  return (react_1.default.createElement(SearchOverlay, { "data-component-name": "Search/SearchDialog", ref: modalRef, onClick: handleOverlayClick, className: (0, utils_1.concatClassNames)('overlay', className) },
71
91
  react_1.default.createElement(SearchDialogWrapper, { className: "scroll-lock", role: "dialog" },
72
92
  react_1.default.createElement(SearchDialogHeader, null,
73
- react_1.default.createElement(SearchInput_1.SearchInput, { value: query, onChange: setQuery, placeholder: translate('theme.search.label', 'Search docs...'), isLoading: isLoading, "data-translation-key": "theme.search.label" }),
74
- product && (react_1.default.createElement(SearchProductTag, { color: "product" },
75
- product.name,
76
- react_1.default.createElement(CloseIcon_1.CloseIcon, { onClick: () => setProduct(undefined), color: "--icon-color-additional" })))),
77
- react_1.default.createElement(SearchDialogBody, null, items !== null ? (items.length ? (items.map(mapItem)) : (react_1.default.createElement(SearchMessage, { "data-translation-key": "theme.search.noResults" }, translate('theme.search.noResults', 'No results')))) : (react_1.default.createElement(react_1.default.Fragment, null,
78
- react_1.default.createElement(SearchRecent_1.SearchRecent, { onSelect: setQuery }),
79
- react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))),
93
+ product && (react_1.default.createElement(react_1.default.Fragment, null,
94
+ react_1.default.createElement(SearchProductTag, { color: "product" },
95
+ product.name,
96
+ react_1.default.createElement(CloseIcon_1.CloseIcon, { onClick: () => setProduct(undefined), color: "--icon-color-additional" })))),
97
+ react_1.default.createElement(SearchInput_1.SearchInput, { value: query, onChange: setQuery, onFilterToggle: onFilterToggle, placeholder: translate('theme.search.label', 'Search docs...'), isLoading: isSearchLoading, "data-translation-key": "theme.search.label" })),
98
+ react_1.default.createElement(SearchDialogBody, null,
99
+ react_1.default.createElement(SearchDialogBodyMainView, null,
100
+ react_1.default.createElement(SearchGroups_1.SearchGroups, { facets: facets, searchFilter: filter, onFilterChange: onFilterChange, onTopFacetsReset: onTopFacetsReset }),
101
+ showResults ? (items && Object.keys(items).some((key) => { var _a; return (_a = items[key]) === null || _a === void 0 ? void 0 : _a.length; }) ? (Object.keys(items).map((key) => {
102
+ var _a, _b, _c;
103
+ return ((_a = items[key]) === null || _a === void 0 ? void 0 : _a.length) ? (react_1.default.createElement(react_1.Fragment, { key: key },
104
+ react_1.default.createElement(SearchGroupTitle, null, key), (_b = items[key]) === null || _b === void 0 ? void 0 :
105
+ _b.map(mapItem),
106
+ showLoadMore(key, ((_c = items[key]) === null || _c === void 0 ? void 0 : _c.length) || 0) && (react_1.default.createElement(SearchGroupFooter, { "data-translation-key": "theme.search.showMore", onClick: () => { var _a; return setLoadMore({ groupKey: key, offset: ((_a = items[key]) === null || _a === void 0 ? void 0 : _a.length) || 0 }); } }, translate('theme.search.showMore', 'Show more'))))) : null;
107
+ })) : isSearchLoading ? (react_1.default.createElement(SearchMessage, null,
108
+ react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "26px", color: "var(--search-input-icon-color)" }),
109
+ translate('theme.search.loading', 'Loading...'))) : (react_1.default.createElement(SearchMessage, { "data-translation-key": "theme.search.noResults" },
110
+ react_1.default.createElement("b", null, translate('theme.search.noResults.title', 'No results')),
111
+ translate('theme.search.noResults.description', 'Prease, try with a different query.')))) : (react_1.default.createElement(react_1.default.Fragment, null,
112
+ react_1.default.createElement(SearchRecent_1.SearchRecent, { onSelect: setQuery }),
113
+ react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))),
114
+ isFilterOpen && (react_1.default.createElement(SearchDialogBodyFilterView, null,
115
+ react_1.default.createElement(SearchFilter_1.SearchFilter, { facets: facets, filter: filter, query: query, onFilterChange: onFilterChange, onFilterReset: onFilterReset, onFacetReset: onFacetReset })))),
80
116
  react_1.default.createElement(SearchDialogFooter, null,
81
117
  react_1.default.createElement(SearchShortcuts, null,
82
118
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "theme.search.keys.navigate", combination: "Tab", text: translate('theme.search.keys.navigate', 'to navigate') }),
83
119
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "theme.search.keys.select", combination: "\u23CE", text: translate('theme.search.keys.select', 'to select') }),
84
120
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "theme.search.keys.exit", combination: "Esc", text: translate('theme.search.keys.exit', 'to exit') })),
121
+ isSearchLoading && (react_1.default.createElement(SearchLoading, null,
122
+ react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "16px", color: "var(--search-input-icon-color)" }),
123
+ translate('theme.search.loading', 'Loading...'))),
85
124
  react_1.default.createElement(SearchCancelButton, { "data-translation-key": "theme.search.cancel", variant: "secondary", size: "small", onClick: onClose }, translate('theme.search.cancel', 'Cancel'))))));
86
125
  }
87
126
  exports.SearchDialog = SearchDialog;
@@ -100,7 +139,6 @@ const SearchOverlay = styled_components_1.default.div `
100
139
  const SearchDialogWrapper = styled_components_1.default.div `
101
140
  display: flex;
102
141
  flex-direction: column;
103
- justify-content: space-between;
104
142
  overflow: auto;
105
143
  width: 100vw;
106
144
  height: 100vh;
@@ -116,47 +154,65 @@ const SearchDialogWrapper = styled_components_1.default.div `
116
154
  max-height: 95vh;
117
155
  height: auto;
118
156
  resize: both;
119
- min-width: 300px;
120
- min-height: 200px;
121
157
  }
122
158
  `;
123
159
  const SearchDialogHeader = styled_components_1.default.header `
124
160
  display: flex;
125
161
  align-items: center;
126
- border-bottom: 1px solid var(--border-color-secondary);
127
- background-color: var(--search-input-bg-color);
128
- padding: var(--spacing-sm);
162
+ border-bottom: var(--search-modal-border);
163
+ background-color: var(--search-modal-header-bg-color);
164
+ padding: var(--search-modal-header-padding);
129
165
  `;
130
166
  const SearchDialogBody = styled_components_1.default.div `
167
+ display: flex;
168
+ flex-direction: row;
131
169
  flex-grow: 1;
132
- overflow-y: scroll;
133
- overscroll-behavior: contain;
134
170
 
135
171
  @media screen and (min-width: ${utils_1.breakpoints.small}) {
136
172
  height: var(--search-modal-min-height);
137
173
  }
138
174
  `;
175
+ const SearchDialogBodyMainView = styled_components_1.default.div `
176
+ flex: 2;
177
+ flex-grow: 2;
178
+ overflow-y: scroll;
179
+ overscroll-behavior: contain;
180
+ border-right: var(--search-modal-border);
181
+ `;
182
+ const SearchDialogBodyFilterView = styled_components_1.default.div `
183
+ overflow: scroll;
184
+ `;
139
185
  const SearchDialogFooter = styled_components_1.default.footer `
140
- padding: var(--spacing-sm);
141
- border-top: 1px solid var(--border-color-secondary);
186
+ display: flex;
187
+ gap: var(--search-modal-footer-gap);
188
+ padding: var(--search-modal-footer-padding);
189
+ border-top: var(--search-modal-border);
142
190
  `;
143
191
  const SearchShortcuts = styled_components_1.default.div `
144
192
  display: none;
145
193
  justify-content: flex-start;
146
194
  align-items: center;
147
- gap: var(--spacing-xs);
195
+ gap: var(--search-shortcuts-gap);
148
196
 
149
197
  @media screen and (min-width: ${utils_1.breakpoints.small}) {
150
198
  display: flex;
151
199
  }
152
200
  `;
153
201
  const SearchMessage = styled_components_1.default.div `
154
- padding: var(--spacing-lg);
155
- color: var(--search-item-title-text-color);
202
+ display: flex;
203
+ height: 40%;
204
+ justify-content: center;
205
+ align-items: center;
206
+ flex-direction: column;
207
+ font-size: var(--search-message-font-size);
208
+ font-weight: var(--search-message-font-weight);
209
+ line-height: var(--search-message-line-height);
210
+ color: var(--search-message-text-color);
211
+ gap: var(--search-message-gap);
156
212
  `;
157
213
  const SearchProductTag = (0, styled_components_1.default)(Tag_1.Tag) `
158
214
  --tag-border-radius: var(--border-radius);
159
-
215
+ border: none;
160
216
  margin: var(--spacing-xs) var(--spacing-sm) !important;
161
217
  `;
162
218
  const SearchCancelButton = (0, styled_components_1.default)(Button_1.Button) `
@@ -166,4 +222,25 @@ const SearchCancelButton = (0, styled_components_1.default)(Button_1.Button) `
166
222
  display: none;
167
223
  }
168
224
  `;
225
+ const SearchGroupTitle = styled_components_1.default.div `
226
+ border-bottom: var(--search-modal-border);
227
+ padding: var(--search-group-title-padding);
228
+ background-color: var(--search-group-title-bg-color);
229
+ `;
230
+ const SearchGroupFooter = styled_components_1.default.div `
231
+ display: flex;
232
+ justify-content: center;
233
+ padding: var(--search-group-footer-padding);
234
+ color: var(--search-group-footer-text-color);
235
+ cursor: pointer;
236
+ `;
237
+ const SearchLoading = styled_components_1.default.div `
238
+ display: none;
239
+ align-items: center;
240
+ gap: var(--spacing-xs);
241
+
242
+ @media screen and (min-width: ${utils_1.breakpoints.small}) {
243
+ display: flex;
244
+ }
245
+ `;
169
246
  //# sourceMappingURL=SearchDialog.js.map
@@ -0,0 +1,11 @@
1
+ import type { SearchFilterItem, SearchFacet } from '../../core/types';
2
+ export type SearchFilterProps = {
3
+ className?: string;
4
+ facets: SearchFacet[];
5
+ filter: SearchFilterItem[];
6
+ query: string;
7
+ onFilterChange: (field: string, value: string | string[], isTop?: boolean) => void;
8
+ onFilterReset: () => void;
9
+ onFacetReset: (field: string) => void;
10
+ };
11
+ export declare function SearchFilter({ className, facets, filter, query, onFilterChange, onFilterReset, onFacetReset, }: SearchFilterProps): JSX.Element;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.SearchFilter = void 0;
30
+ const React = __importStar(require("react"));
31
+ const styled_components_1 = __importDefault(require("styled-components"));
32
+ const Button_1 = require("../../components/Button/Button");
33
+ const CleanIcon_1 = require("../../icons/CleanIcon/CleanIcon");
34
+ const SearchFilterField_1 = require("../../components/Search/SearchFilterField");
35
+ const hooks_1 = require("../../core/hooks");
36
+ function SearchFilter({ className, facets, filter, query, onFilterChange, onFilterReset, onFacetReset, }) {
37
+ const { useTranslate } = (0, hooks_1.useThemeHooks)();
38
+ const { translate } = useTranslate();
39
+ return (React.createElement(SearchFilterWrapper, { "data-component-name": "Search/SearchFilter", className: className },
40
+ React.createElement(SearchFilterHeader, null,
41
+ React.createElement("span", { "data-translation-key": "theme.search.filter.title" }, translate('theme.search.filter.title', 'Advanced filter')),
42
+ React.createElement(Button_1.Button, { "data-translation-key": "theme.search.filter.reset", onClick: onFilterReset, variant: "ghost", icon: React.createElement(CleanIcon_1.CleanIcon, null) }, translate('theme.search.filter.reset', 'Reset filters'))),
43
+ React.createElement(SearchFilterFields, null, facets.map((facet, index) => (React.createElement(SearchFilterField_1.SearchFilterField, { key: `${facet.field}-${index}`, facet: facet, onFilterChange: onFilterChange, onFacetReset: onFacetReset, filter: filter, query: query }))))));
44
+ }
45
+ exports.SearchFilter = SearchFilter;
46
+ const SearchFilterWrapper = styled_components_1.default.div `
47
+ width: var(--search-filter-width);
48
+ display: flex;
49
+ flex-direction: column;
50
+ padding: var(--search-filter-padding);
51
+ font-size: var(--search-filter-font-size);
52
+ font-weight: var(--search-filter-font-weight);
53
+ line-height: var(--search-filter-line-height);
54
+ `;
55
+ const SearchFilterHeader = styled_components_1.default.div `
56
+ position: sticky;
57
+ top: 0px;
58
+ display: flex;
59
+ justify-content: space-between;
60
+ align-items: center;
61
+ padding: var(--search-filter-header-padding);
62
+ color: var(--search-filter-header-text-color);
63
+ background-color: var(--search-filter-bg-color);
64
+ z-index: var(--search-filter-header-z-index);
65
+ `;
66
+ const SearchFilterFields = styled_components_1.default.div `
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: var(--search-filter-fields-gap);
70
+ `;
71
+ //# sourceMappingURL=SearchFilter.js.map
@@ -0,0 +1,11 @@
1
+ import type { SearchFacet, SearchFilterItem } from '../../core/types';
2
+ type SearchFilterFieldProps = {
3
+ className?: string;
4
+ facet: SearchFacet;
5
+ filter: SearchFilterItem[];
6
+ query: string;
7
+ onFilterChange: (field: string, value: string | string[], isTop?: boolean) => void;
8
+ onFacetReset: (filed: string) => void;
9
+ };
10
+ export declare function SearchFilterField({ className, facet, filter, query, onFilterChange, onFacetReset, }: SearchFilterFieldProps): JSX.Element;
11
+ export {};
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SearchFilterField = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const Button_1 = require("../../components/Button/Button");
10
+ const ResetIcon_1 = require("../../icons/ResetIcon/ResetIcon");
11
+ const core_1 = require("../../core");
12
+ const SearchFilterFieldSelect_1 = require("../../components/Search/FilterFields/SearchFilterFieldSelect");
13
+ const SearchFilterFieldTags_1 = require("../../components/Search/FilterFields/SearchFilterFieldTags");
14
+ function SearchFilterField({ className, facet, filter, query, onFilterChange, onFacetReset, }) {
15
+ var _a;
16
+ const { useTranslate } = (0, core_1.useThemeHooks)();
17
+ const { translate } = useTranslate();
18
+ const selectedValues = ((_a = filter.find((item) => item.field === facet.field)) === null || _a === void 0 ? void 0 : _a.values) || [];
19
+ const onChange = (value) => {
20
+ onFilterChange(facet.field, value, facet.isTop);
21
+ };
22
+ const onReset = () => {
23
+ onFacetReset(facet.field);
24
+ };
25
+ return (react_1.default.createElement(FilterFieldWrapper, { "data-component-name": "Search/SearchFilterField", className: className },
26
+ react_1.default.createElement(FilterFieldLabel, null,
27
+ facet.name,
28
+ selectedValues.length > 0 && (react_1.default.createElement(Button_1.Button, { "data-translation-key": "theme.search.filter.field.reset", icon: react_1.default.createElement(ResetIcon_1.ResetIcon, null), variant: "ghost", size: "small", onClick: onReset }, translate('theme.search.filter.field.reset', 'Reset')))),
29
+ ['select', 'multi-select'].includes(facet.type) && (react_1.default.createElement(SearchFilterFieldSelect_1.SearchFilterFieldSelect, { facet: facet, filter: filter, query: query, selectedValues: selectedValues, onChange: onChange })),
30
+ facet.type === 'tags' && (react_1.default.createElement(SearchFilterFieldTags_1.SearchFilterFieldTags, { facet: facet, selectedValues: selectedValues, onChange: onChange }))));
31
+ }
32
+ exports.SearchFilterField = SearchFilterField;
33
+ const FilterFieldWrapper = styled_components_1.default.div `
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: 4px;
37
+ `;
38
+ const FilterFieldLabel = styled_components_1.default.div `
39
+ display: flex;
40
+ justify-content: space-between;
41
+ align-items: center;
42
+ `;
43
+ //# sourceMappingURL=SearchFilterField.js.map
@@ -0,0 +1,9 @@
1
+ import { type SearchFacet, type SearchFilterItem } from '../../index.js';
2
+ type SearchGroupsProps = {
3
+ facets: SearchFacet[];
4
+ searchFilter: SearchFilterItem[];
5
+ onFilterChange: (field: string, value: string[], isTop?: boolean) => void;
6
+ onTopFacetsReset: () => void;
7
+ };
8
+ export declare function SearchGroups({ facets, searchFilter, onFilterChange, onTopFacetsReset, }: SearchGroupsProps): JSX.Element;
9
+ export {};