@redocly/theme 0.42.2 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) 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 +109 -27
  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 +1 -1
  20. package/lib/components/Search/SearchInput.js +5 -2
  21. package/lib/components/Search/SearchItem.d.ts +2 -2
  22. package/lib/components/Search/SearchItem.js +24 -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 +136 -98
  27. package/lib/components/Select/SelectInput.d.ts +23 -0
  28. package/lib/components/Select/SelectInput.js +129 -0
  29. package/lib/components/Select/variables.js +12 -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 +2 -1
  37. package/lib/core/hooks/__mocks__/index.js +2 -1
  38. package/lib/core/hooks/__mocks__/search/use-search-filter.d.ts +9 -0
  39. package/lib/core/hooks/__mocks__/search/use-search-filter.js +14 -0
  40. package/lib/core/hooks/__mocks__/use-theme-hooks.d.ts +6 -1
  41. package/lib/core/hooks/__mocks__/use-theme-hooks.js +6 -1
  42. package/lib/core/hooks/index.d.ts +2 -1
  43. package/lib/core/hooks/index.js +2 -1
  44. package/lib/core/hooks/search/use-recent-searches.js +2 -0
  45. package/lib/core/hooks/{use-search.d.ts → search/use-search-dialog.d.ts} +1 -1
  46. package/lib/core/hooks/{use-search.js → search/use-search-dialog.js} +5 -5
  47. package/lib/core/hooks/search/use-search-filter.d.ts +9 -0
  48. package/lib/core/hooks/search/use-search-filter.js +50 -0
  49. package/lib/core/types/hooks.d.ts +17 -4
  50. package/lib/core/types/index.d.ts +1 -1
  51. package/lib/core/types/index.js +1 -1
  52. package/lib/core/types/l10n.d.ts +1 -2
  53. package/lib/core/types/search.d.ts +42 -2
  54. package/lib/core/types/select.d.ts +31 -0
  55. package/lib/core/types/{select-option.js → select.js} +1 -1
  56. package/lib/core/utils/index.d.ts +1 -0
  57. package/lib/core/utils/index.js +1 -0
  58. package/lib/core/utils/text-trimmer.d.ts +1 -0
  59. package/lib/core/utils/text-trimmer.js +16 -0
  60. package/lib/icons/ResetIcon/ResetIcon.d.ts +9 -0
  61. package/lib/icons/ResetIcon/ResetIcon.js +22 -0
  62. package/lib/icons/SettingsIcon/SettingsIcon.d.ts +9 -0
  63. package/lib/icons/SettingsIcon/SettingsIcon.js +23 -0
  64. package/lib/index.d.ts +8 -1
  65. package/lib/index.js +8 -1
  66. package/lib/markdoc/components/Cards/Card.js +6 -6
  67. package/package.json +3 -3
  68. package/src/components/Dropdown/DropdownMenu.tsx +2 -1
  69. package/src/components/Filter/FilterSelect.tsx +3 -3
  70. package/src/components/Loaders/SpinnerLoader.tsx +31 -0
  71. package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +135 -0
  72. package/src/components/Search/FilterFields/SearchFilterFieldTags.tsx +61 -0
  73. package/src/components/Search/Search.tsx +2 -2
  74. package/src/components/Search/SearchDialog.tsx +183 -41
  75. package/src/components/Search/SearchFilter.tsx +90 -0
  76. package/src/components/Search/SearchFilterField.tsx +84 -0
  77. package/src/components/Search/SearchGroups.tsx +81 -0
  78. package/src/components/Search/SearchHighlight.tsx +29 -2
  79. package/src/components/Search/SearchInput.tsx +9 -3
  80. package/src/components/Search/SearchItem.tsx +39 -24
  81. package/src/components/Search/variables.ts +48 -2
  82. package/src/components/Segmented/Segmented.tsx +2 -2
  83. package/src/components/Select/Select.tsx +208 -157
  84. package/src/components/Select/SelectInput.tsx +201 -0
  85. package/src/components/Select/variables.ts +12 -1
  86. package/src/components/Tag/Tag.tsx +57 -6
  87. package/src/components/Tag/variables.dark.ts +20 -5
  88. package/src/components/Tag/variables.ts +49 -17
  89. package/src/components/VersionPicker/VersionPicker.tsx +15 -39
  90. package/src/core/hooks/__mocks__/index.ts +2 -1
  91. package/src/core/hooks/__mocks__/search/use-search-filter.ts +10 -0
  92. package/src/core/hooks/__mocks__/use-theme-hooks.ts +6 -1
  93. package/src/core/hooks/index.ts +2 -1
  94. package/src/core/hooks/search/use-recent-searches.ts +3 -0
  95. package/src/core/hooks/{use-search.ts → search/use-search-dialog.ts} +1 -1
  96. package/src/core/hooks/search/use-search-filter.ts +57 -0
  97. package/src/core/types/hooks.ts +25 -4
  98. package/src/core/types/index.ts +1 -1
  99. package/src/core/types/l10n.ts +110 -38
  100. package/src/core/types/search.ts +53 -2
  101. package/src/core/types/select.ts +33 -0
  102. package/src/core/utils/index.ts +1 -0
  103. package/src/core/utils/text-trimmer.ts +7 -0
  104. package/src/icons/ResetIcon/ResetIcon.tsx +26 -0
  105. package/src/icons/SettingsIcon/SettingsIcon.tsx +30 -0
  106. package/src/index.ts +8 -1
  107. package/src/markdoc/components/Cards/Card.tsx +15 -15
  108. package/lib/core/types/select-option.d.ts +0 -4
  109. package/src/core/types/select-option.ts +0 -4
  110. /package/lib/components/{Loading → Loaders}/Loading.d.ts +0 -0
  111. /package/lib/components/{Loading → Loaders}/Loading.js +0 -0
  112. /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, checkmarkIconPosition: "start" }));
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,17 @@ 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");
45
+ const SettingsIcon_1 = require("../../icons/SettingsIcon/SettingsIcon");
42
46
  function SearchDialog({ onClose, className }) {
43
- const { useTranslate, useCurrentProduct, useFuseSearch, useProducts } = (0, hooks_1.useThemeHooks)();
47
+ const { useTranslate, useCurrentProduct, useSearch, useProducts } = (0, hooks_1.useThemeHooks)();
44
48
  const products = useProducts();
45
49
  const currentProduct = useCurrentProduct();
46
50
  const [product, setProduct] = (0, react_1.useState)(currentProduct);
47
- const { query, setQuery, items, isLoading } = useFuseSearch(product === null || product === void 0 ? void 0 : product.name);
51
+ const { query, setQuery, filter, setFilter, items, isSearchLoading, facets, setLoadMore, advancedSearch, } = useSearch(product === null || product === void 0 ? void 0 : product.name);
52
+ const { isFilterOpen, onFilterToggle, onFilterChange, onFilterReset, onFacetReset, onTopFacetsReset, } = (0, hooks_1.useSearchFilter)(filter, setFilter);
48
53
  const modalRef = (0, react_1.useRef)(null);
49
54
  const { translate } = useTranslate();
50
55
  (0, hooks_1.useDialogHotKeys)(modalRef, onClose);
@@ -57,31 +62,67 @@ function SearchDialog({ onClose, className }) {
57
62
  onClose();
58
63
  }
59
64
  };
60
- const mapItem = (item) => {
65
+ const mapItem = (item, index) => {
61
66
  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}/`); });
67
+ if (!product && item.document.product) {
68
+ const resolvedProduct = products.find((product) => { var _a; return product.slug.match(`/${(_a = item.document.product) === null || _a === void 0 ? void 0 : _a.folder}/`); });
64
69
  itemProduct = resolvedProduct
65
70
  ? { name: resolvedProduct.name, icon: resolvedProduct.icon }
66
71
  : undefined;
67
72
  }
68
- return react_1.default.createElement(SearchItem_1.SearchItem, { key: item.id, item: item, product: itemProduct });
73
+ return react_1.default.createElement(SearchItem_1.SearchItem, { key: `${index}-${item.document.id}`, item: item, product: itemProduct });
69
74
  };
75
+ const showLoadMore = (groupKey, currentCount = 0) => {
76
+ const topFacet = facets.find((facet) => facet.isTop);
77
+ let needLoadMore = false;
78
+ if (topFacet) {
79
+ const groupValue = topFacet.values.find((value) => {
80
+ if (typeof value === 'object') {
81
+ return value.value === groupKey;
82
+ }
83
+ else
84
+ return false;
85
+ });
86
+ needLoadMore = groupValue ? groupValue.count > currentCount : false;
87
+ }
88
+ return needLoadMore;
89
+ };
90
+ const showResults = !!((filter && filter.length) || query);
70
91
  return (react_1.default.createElement(SearchOverlay, { "data-component-name": "Search/SearchDialog", ref: modalRef, onClick: handleOverlayClick, className: (0, utils_1.concatClassNames)('overlay', className) },
71
92
  react_1.default.createElement(SearchDialogWrapper, { className: "scroll-lock", role: "dialog" },
72
93
  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)))),
94
+ product && (react_1.default.createElement(react_1.default.Fragment, null,
95
+ react_1.default.createElement(SearchProductTag, { color: "product" },
96
+ product.name,
97
+ react_1.default.createElement(CloseIcon_1.CloseIcon, { onClick: () => setProduct(undefined), color: "--icon-color-additional" })))),
98
+ react_1.default.createElement(SearchInput_1.SearchInput, { value: query, onChange: setQuery, placeholder: translate('theme.search.label', 'Search docs...'), isLoading: isSearchLoading, "data-translation-key": "theme.search.label" }),
99
+ advancedSearch && (react_1.default.createElement(SearchFilterToggleButton, { icon: react_1.default.createElement(SettingsIcon_1.SettingsIcon, null), onClick: onFilterToggle }))),
100
+ react_1.default.createElement(SearchDialogBody, null,
101
+ react_1.default.createElement(SearchDialogBodyMainView, null,
102
+ react_1.default.createElement(SearchGroups_1.SearchGroups, { facets: facets, searchFilter: filter, onFilterChange: onFilterChange, onTopFacetsReset: onTopFacetsReset }),
103
+ 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) => {
104
+ var _a, _b, _c;
105
+ return ((_a = items[key]) === null || _a === void 0 ? void 0 : _a.length) ? (react_1.default.createElement(react_1.Fragment, { key: key },
106
+ react_1.default.createElement(SearchGroupTitle, null, key), (_b = items[key]) === null || _b === void 0 ? void 0 :
107
+ _b.map(mapItem),
108
+ 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;
109
+ })) : isSearchLoading ? (react_1.default.createElement(SearchMessage, null,
110
+ react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "26px", color: "var(--search-input-icon-color)" }),
111
+ translate('theme.search.loading', 'Loading...'))) : (react_1.default.createElement(SearchMessage, { "data-translation-key": "theme.search.noResults" },
112
+ react_1.default.createElement("b", null, translate('theme.search.noResults.title', 'No results')),
113
+ translate('theme.search.noResults.description', 'Prease, try with a different query.')))) : (react_1.default.createElement(react_1.default.Fragment, null,
114
+ react_1.default.createElement(SearchRecent_1.SearchRecent, { onSelect: setQuery }),
115
+ react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))),
116
+ advancedSearch && isFilterOpen && (react_1.default.createElement(SearchDialogBodyFilterView, null,
117
+ react_1.default.createElement(SearchFilter_1.SearchFilter, { facets: facets, filter: filter, query: query, onFilterChange: onFilterChange, onFilterReset: onFilterReset, onFacetReset: onFacetReset })))),
80
118
  react_1.default.createElement(SearchDialogFooter, null,
81
119
  react_1.default.createElement(SearchShortcuts, null,
82
120
  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
121
  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
122
  react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "theme.search.keys.exit", combination: "Esc", text: translate('theme.search.keys.exit', 'to exit') })),
123
+ isSearchLoading && (react_1.default.createElement(SearchLoading, null,
124
+ react_1.default.createElement(SpinnerLoader_1.SpinnerLoader, { size: "16px", color: "var(--search-input-icon-color)" }),
125
+ translate('theme.search.loading', 'Loading...'))),
85
126
  react_1.default.createElement(SearchCancelButton, { "data-translation-key": "theme.search.cancel", variant: "secondary", size: "small", onClick: onClose }, translate('theme.search.cancel', 'Cancel'))))));
86
127
  }
87
128
  exports.SearchDialog = SearchDialog;
@@ -100,7 +141,6 @@ const SearchOverlay = styled_components_1.default.div `
100
141
  const SearchDialogWrapper = styled_components_1.default.div `
101
142
  display: flex;
102
143
  flex-direction: column;
103
- justify-content: space-between;
104
144
  overflow: auto;
105
145
  width: 100vw;
106
146
  height: 100vh;
@@ -116,49 +156,70 @@ const SearchDialogWrapper = styled_components_1.default.div `
116
156
  max-height: 95vh;
117
157
  height: auto;
118
158
  resize: both;
119
- min-width: 300px;
120
- min-height: 200px;
121
159
  }
122
160
  `;
123
161
  const SearchDialogHeader = styled_components_1.default.header `
124
162
  display: flex;
125
163
  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);
164
+ border-bottom: var(--search-modal-border);
165
+ background-color: var(--search-modal-header-bg-color);
166
+ padding: var(--search-modal-header-padding);
129
167
  `;
130
168
  const SearchDialogBody = styled_components_1.default.div `
169
+ display: flex;
170
+ flex-direction: row;
131
171
  flex-grow: 1;
132
- overflow-y: scroll;
133
- overscroll-behavior: contain;
134
172
 
135
173
  @media screen and (min-width: ${utils_1.breakpoints.small}) {
136
174
  height: var(--search-modal-min-height);
137
175
  }
138
176
  `;
177
+ const SearchDialogBodyMainView = styled_components_1.default.div `
178
+ flex: 2;
179
+ flex-grow: 2;
180
+ overflow-y: scroll;
181
+ overscroll-behavior: contain;
182
+ border-right: var(--search-modal-border);
183
+ `;
184
+ const SearchDialogBodyFilterView = styled_components_1.default.div `
185
+ overflow: scroll;
186
+ `;
139
187
  const SearchDialogFooter = styled_components_1.default.footer `
140
- padding: var(--spacing-sm);
141
- border-top: 1px solid var(--border-color-secondary);
188
+ display: flex;
189
+ gap: var(--search-modal-footer-gap);
190
+ padding: var(--search-modal-footer-padding);
191
+ border-top: var(--search-modal-border);
142
192
  `;
143
193
  const SearchShortcuts = styled_components_1.default.div `
144
194
  display: none;
145
195
  justify-content: flex-start;
146
196
  align-items: center;
147
- gap: var(--spacing-xs);
197
+ gap: var(--search-shortcuts-gap);
148
198
 
149
199
  @media screen and (min-width: ${utils_1.breakpoints.small}) {
150
200
  display: flex;
151
201
  }
152
202
  `;
153
203
  const SearchMessage = styled_components_1.default.div `
154
- padding: var(--spacing-lg);
155
- color: var(--search-item-title-text-color);
204
+ display: flex;
205
+ height: 40%;
206
+ justify-content: center;
207
+ align-items: center;
208
+ flex-direction: column;
209
+ font-size: var(--search-message-font-size);
210
+ font-weight: var(--search-message-font-weight);
211
+ line-height: var(--search-message-line-height);
212
+ color: var(--search-message-text-color);
213
+ gap: var(--search-message-gap);
156
214
  `;
157
215
  const SearchProductTag = (0, styled_components_1.default)(Tag_1.Tag) `
158
216
  --tag-border-radius: var(--border-radius);
159
-
217
+ border: none;
160
218
  margin: var(--spacing-xs) var(--spacing-sm) !important;
161
219
  `;
220
+ const SearchFilterToggleButton = (0, styled_components_1.default)(Button_1.Button) `
221
+ margin-left: 0;
222
+ `;
162
223
  const SearchCancelButton = (0, styled_components_1.default)(Button_1.Button) `
163
224
  width: 100%;
164
225
 
@@ -166,4 +227,25 @@ const SearchCancelButton = (0, styled_components_1.default)(Button_1.Button) `
166
227
  display: none;
167
228
  }
168
229
  `;
230
+ const SearchGroupTitle = styled_components_1.default.div `
231
+ border-bottom: var(--search-modal-border);
232
+ padding: var(--search-group-title-padding);
233
+ background-color: var(--search-group-title-bg-color);
234
+ `;
235
+ const SearchGroupFooter = styled_components_1.default.div `
236
+ display: flex;
237
+ justify-content: center;
238
+ padding: var(--search-group-footer-padding);
239
+ color: var(--search-group-footer-text-color);
240
+ cursor: pointer;
241
+ `;
242
+ const SearchLoading = styled_components_1.default.div `
243
+ display: none;
244
+ align-items: center;
245
+ gap: var(--spacing-xs);
246
+
247
+ @media screen and (min-width: ${utils_1.breakpoints.small}) {
248
+ display: flex;
249
+ }
250
+ `;
169
251
  //# 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, 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 {};