@geotab/zenith 3.0.1 → 3.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/advancedGroupsFilter/advancedGroupsFilter.d.ts +1 -0
- package/dist/advancedGroupsFilter/advancedGroupsFilter.js +2 -2
- package/dist/advancedGroupsFilter/advancedGroupsFilterFormSection.js +3 -1
- package/dist/chip/chip.js +5 -5
- package/dist/commonStyles/zIndex.less +5 -0
- package/dist/dateInput/dateInput.d.ts +2 -1
- package/dist/dateInput/dateInput.js +11 -2
- package/dist/dateRange/dateRange.js +9 -8
- package/dist/dropdown/dropdown.d.ts +2 -0
- package/dist/dropdown/dropdown.js +6 -5
- package/dist/dropdown/dropdownHelper.d.ts +4 -4
- package/dist/dropdown/dropdownHelper.js +2 -1
- package/dist/dropdown/dropdownList.js +2 -2
- package/dist/dropdown/dropdownPopup.d.ts +1 -0
- package/dist/dropdown/dropdownPopup.js +2 -2
- package/dist/dropdown/dropdownSearchableTrigger.js +1 -1
- package/dist/dropdown/stateReducer/stateReducer.d.ts +6 -2
- package/dist/dropdown/stateReducer/stateReducer.js +28 -42
- package/dist/dropdown/stateReducer/stateReducerHelper.d.ts +2 -0
- package/dist/dropdown/stateReducer/stateReducerHelper.js +12 -1
- package/dist/dropdown/useDropdownState.d.ts +1 -1
- package/dist/dropdown/useDropdownState.js +5 -2
- package/dist/filters/components/filtersContainer.d.ts +1 -0
- package/dist/filters/components/filtersContainer.js +10 -11
- package/dist/filters/components/filtersDateInput.d.ts +10 -0
- package/dist/filters/components/filtersDateInput.js +27 -0
- package/dist/filters/components/filtersDropdown.d.ts +5 -4
- package/dist/filters/components/filtersDropdown.js +3 -3
- package/dist/filters/components/filtersEmptySelectedList.d.ts +2 -0
- package/dist/filters/components/filtersEmptySelectedList.js +11 -0
- package/dist/filters/components/filtersItem.d.ts +5 -4
- package/dist/filters/components/filtersItem.js +2 -1
- package/dist/filters/components/filtersSaveModal.d.ts +3 -1
- package/dist/filters/components/filtersSaveModal.js +2 -2
- package/dist/filters/components/filtersSavedChipComponent.js +68 -6
- package/dist/filters/components/filtersSearch.d.ts +4 -4
- package/dist/filters/components/filtersSearch.js +20 -9
- package/dist/filters/components/filtersSearchItemData.js +18 -1
- package/dist/filters/components/filtersSearchList.d.ts +5 -1
- package/dist/filters/components/filtersSearchList.js +155 -27
- package/dist/filters/components/filtersSelect.d.ts +1 -0
- package/dist/filters/components/filtersSelect.js +35 -7
- package/dist/filters/components/filtersSelectListItem.d.ts +21 -15
- package/dist/filters/components/filtersSelectListItem.js +13 -3
- package/dist/filters/components/filtersSidePanel.d.ts +15 -0
- package/dist/filters/components/filtersSidePanel.js +212 -0
- package/dist/filters/components/filtersSidePanelChip.d.ts +9 -0
- package/dist/filters/components/filtersSidePanelChip.js +13 -0
- package/dist/filters/components/filtersSidePanelDropdown.d.ts +6 -0
- package/dist/filters/components/filtersSidePanelDropdown.js +85 -0
- package/dist/filters/components/filtersSidePanelItem.d.ts +16 -0
- package/dist/filters/components/filtersSidePanelItem.js +67 -0
- package/dist/filters/components/filtersSidePanelRange.d.ts +6 -0
- package/dist/filters/components/filtersSidePanelRange.js +28 -0
- package/dist/filters/filters.d.ts +5 -0
- package/dist/filters/filters.js +101 -38
- package/dist/filters/filtersHelper.d.ts +4 -2
- package/dist/filters/filtersHelper.js +40 -1
- package/dist/filters/filtersHooks.d.ts +12 -2
- package/dist/filters/filtersHooks.js +21 -3
- package/dist/formStepper/formStepper.d.ts +1 -1
- package/dist/formStepper/formStepper.js +5 -2
- package/dist/groupsFilter/groupsFilter.js +72 -37
- package/dist/groupsFilter/groupsFilterMenu.d.ts +1 -0
- package/dist/groupsFilter/groupsFilterMenu.js +2 -2
- package/dist/groupsFilter/groupsFilterTrigger.js +1 -1
- package/dist/images/imageLooking.d.ts +4 -0
- package/dist/images/imageLooking.js +16 -0
- package/dist/index.css +407 -83
- package/dist/index.d.ts +7 -4
- package/dist/index.js +26 -15
- package/dist/list/list.d.ts +3 -1
- package/dist/list/list.js +2 -2
- package/dist/mobileSheet/mobileSheet.d.ts +2 -0
- package/dist/mobileSheet/mobileSheet.js +4 -4
- package/dist/modal/modal.d.ts +1 -0
- package/dist/modal/modal.js +2 -2
- package/dist/radioGroup/radioGroup.d.ts +1 -0
- package/dist/radioGroup/radioGroup.js +3 -2
- package/dist/range/range.js +29 -10
- package/dist/searchInputRaw/searchInputRaw.js +1 -1
- package/dist/sidePanel/sidePanel.d.ts +1 -0
- package/dist/sidePanel/sidePanel.js +3 -3
- package/dist/tabs/tabItem/tabItem.d.ts +1 -0
- package/dist/tabs/tabItem/tabItem.js +2 -2
- package/dist/tabs/tabs.d.ts +1 -0
- package/dist/tabs/tabs.js +1 -1
- package/dist/utils/keyboardHelpers.d.ts +2 -0
- package/dist/utils/keyboardHelpers.js +49 -0
- package/dist/utils/localization/translations/cs-json.d.ts +1 -0
- package/dist/utils/localization/translations/cs-json.js +2 -1
- package/dist/utils/localization/translations/de-json.d.ts +1 -0
- package/dist/utils/localization/translations/de-json.js +2 -1
- package/dist/utils/localization/translations/en-json.d.ts +7 -0
- package/dist/utils/localization/translations/en-json.js +8 -1
- package/dist/utils/localization/translations/es-json.d.ts +1 -0
- package/dist/utils/localization/translations/es-json.js +2 -1
- package/dist/utils/localization/translations/fr-FR-json.d.ts +1 -0
- package/dist/utils/localization/translations/fr-FR-json.js +2 -1
- package/dist/utils/localization/translations/fr-json.d.ts +1 -0
- package/dist/utils/localization/translations/fr-json.js +2 -1
- package/dist/utils/localization/translations/id-json.d.ts +1 -0
- package/dist/utils/localization/translations/id-json.js +2 -1
- package/dist/utils/localization/translations/it-json.d.ts +1 -0
- package/dist/utils/localization/translations/it-json.js +2 -1
- package/dist/utils/localization/translations/ja-json.d.ts +1 -0
- package/dist/utils/localization/translations/ja-json.js +2 -1
- package/dist/utils/localization/translations/ko-KR-json.d.ts +1 -0
- package/dist/utils/localization/translations/ko-KR-json.js +2 -1
- package/dist/utils/localization/translations/ms-json.d.ts +1 -0
- package/dist/utils/localization/translations/ms-json.js +2 -1
- package/dist/utils/localization/translations/nl-json.d.ts +1 -0
- package/dist/utils/localization/translations/nl-json.js +2 -1
- package/dist/utils/localization/translations/pl-json.d.ts +1 -0
- package/dist/utils/localization/translations/pl-json.js +2 -1
- package/dist/utils/localization/translations/pt-BR-json.d.ts +1 -0
- package/dist/utils/localization/translations/pt-BR-json.js +2 -1
- package/dist/utils/localization/translations/sv-json.d.ts +1 -0
- package/dist/utils/localization/translations/sv-json.js +2 -1
- package/dist/utils/localization/translations/th-json.d.ts +1 -0
- package/dist/utils/localization/translations/th-json.js +2 -1
- package/dist/utils/localization/translations/tr-json.d.ts +1 -0
- package/dist/utils/localization/translations/tr-json.js +2 -1
- package/dist/utils/localization/translations/zh-Hans-json.d.ts +1 -0
- package/dist/utils/localization/translations/zh-Hans-json.js +2 -1
- package/dist/utils/localization/translations/zh-TW-json.d.ts +1 -0
- package/dist/utils/localization/translations/zh-TW-json.js +2 -1
- package/esm/advancedGroupsFilter/advancedGroupsFilter.d.ts +1 -0
- package/esm/advancedGroupsFilter/advancedGroupsFilter.js +2 -2
- package/esm/advancedGroupsFilter/advancedGroupsFilterFormSection.js +3 -1
- package/esm/chip/chip.js +5 -5
- package/esm/dateInput/dateInput.d.ts +2 -1
- package/esm/dateInput/dateInput.js +11 -2
- package/esm/dateRange/dateRange.js +9 -8
- package/esm/dropdown/dropdown.d.ts +2 -0
- package/esm/dropdown/dropdown.js +5 -4
- package/esm/dropdown/dropdownHelper.d.ts +4 -4
- package/esm/dropdown/dropdownHelper.js +2 -1
- package/esm/dropdown/dropdownList.js +2 -2
- package/esm/dropdown/dropdownPopup.d.ts +1 -0
- package/esm/dropdown/dropdownPopup.js +2 -2
- package/esm/dropdown/dropdownSearchableTrigger.js +1 -1
- package/esm/dropdown/stateReducer/stateReducer.d.ts +6 -2
- package/esm/dropdown/stateReducer/stateReducer.js +29 -43
- package/esm/dropdown/stateReducer/stateReducerHelper.d.ts +2 -0
- package/esm/dropdown/stateReducer/stateReducerHelper.js +10 -0
- package/esm/dropdown/useDropdownState.d.ts +1 -1
- package/esm/dropdown/useDropdownState.js +5 -2
- package/esm/filters/components/filtersContainer.d.ts +1 -0
- package/esm/filters/components/filtersContainer.js +12 -13
- package/esm/filters/components/filtersDateInput.d.ts +10 -0
- package/esm/filters/components/filtersDateInput.js +23 -0
- package/esm/filters/components/filtersDropdown.d.ts +5 -4
- package/esm/filters/components/filtersDropdown.js +3 -3
- package/esm/filters/components/filtersEmptySelectedList.d.ts +2 -0
- package/esm/filters/components/filtersEmptySelectedList.js +7 -0
- package/esm/filters/components/filtersItem.d.ts +5 -4
- package/esm/filters/components/filtersItem.js +2 -1
- package/esm/filters/components/filtersSaveModal.d.ts +3 -1
- package/esm/filters/components/filtersSaveModal.js +2 -2
- package/esm/filters/components/filtersSavedChipComponent.js +68 -6
- package/esm/filters/components/filtersSearch.d.ts +4 -4
- package/esm/filters/components/filtersSearch.js +20 -9
- package/esm/filters/components/filtersSearchItemData.js +18 -1
- package/esm/filters/components/filtersSearchList.d.ts +5 -1
- package/esm/filters/components/filtersSearchList.js +156 -28
- package/esm/filters/components/filtersSelect.d.ts +1 -0
- package/esm/filters/components/filtersSelect.js +36 -8
- package/esm/filters/components/filtersSelectListItem.d.ts +21 -15
- package/esm/filters/components/filtersSelectListItem.js +13 -3
- package/esm/filters/components/filtersSidePanel.d.ts +15 -0
- package/esm/filters/components/filtersSidePanel.js +208 -0
- package/esm/filters/components/filtersSidePanelChip.d.ts +9 -0
- package/esm/filters/components/filtersSidePanelChip.js +9 -0
- package/esm/filters/components/filtersSidePanelDropdown.d.ts +6 -0
- package/esm/filters/components/filtersSidePanelDropdown.js +81 -0
- package/esm/filters/components/filtersSidePanelItem.d.ts +16 -0
- package/esm/filters/components/filtersSidePanelItem.js +63 -0
- package/esm/filters/components/filtersSidePanelRange.d.ts +6 -0
- package/esm/filters/components/filtersSidePanelRange.js +24 -0
- package/esm/filters/filters.d.ts +5 -0
- package/esm/filters/filters.js +101 -38
- package/esm/filters/filtersHelper.d.ts +4 -2
- package/esm/filters/filtersHelper.js +37 -0
- package/esm/filters/filtersHooks.d.ts +12 -2
- package/esm/filters/filtersHooks.js +19 -2
- package/esm/formStepper/formStepper.d.ts +1 -1
- package/esm/formStepper/formStepper.js +5 -2
- package/esm/groupsFilter/groupsFilter.js +72 -37
- package/esm/groupsFilter/groupsFilterMenu.d.ts +1 -0
- package/esm/groupsFilter/groupsFilterMenu.js +2 -2
- package/esm/groupsFilter/groupsFilterTrigger.js +1 -1
- package/esm/images/imageLooking.d.ts +4 -0
- package/esm/images/imageLooking.js +12 -0
- package/esm/index.d.ts +7 -4
- package/esm/index.js +6 -3
- package/esm/list/list.d.ts +3 -1
- package/esm/list/list.js +2 -2
- package/esm/mobileSheet/mobileSheet.d.ts +2 -0
- package/esm/mobileSheet/mobileSheet.js +4 -4
- package/esm/modal/modal.d.ts +1 -0
- package/esm/modal/modal.js +2 -2
- package/esm/radioGroup/radioGroup.d.ts +1 -0
- package/esm/radioGroup/radioGroup.js +3 -2
- package/esm/range/range.js +29 -10
- package/esm/searchInputRaw/searchInputRaw.js +1 -1
- package/esm/sidePanel/sidePanel.d.ts +1 -0
- package/esm/sidePanel/sidePanel.js +3 -3
- package/esm/tabs/tabItem/tabItem.d.ts +1 -0
- package/esm/tabs/tabItem/tabItem.js +2 -2
- package/esm/tabs/tabs.d.ts +1 -0
- package/esm/tabs/tabs.js +1 -1
- package/esm/utils/keyboardHelpers.d.ts +2 -0
- package/esm/utils/keyboardHelpers.js +44 -0
- package/esm/utils/localization/translations/cs-json.d.ts +1 -0
- package/esm/utils/localization/translations/cs-json.js +2 -1
- package/esm/utils/localization/translations/de-json.d.ts +1 -0
- package/esm/utils/localization/translations/de-json.js +2 -1
- package/esm/utils/localization/translations/en-json.d.ts +7 -0
- package/esm/utils/localization/translations/en-json.js +8 -1
- package/esm/utils/localization/translations/es-json.d.ts +1 -0
- package/esm/utils/localization/translations/es-json.js +2 -1
- package/esm/utils/localization/translations/fr-FR-json.d.ts +1 -0
- package/esm/utils/localization/translations/fr-FR-json.js +2 -1
- package/esm/utils/localization/translations/fr-json.d.ts +1 -0
- package/esm/utils/localization/translations/fr-json.js +2 -1
- package/esm/utils/localization/translations/id-json.d.ts +1 -0
- package/esm/utils/localization/translations/id-json.js +2 -1
- package/esm/utils/localization/translations/it-json.d.ts +1 -0
- package/esm/utils/localization/translations/it-json.js +2 -1
- package/esm/utils/localization/translations/ja-json.d.ts +1 -0
- package/esm/utils/localization/translations/ja-json.js +2 -1
- package/esm/utils/localization/translations/ko-KR-json.d.ts +1 -0
- package/esm/utils/localization/translations/ko-KR-json.js +2 -1
- package/esm/utils/localization/translations/ms-json.d.ts +1 -0
- package/esm/utils/localization/translations/ms-json.js +2 -1
- package/esm/utils/localization/translations/nl-json.d.ts +1 -0
- package/esm/utils/localization/translations/nl-json.js +2 -1
- package/esm/utils/localization/translations/pl-json.d.ts +1 -0
- package/esm/utils/localization/translations/pl-json.js +2 -1
- package/esm/utils/localization/translations/pt-BR-json.d.ts +1 -0
- package/esm/utils/localization/translations/pt-BR-json.js +2 -1
- package/esm/utils/localization/translations/sv-json.d.ts +1 -0
- package/esm/utils/localization/translations/sv-json.js +2 -1
- package/esm/utils/localization/translations/th-json.d.ts +1 -0
- package/esm/utils/localization/translations/th-json.js +2 -1
- package/esm/utils/localization/translations/tr-json.d.ts +1 -0
- package/esm/utils/localization/translations/tr-json.js +2 -1
- package/esm/utils/localization/translations/zh-Hans-json.d.ts +1 -0
- package/esm/utils/localization/translations/zh-Hans-json.js +2 -1
- package/esm/utils/localization/translations/zh-TW-json.d.ts +1 -0
- package/esm/utils/localization/translations/zh-TW-json.js +2 -1
- package/package.json +1 -1
- package/dist/filters/components/filtersModal.d.ts +0 -17
- package/dist/filters/components/filtersModal.js +0 -107
- package/dist/filters/components/filtersModalItem.d.ts +0 -9
- package/dist/filters/components/filtersModalItem.js +0 -74
- package/esm/filters/components/filtersModal.d.ts +0 -17
- package/esm/filters/components/filtersModal.js +0 -103
- package/esm/filters/components/filtersModalItem.d.ts +0 -9
- package/esm/filters/components/filtersModalItem.js +0 -70
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { List } from "../../list/list";
|
|
4
4
|
import { useLanguage } from "../../utils/localization/useLanguage";
|
|
5
5
|
import { Button } from "../../button/button";
|
|
@@ -11,61 +11,189 @@ import { useMobile } from "../../commonHelpers/hooks/useMobile";
|
|
|
11
11
|
import { useDrive } from "../../utils/theme/useDrive";
|
|
12
12
|
import { classNames } from "../../commonHelpers/classNames/classNames";
|
|
13
13
|
import { MAX_TOTAL_RESULTS } from "../filtersHelper";
|
|
14
|
+
import { EmptySearchList } from "../../dataGrid/emptySearchList/emptySearchList";
|
|
15
|
+
import { getNewFocusableItem } from "../../utils/keyboardHelpers";
|
|
16
|
+
import { FOCUSABLE_SELECTOR } from "../../utils/focusableSelector";
|
|
14
17
|
export const NO_TYPED_SEARCH_ITEM = "noTypedSearchItem";
|
|
15
18
|
export const KEYWORD_ID = "keywordId";
|
|
16
19
|
export const KEYWORD_TYPE = "keyword";
|
|
17
|
-
export const
|
|
20
|
+
export const NOT_POPULATED_NAME = "...";
|
|
21
|
+
export const FiltersSearchList = ({ searchValue, searchData, recentSearches, searchSelection, onlyOneType, handleSearchItemClick, onRemoveRecentSearchItem, handleRecentSearchItemClick, getIconByType, handleClearSearchSelection, searchListRef }) => {
|
|
18
22
|
const { translate } = useLanguage();
|
|
19
|
-
const
|
|
23
|
+
const isSearchModeAvailable = Boolean(handleSearchItemClick && searchSelection);
|
|
24
|
+
const isRecentSearchesModeAvailable = Boolean(recentSearches && handleRecentSearchItemClick && onRemoveRecentSearchItem);
|
|
20
25
|
const isMobile = useMobile();
|
|
21
26
|
const isDrive = useDrive();
|
|
22
27
|
const [removedItems, setRemovedItems] = useState([]);
|
|
23
|
-
const
|
|
28
|
+
const initialSearchSelectionRef = useRef(searchSelection || []);
|
|
29
|
+
const hasNotPopulatedName = initialSearchSelectionRef.current.length === 0 ? false : initialSearchSelectionRef.current.some(el => el.name === NOT_POPULATED_NAME);
|
|
30
|
+
const getCurrentMode = useCallback(() => {
|
|
31
|
+
if (searchValue) {
|
|
32
|
+
return "search";
|
|
33
|
+
}
|
|
34
|
+
if (isSearchModeAvailable && initialSearchSelectionRef.current.length > 0) {
|
|
35
|
+
return "selected";
|
|
36
|
+
}
|
|
37
|
+
if (isRecentSearchesModeAvailable && (recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.data) && recentSearches.data.length > 0) {
|
|
38
|
+
return "recent";
|
|
39
|
+
}
|
|
40
|
+
return "";
|
|
41
|
+
}, [searchValue, isSearchModeAvailable, isRecentSearchesModeAvailable, recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.data]);
|
|
42
|
+
const [currentMode, setCurrentMode] = useState(getCurrentMode());
|
|
24
43
|
const waitingItemsLimit = 5;
|
|
25
|
-
const isRecentSearchesMode = Boolean(recentSearches && handleRecentSearchItemClick && onRemoveRecentSearchItem);
|
|
26
44
|
// Handle React Query errors
|
|
27
45
|
useEffect(() => {
|
|
28
|
-
if (
|
|
46
|
+
if (currentMode === "search" && (searchData === null || searchData === void 0 ? void 0 : searchData.error)) {
|
|
29
47
|
console.error("Failed to fetch search results. Error:", searchData.error);
|
|
30
48
|
}
|
|
31
|
-
}, [
|
|
49
|
+
}, [currentMode, searchData === null || searchData === void 0 ? void 0 : searchData.error]);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (currentMode !== "search" && searchValue) {
|
|
52
|
+
setCurrentMode("search");
|
|
53
|
+
}
|
|
54
|
+
}, [searchValue, currentMode]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (currentMode === "recent" && searchSelection && searchSelection.length === 0) {
|
|
57
|
+
initialSearchSelectionRef.current = [];
|
|
58
|
+
}
|
|
59
|
+
}, [isSearchModeAvailable, isRecentSearchesModeAvailable, currentMode, searchSelection]);
|
|
32
60
|
// Reset history mode when search value changes
|
|
33
61
|
useEffect(() => {
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
if (currentMode === "history" && searchValue) {
|
|
63
|
+
setCurrentMode(isSearchModeAvailable ? "search" : "");
|
|
64
|
+
}
|
|
65
|
+
else if (currentMode === "search" && !searchValue) {
|
|
66
|
+
setCurrentMode(getCurrentMode());
|
|
67
|
+
}
|
|
68
|
+
}, [currentMode, getCurrentMode, isRecentSearchesModeAvailable, isSearchModeAvailable, searchValue]);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (searchSelection && searchSelection.length === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
searchSelection === null || searchSelection === void 0 ? void 0 : searchSelection.forEach(item => {
|
|
74
|
+
const existingItem = initialSearchSelectionRef.current.find(el => (onlyOneType ? el.id === item.id : el.id === item.id && el.type === item.type));
|
|
75
|
+
if (!existingItem) {
|
|
76
|
+
initialSearchSelectionRef.current = [...initialSearchSelectionRef.current, item];
|
|
77
|
+
}
|
|
78
|
+
else if (hasNotPopulatedName) {
|
|
79
|
+
existingItem.name = item.name;
|
|
80
|
+
existingItem.description = item.description;
|
|
81
|
+
existingItem.type = item.type;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}, [hasNotPopulatedName, onlyOneType, searchSelection]);
|
|
85
|
+
const searchItems = useMemo(() => currentMode === "search" || currentMode === "" ? (searchData === null || searchData === void 0 ? void 0 : searchData.data) || [] : [], [currentMode, searchData === null || searchData === void 0 ? void 0 : searchData.data]);
|
|
86
|
+
const recentItems = useMemo(() => currentMode === "recent" || currentMode === "history" ? (recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.data) || [] : [], [currentMode, recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.data]);
|
|
87
|
+
const isLoading = currentMode === "search" && (searchData === null || searchData === void 0 ? void 0 : searchData.isLoading) || (currentMode === "recent" || currentMode === "history" ? recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.isLoading : false) || false;
|
|
88
|
+
const changeMode = useCallback((newVal) => {
|
|
89
|
+
setCurrentMode(newVal);
|
|
43
90
|
setRemovedItems([]);
|
|
44
91
|
// Note: In React Query implementation, the parent component should handle
|
|
45
92
|
// refetching data when switching between modes
|
|
46
93
|
}, []);
|
|
47
94
|
const handleRemove = useCallback((itemId) => () => {
|
|
95
|
+
var _a;
|
|
48
96
|
setRemovedItems(prev => [...prev, itemId]);
|
|
49
97
|
onRemoveRecentSearchItem && onRemoveRecentSearchItem([itemId]);
|
|
50
|
-
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
99
|
+
const firstItem = (_a = searchListRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(FOCUSABLE_SELECTOR);
|
|
100
|
+
firstItem === null || firstItem === void 0 ? void 0 : firstItem.focus();
|
|
101
|
+
}, [onRemoveRecentSearchItem, searchListRef]);
|
|
51
102
|
const handleRemoveAll = useCallback(() => {
|
|
52
103
|
setRemovedItems(recentItems.map(item => item.id));
|
|
53
104
|
onRemoveRecentSearchItem && onRemoveRecentSearchItem(recentItems.map(item => item.id));
|
|
54
|
-
changeMode();
|
|
55
|
-
}, [onRemoveRecentSearchItem,
|
|
105
|
+
changeMode(getCurrentMode());
|
|
106
|
+
}, [recentItems, onRemoveRecentSearchItem, changeMode, getCurrentMode]);
|
|
56
107
|
const memoizedSearchItemClick = useCallback((itemId, itemType) => () => {
|
|
57
|
-
const currentSearchItem = searchItems.find(item => item.id === itemId
|
|
108
|
+
const currentSearchItem = onlyOneType && !itemType ? searchItems.find(item => item.id === itemId)
|
|
109
|
+
: searchItems.find(item => item.id === itemId && item.type === itemType);
|
|
58
110
|
currentSearchItem && handleSearchItemClick && handleSearchItemClick(currentSearchItem);
|
|
59
|
-
}, [handleSearchItemClick, searchItems]);
|
|
111
|
+
}, [handleSearchItemClick, onlyOneType, searchItems]);
|
|
112
|
+
const memoizedSelectedItemClick = useCallback((itemId, itemType) => () => {
|
|
113
|
+
const currentSelectedItem = onlyOneType && !itemType ? initialSearchSelectionRef.current.find(item => item.id === itemId)
|
|
114
|
+
: initialSearchSelectionRef.current.find(item => item.id === itemId && item.type === itemType);
|
|
115
|
+
currentSelectedItem && handleSearchItemClick && handleSearchItemClick(currentSelectedItem);
|
|
116
|
+
}, [handleSearchItemClick, onlyOneType]);
|
|
60
117
|
const memoizedRecentSearchItemClick = useCallback((itemId, itemType) => () => {
|
|
61
118
|
const currentSearchItem = recentItems.find(item => item.id === itemId && item.type === itemType);
|
|
62
119
|
currentSearchItem && handleRecentSearchItemClick && handleRecentSearchItemClick(currentSearchItem);
|
|
63
120
|
}, [handleRecentSearchItemClick, recentItems]);
|
|
121
|
+
const memoizedClearSelectedItems = useCallback(() => {
|
|
122
|
+
var _a;
|
|
123
|
+
handleClearSearchSelection === null || handleClearSearchSelection === void 0 ? void 0 : handleClearSearchSelection();
|
|
124
|
+
initialSearchSelectionRef.current = [];
|
|
125
|
+
setCurrentMode(isRecentSearchesModeAvailable && ((_a = recentSearches === null || recentSearches === void 0 ? void 0 : recentSearches.data) === null || _a === void 0 ? void 0 : _a.length) ? "recent" : "");
|
|
126
|
+
}, [handleClearSearchSelection, isRecentSearchesModeAvailable, recentSearches]);
|
|
127
|
+
const handleKeyDown = useCallback((event) => {
|
|
128
|
+
const isListItem = event.target instanceof HTMLElement && event.target.dataset.listItem === "true";
|
|
129
|
+
const isButtonItem = event.target instanceof HTMLElement && event.target.dataset.closeButton === "true";
|
|
130
|
+
const getSelector = () => {
|
|
131
|
+
if (isListItem) {
|
|
132
|
+
return `[data-list-item="true"]`;
|
|
133
|
+
}
|
|
134
|
+
if (isButtonItem) {
|
|
135
|
+
return `[data-close-button="true"]`;
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
};
|
|
139
|
+
if (event.key === "ArrowDown") {
|
|
140
|
+
const nextItem = getNewFocusableItem(1, searchListRef.current, getSelector());
|
|
141
|
+
nextItem === null || nextItem === void 0 ? void 0 : nextItem.focus();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (event.key === "ArrowUp") {
|
|
145
|
+
const prevItem = getNewFocusableItem(-1, searchListRef.current, getSelector());
|
|
146
|
+
prevItem === null || prevItem === void 0 ? void 0 : prevItem.focus();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (event.key === "ArrowRight" && isListItem) {
|
|
150
|
+
const nextItem = getNewFocusableItem(1, searchListRef.current, `[data-close-button="true"]`);
|
|
151
|
+
nextItem === null || nextItem === void 0 ? void 0 : nextItem.focus();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (event.key === "ArrowLeft" && isButtonItem) {
|
|
155
|
+
const prevItem = getNewFocusableItem(-1, searchListRef.current, `[data-list-item="true"]`);
|
|
156
|
+
prevItem === null || prevItem === void 0 ? void 0 : prevItem.focus();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}, [searchListRef]);
|
|
64
160
|
const memoizedRecentDataArr = useMemo(() => recentItems.filter(item => !removedItems.includes(item.id)).reverse(), [recentItems, removedItems]);
|
|
65
|
-
const memoizedRecentData = useMemo(() =>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
161
|
+
const memoizedRecentData = useMemo(() => {
|
|
162
|
+
if (currentMode !== "recent" && currentMode !== "history") {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
const recentDataArr = currentMode === "history" ? memoizedRecentDataArr : memoizedRecentDataArr.slice(0, waitingItemsLimit);
|
|
166
|
+
return recentDataArr.map(item => (_jsx(FiltersSearchItemData, { id: item.id, name: item.name, isActive: false, secondary: item.description, onClose: handleRemove(item.id), onClick: memoizedRecentSearchItemClick(item.id, item.type), icon: getIconByType(item.type || onlyOneType), isMobile: isMobile, isDrive: isDrive }, `${currentMode}-${item.id}`)));
|
|
167
|
+
}, [currentMode, memoizedRecentDataArr, handleRemove, memoizedRecentSearchItemClick, getIconByType, onlyOneType, isMobile, isDrive]);
|
|
168
|
+
const memoizedSearchData = useMemo(() => currentMode !== "search" && currentMode !== "" ? [] : searchItems.slice(0, MAX_TOTAL_RESULTS).map(item => (_jsx(FiltersSearchItemData, { id: item.id, name: item.name, isActive: isSearchModeAvailable ? (onlyOneType ? searchSelection.some(el => el.id === item.id) : searchSelection.filter(el => el.id === item.id)
|
|
169
|
+
.some(el => el.type === (item.type || NO_TYPED_SEARCH_ITEM)) || false) : false, secondary: item.description, onClose: undefined, onClick: isSearchModeAvailable ? memoizedSearchItemClick(item.id, item.type) : undefined, icon: getIconByType(item.type || onlyOneType), isMobile: isMobile, isDrive: isDrive }, `search-${item.id}-${item.type || NO_TYPED_SEARCH_ITEM}`))), [currentMode, searchItems, isSearchModeAvailable, searchSelection, memoizedSearchItemClick, getIconByType, onlyOneType, isMobile, isDrive]);
|
|
170
|
+
const memoizedSelectedData = useMemo(() => currentMode !== "selected" || initialSearchSelectionRef.current.length === 0 ? [] : initialSearchSelectionRef.current.slice(0, MAX_TOTAL_RESULTS)
|
|
171
|
+
.map(item => (_jsx(FiltersSearchItemData, { id: item.id, name: item.name, isActive: onlyOneType ? (searchSelection || []).some(el => el.id === item.id)
|
|
172
|
+
: (searchSelection || []).filter(el => el.id === item.id).some(el => el.type === (item.type || NO_TYPED_SEARCH_ITEM)) || false, secondary: item.description, onClose: undefined, onClick: memoizedSelectedItemClick(item.id, item.type), icon: getIconByType(item.type || onlyOneType), isMobile: isMobile, isDrive: isDrive }, `selected-${item.id}-${item.type || onlyOneType || NO_TYPED_SEARCH_ITEM}-${item.name}-${hasNotPopulatedName ? "notPopulated" : ""}`))), [currentMode, onlyOneType, searchSelection, memoizedSelectedItemClick, getIconByType, isMobile, isDrive, hasNotPopulatedName]);
|
|
173
|
+
const resultsToShow = useMemo(() => {
|
|
174
|
+
if (currentMode === "search") {
|
|
175
|
+
return memoizedSearchData;
|
|
176
|
+
}
|
|
177
|
+
if (currentMode === "recent" || currentMode === "history") {
|
|
178
|
+
return memoizedRecentData;
|
|
179
|
+
}
|
|
180
|
+
if (currentMode === "selected") {
|
|
181
|
+
return memoizedSelectedData;
|
|
182
|
+
}
|
|
183
|
+
return memoizedSearchData;
|
|
184
|
+
}, [currentMode, memoizedSearchData, memoizedRecentData, memoizedSelectedData]);
|
|
185
|
+
const getSearchHeaderContent = () => {
|
|
186
|
+
if (currentMode === "history") {
|
|
187
|
+
return _jsxs(_Fragment, { children: [_jsx(TextIconButton, { className: "zen-filters-search-list__header-back-button", title: translate("Back"), type: "tertiary", onClick: changeMode.bind(null, "recent"), icon: IconChevronLeft, iconPosition: ButtonIconPosition.Start }), _jsx(Button, { type: "tertiary", onClick: handleRemoveAll, children: translate("Clear all") })] });
|
|
188
|
+
}
|
|
189
|
+
if (currentMode === "recent" || currentMode === "selected") {
|
|
190
|
+
return _jsxs(_Fragment, { children: [_jsxs("div", { className: "zen-filters-search-list__header-title", children: [_jsx(Button, { type: currentMode === "recent" ? "tertiary" : "tertiary-black", className: currentMode === "recent" ? "zen-filters-search-list__header-button--active" : "", title: translate("Recent searches"), onClick: changeMode.bind(null, "recent"), children: translate("Recent searches") }), _jsx(Button, { type: currentMode === "selected" ? "tertiary" : "tertiary-black", className: currentMode === "selected" ? "zen-filters-search-list__header-button--active" : "", title: translate("Currently selected"), onClick: changeMode.bind(null, "selected"), children: translate("Currently selected") })] }), currentMode === "recent" && recentItems.length > resultsToShow.length && _jsx(Button, { type: "tertiary", onClick: changeMode.bind(null, "history"), children: translate("View history") }), currentMode === "selected" && resultsToShow.length > 0 && _jsx(Button, { type: "tertiary", onClick: memoizedClearSelectedItems, children: translate("Clear") })] });
|
|
191
|
+
}
|
|
192
|
+
if (currentMode === "search" && resultsToShow.length > 0) {
|
|
193
|
+
return _jsx("div", { className: "zen-filters-search-list__header-title", children: translate("Top results") });
|
|
194
|
+
}
|
|
195
|
+
return undefined;
|
|
196
|
+
};
|
|
197
|
+
const searchHeaderContent = getSearchHeaderContent();
|
|
198
|
+
return _jsxs("div", { className: "zen-filters-search-list", children: [searchHeaderContent ? _jsx("div", { className: classNames(["zen-filters-search-list__header", isDrive ? (isMobile ? "zen-filters-search-list__header--drive" : "zen-filters-search-list__header--drive-tablet") : ""]), children: searchHeaderContent }) : null, _jsx("div", { ref: searchListRef, children: _jsx(List, { className: "zen-filters-search-list__data", onKeyDown: handleKeyDown, isLoading: currentMode === "selected" ? false : isLoading, type: "data", waitingItems: waitingItemsLimit, children: resultsToShow }) }), !isLoading && resultsToShow.length === 0 ? _jsx(EmptySearchList, { children: translate("No data available") }) : null] });
|
|
71
199
|
};
|
|
@@ -15,6 +15,7 @@ export interface IFiltersSelect extends IFiltersSelectProps {
|
|
|
15
15
|
value: IFiltersSearchType;
|
|
16
16
|
onChange: (newValue: IFiltersSearchType) => void;
|
|
17
17
|
className?: string;
|
|
18
|
+
selectListRef: React.RefObject<HTMLDivElement>;
|
|
18
19
|
}
|
|
19
20
|
export declare const ALL_SELECT_OPTION_ID: string;
|
|
20
21
|
export interface IFiltersSearchType {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
import { classNames } from "../../commonHelpers/classNames/classNames";
|
|
4
4
|
import { useLanguage } from "../../utils/localization/useLanguage";
|
|
5
5
|
import { useUniqueId } from "../../commonHelpers/useUniqueId";
|
|
6
6
|
import { FiltersSelectListExpandableItem, FiltersSelectListItem } from "./filtersSelectListItem";
|
|
7
|
+
import { getNewFocusableItem } from "../../utils/keyboardHelpers";
|
|
7
8
|
export const ALL_SELECT_OPTION_ID = "All";
|
|
8
9
|
export const FiltersSelectDisplayName = "FiltersSelect";
|
|
9
10
|
export const getFiltersSearchTypeAllOption = () => ({
|
|
@@ -13,7 +14,7 @@ export const getAllOption = (translate) => ({
|
|
|
13
14
|
id: ALL_SELECT_OPTION_ID,
|
|
14
15
|
name: translate("All")
|
|
15
16
|
});
|
|
16
|
-
export const FiltersSelect = ({ value,
|
|
17
|
+
export const FiltersSelect = ({ value, onChange, items, className, selectListRef }) => {
|
|
17
18
|
const { translate } = useLanguage();
|
|
18
19
|
const [activeId, setActiveId] = useState("");
|
|
19
20
|
const filtersSelectListId = useUniqueId();
|
|
@@ -28,18 +29,45 @@ export const FiltersSelect = ({ value, name, onChange, id, items, className }) =
|
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
31
|
setActiveId(clickedId);
|
|
31
|
-
|
|
32
|
-
}, [activeId, onChange]);
|
|
32
|
+
}, [activeId]);
|
|
33
33
|
const handleItemClick = useCallback((clickedId, parentId) => () => {
|
|
34
|
+
if (!clickedId) {
|
|
35
|
+
parentId && onChange({ [parentId]: undefined });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
34
38
|
if (parentId) {
|
|
35
39
|
onChange({ [parentId]: clickedId });
|
|
36
40
|
return;
|
|
37
41
|
}
|
|
38
|
-
setActiveId("");
|
|
39
42
|
onChange(Object.keys(value).includes(clickedId) ? getFiltersSearchTypeAllOption() : { [clickedId]: undefined });
|
|
40
43
|
}, [onChange, value]);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
const handleKeyDown = useCallback((event) => {
|
|
45
|
+
var _a, _b, _c, _d;
|
|
46
|
+
if (event.key === "ArrowDown") {
|
|
47
|
+
const nextElement = ((_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.nextElementSibling) ? (_b = document.activeElement) === null || _b === void 0 ? void 0 : _b.nextElementSibling
|
|
48
|
+
: getNewFocusableItem(1, selectListRef.current);
|
|
49
|
+
nextElement === null || nextElement === void 0 ? void 0 : nextElement.focus();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (event.key === "ArrowUp") {
|
|
53
|
+
const nextElement = ((_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.previousElementSibling) ? (_d = document.activeElement) === null || _d === void 0 ? void 0 : _d.previousElementSibling
|
|
54
|
+
: getNewFocusableItem(-1, selectListRef.current);
|
|
55
|
+
nextElement === null || nextElement === void 0 ? void 0 : nextElement.focus();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (event.key === "ArrowLeft") {
|
|
59
|
+
const nextElement = getNewFocusableItem(-1, selectListRef.current);
|
|
60
|
+
nextElement === null || nextElement === void 0 ? void 0 : nextElement.focus();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (event.key === "ArrowRight") {
|
|
64
|
+
const nextElement = getNewFocusableItem(1, selectListRef.current);
|
|
65
|
+
nextElement === null || nextElement === void 0 ? void 0 : nextElement.focus();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}, [selectListRef]);
|
|
69
|
+
const selectListComponent = useMemo(() => preparedItems.map(el => el.subItems && el.subItems.length > 0 ?
|
|
70
|
+
_jsx(FiltersSelectListExpandableItem, { id: `${filtersSelectListId}-${el.id}`, name: el.name, isExpanded: el.id === activeId, isActive: Object.keys(value).includes(el.id) && Boolean(value[el.id]), className: classNames([value.hasOwnProperty(el.id) ? "zen-filters-select__list-item-wrapper--active" : ""]), onExpandItem: handleExpandableItemClick(el.id), onClick: handleItemClick(undefined, el.id), content: el.id === activeId ? el.subItems.map(subEl => _jsx(FiltersSelectListItem, { className: classNames(["zen-filters-select__sub-item"]), id: `${filtersSelectListId}-${el.id}-${subEl.id}`, name: subEl.name, isActive: value[el.id] === subEl.id, onClick: handleItemClick(subEl.id, el.id) }, `${el.id}-${subEl.id}`)) : _jsx(_Fragment, {}) }, `${filtersSelectListId}-${el.id}`) : _jsx(FiltersSelectListItem, { id: `${filtersSelectListId}-${el.id}`, name: el.name, className: "zen-filters-select__list-item--not-expandable", isActive: Object.keys(value).includes(el.id), onClick: handleItemClick(el.id) }, `${filtersSelectListId}-${el.id}`)), [activeId, filtersSelectListId, handleExpandableItemClick, handleItemClick, preparedItems, value]);
|
|
71
|
+
return _jsx("div", { className: "zen-filters-select", ref: selectListRef, onKeyDown: handleKeyDown, children: _jsx("div", { className: classNames(["zen-filters-select__list", className || ""]), children: selectListComponent }) });
|
|
44
72
|
};
|
|
45
73
|
FiltersSelect.displayName = FiltersSelectDisplayName;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
interface IFiltersSelectListItem {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
onClick: () => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const FiltersSelectListItem: ({ id, name, isActive, onClick, className }: IFiltersSelectListItem) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
interface IFiltersSelectListExpandableItem {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
content: React.ReactNode;
|
|
14
|
+
isActive: boolean;
|
|
15
|
+
isExpanded: boolean;
|
|
16
|
+
onClick: () => void;
|
|
17
|
+
className?: string;
|
|
18
|
+
onExpandItem?: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const FiltersSelectListExpandableItem: ({ id, name, content, isActive, isExpanded, onClick, className, onExpandItem }: IFiltersSelectListExpandableItem) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
import { Button } from "../../button/button";
|
|
2
4
|
import { classNames } from "../../commonHelpers/classNames/classNames";
|
|
3
5
|
import { useUniqueId } from "../../commonHelpers/useUniqueId";
|
|
4
|
-
import {
|
|
6
|
+
import { IconChevronDownSmall } from "../../icons/iconChevronDownSmall";
|
|
7
|
+
import { useLanguage } from "../../utils/localization/useLanguage";
|
|
5
8
|
export const FiltersSelectListItem = ({ id, name, isActive, onClick, className = "" }) => _jsx("div", { children: _jsx("button", { type: "button", className: classNames(["zen-filters-select__list-item", isActive ? "zen-filters-select__list-item--active" : "", className]), id: id, onClick: onClick, children: name }) });
|
|
6
|
-
export const FiltersSelectListExpandableItem = ({ id, name, content, isActive, onClick, className = "" }) => {
|
|
9
|
+
export const FiltersSelectListExpandableItem = ({ id, name, content, isActive, isExpanded, onClick, className = "", onExpandItem }) => {
|
|
7
10
|
const ariaControlsId = useUniqueId();
|
|
8
|
-
|
|
11
|
+
const { translate } = useLanguage();
|
|
12
|
+
const handleExpandItem = useCallback((e) => {
|
|
13
|
+
e.stopPropagation();
|
|
14
|
+
if (onExpandItem) {
|
|
15
|
+
onExpandItem();
|
|
16
|
+
}
|
|
17
|
+
}, [onExpandItem]);
|
|
18
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: classNames(["zen-filters-select__list-item-wrapper", isExpanded ? "zen-filters-select__list-item-wrapper--expanded" : "", className]), children: [_jsx("button", { type: "button", className: classNames(["zen-filters-select__list-item"]), id: id, onClick: onClick, children: _jsxs("div", { className: "zen-filters-select__list-item-title", children: [name, isActive ? _jsx("div", { className: "zen-filters-select__item-active-indicator" }) : null] }) }), _jsx(Button, { type: "tertiary-black", onClick: handleExpandItem, className: "zen-filters-select__item-button", "aria-expanded": isExpanded, "aria-controls": ariaControlsId, "aria-label": isExpanded ? `${translate("Collapse")} ${name}` : `${translate("Expand")} ${name}`, children: _jsx(IconChevronDownSmall, { size: "large", className: classNames(["zen-filters-select__item-icon", isExpanded ? "zen-filters-select__item-icon--rotated" : ""]) }) })] }), _jsx("div", { id: ariaControlsId, "aria-labelledby": id, role: "region", className: classNames(["zen-filters-select__item-content", content ? "" : "zen-filters-select__item-content--hidden"]), children: content })] }));
|
|
9
19
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
import { TFiltersComponentsItemState, TFiltersComponentsProps } from "./filtersItem";
|
|
3
|
+
import "./filtersSidePanel.less";
|
|
4
|
+
export interface IFiltersSidePanel {
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onApply: (state: Record<string, TFiltersComponentsItemState>) => void;
|
|
8
|
+
onPin?: () => void;
|
|
9
|
+
isPinned?: boolean;
|
|
10
|
+
filters: ReactElement<TFiltersComponentsProps>[];
|
|
11
|
+
externalState?: Record<string, TFiltersComponentsItemState>;
|
|
12
|
+
setExternalState?: (newState: Partial<Record<string, TFiltersComponentsItemState>>) => void;
|
|
13
|
+
triggerRef: React.RefObject<HTMLElement>;
|
|
14
|
+
}
|
|
15
|
+
export declare const FiltersSidePanel: ({ isOpen, onApply, onClose, onPin, isPinned, filters, externalState, setExternalState, triggerRef }: IFiltersSidePanel) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { useLanguage } from "../../utils/localization/useLanguage";
|
|
4
|
+
import { useUniqueId } from "../../commonHelpers/useUniqueId";
|
|
5
|
+
import { useMobile } from "../../commonHelpers/hooks/useMobile";
|
|
6
|
+
import { useBodyScroll } from "../../utils/useBodyScroll";
|
|
7
|
+
import { Shield } from "../../shield/shield";
|
|
8
|
+
import { createPortal } from "react-dom";
|
|
9
|
+
import { CUSTOM_POPUP_COMPONENT_CLASSNAME, SidePanel, SidePanelCloseReason } from "../../sidePanel/sidePanel";
|
|
10
|
+
import { classNames } from "../../commonHelpers/classNames/classNames";
|
|
11
|
+
import { themeContext } from "../../utils/theme/themeContext";
|
|
12
|
+
import { ButtonIconPosition, TextIconButton } from "../../textIconButton/textIconButton";
|
|
13
|
+
import { IconClose } from "../../icons/iconClose";
|
|
14
|
+
import { Button } from "../../button/button";
|
|
15
|
+
import { FooterButtons } from "../../footerButtons/footerButtons";
|
|
16
|
+
import { IconDisk } from "../../icons/iconDisk";
|
|
17
|
+
import { IconPin2 } from "../../icons/iconPin2";
|
|
18
|
+
import { useFiltersSavedItems } from "./filtersSavedItemsProvider";
|
|
19
|
+
import { useDriveClassName } from "../../utils/theme/useDriveClassName";
|
|
20
|
+
import { ALL_SELECT_OPTION_ID, getAllOption } from "./filtersSelect";
|
|
21
|
+
import { createStateObject } from "../filtersHelper";
|
|
22
|
+
import { Tabs } from "../../tabs/tabs";
|
|
23
|
+
import { FiltersSidePanelItem } from "./filtersSidePanelItem";
|
|
24
|
+
import { FiltersSaveModal } from "./filtersSaveModal";
|
|
25
|
+
import { isElementsEqual } from "../../utils/compareElementsUtils/isElementsEqual";
|
|
26
|
+
import { FiltersEmptySelectedList } from "./filtersEmptySelectedList";
|
|
27
|
+
const SELECTED_TAB_ID = "Selected";
|
|
28
|
+
const getSelectedOption = (translate) => ({
|
|
29
|
+
id: SELECTED_TAB_ID,
|
|
30
|
+
name: translate("Selected")
|
|
31
|
+
});
|
|
32
|
+
export const FiltersSidePanel = ({ isOpen, onApply, onClose, onPin, isPinned, filters, externalState, setExternalState, triggerRef }) => {
|
|
33
|
+
var _a;
|
|
34
|
+
const { translate } = useLanguage();
|
|
35
|
+
const isLongTextLanguages = useMemo(() => `${translate("Reset")}${translate("Cancel")}${translate("Apply")}`.length > 31, [translate]);
|
|
36
|
+
const dataShieldId = useUniqueId();
|
|
37
|
+
const iconDriveClassName = useDriveClassName("icon");
|
|
38
|
+
const { dark } = useContext(themeContext);
|
|
39
|
+
const isMobile = useMobile();
|
|
40
|
+
const { setScrollHidden, resetScroll } = useBodyScroll();
|
|
41
|
+
const { onSave } = useFiltersSavedItems();
|
|
42
|
+
const [activeTabId, setActiveTabId] = useState(ALL_SELECT_OPTION_ID);
|
|
43
|
+
const [isSaveModalOpen, setIsSaveModalOpen] = useState(false);
|
|
44
|
+
const [filtersInternalState, setFiltersInternalState] = useState(createStateObject(filters, "state"));
|
|
45
|
+
const [initialExternalState, setInitialExternalState] = useState(externalState);
|
|
46
|
+
const prevIsOpenRef = useRef(false);
|
|
47
|
+
const [selectedIds, setSelectedIds] = useState([]);
|
|
48
|
+
const [errorItems, setErrorItems] = useState(new Set());
|
|
49
|
+
const saveButtonRef = useRef(null);
|
|
50
|
+
const externalMode = useMemo(() => {
|
|
51
|
+
if (externalState === undefined || setExternalState === undefined) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}, [externalState, setExternalState]);
|
|
56
|
+
const handleInternalFiltersStateChange = useCallback((id) => (newState) => {
|
|
57
|
+
setFiltersInternalState((prevState) => (Object.assign(Object.assign({}, prevState), { [id]: newState })));
|
|
58
|
+
}, []);
|
|
59
|
+
const handleExternalFiltersStateChange = useCallback((id) => (newState) => {
|
|
60
|
+
setExternalState && setExternalState({ [id]: newState });
|
|
61
|
+
}, [setExternalState]);
|
|
62
|
+
const currentState = useMemo(() => externalMode ? externalState
|
|
63
|
+
: filtersInternalState, [externalMode, externalState, filtersInternalState]);
|
|
64
|
+
const currentFilters = useMemo(() => filters.filter((item) => currentState.hasOwnProperty(item.props.id)
|
|
65
|
+
&& (typeof item.props.visible === "boolean" ? item.props.visible
|
|
66
|
+
: item.props.visible === undefined ? true : (item.props.visible([ALL_SELECT_OPTION_ID], currentState) || item.props.visible([ALL_SELECT_OPTION_ID])))), [currentState, filters]);
|
|
67
|
+
const inhibitedFilters = useMemo(() => {
|
|
68
|
+
const inhibited = new Set();
|
|
69
|
+
currentFilters.forEach((item) => {
|
|
70
|
+
if (item.props.inhibit && item.props.inhibit.length > 0) {
|
|
71
|
+
item.props.inhibit.forEach((id) => inhibited.add(id));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return inhibited;
|
|
75
|
+
}, [currentFilters]);
|
|
76
|
+
const filteredCurrentFilters = useMemo(() => currentFilters.filter((item) => !externalMode ? !inhibitedFilters.has(item.props.id) : true), [currentFilters, externalMode, inhibitedFilters]);
|
|
77
|
+
const handleReadyForFocus = useCallback((isCurrentOpen) => {
|
|
78
|
+
if (!isCurrentOpen) {
|
|
79
|
+
triggerRef.current.focus();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}, [triggerRef]);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const handleOpen = () => {
|
|
85
|
+
setScrollHidden();
|
|
86
|
+
};
|
|
87
|
+
const handleClose = () => {
|
|
88
|
+
resetScroll();
|
|
89
|
+
};
|
|
90
|
+
if (isOpen) {
|
|
91
|
+
handleOpen();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
handleClose();
|
|
95
|
+
}
|
|
96
|
+
return () => { handleClose(); };
|
|
97
|
+
}, [isOpen, setScrollHidden, resetScroll]);
|
|
98
|
+
const handleClearClick = useCallback(() => {
|
|
99
|
+
const newState = createStateObject(filters, "defaultState");
|
|
100
|
+
externalMode && setExternalState ? setExternalState(Object.assign({}, newState)) : setFiltersInternalState(newState);
|
|
101
|
+
}, [externalMode, filters, setExternalState]);
|
|
102
|
+
const handleApplyClick = useCallback(() => {
|
|
103
|
+
const stateForApply = externalMode ? currentState : {};
|
|
104
|
+
if (!externalMode) {
|
|
105
|
+
Object.keys(currentState).forEach(key => {
|
|
106
|
+
if (!inhibitedFilters.has(key)) {
|
|
107
|
+
stateForApply[key] = currentState[key];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
onApply(stateForApply);
|
|
112
|
+
onClose();
|
|
113
|
+
}, [currentState, externalMode, inhibitedFilters, onApply, onClose]);
|
|
114
|
+
const handleCancelClick = useCallback(() => {
|
|
115
|
+
const newState = createStateObject(filters, "state");
|
|
116
|
+
externalMode && setExternalState ? setExternalState(Object.assign({}, newState)) : setFiltersInternalState(newState);
|
|
117
|
+
onClose();
|
|
118
|
+
}, [externalMode, filters, onClose, setExternalState]);
|
|
119
|
+
const handleExternalModeClose = useCallback(() => {
|
|
120
|
+
if (!(externalMode && initialExternalState && setExternalState)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
setExternalState(initialExternalState);
|
|
124
|
+
onClose();
|
|
125
|
+
}, [externalMode, initialExternalState, onClose, setExternalState]);
|
|
126
|
+
const toggleSaveModal = useCallback(() => {
|
|
127
|
+
var _a;
|
|
128
|
+
isSaveModalOpen && ((_a = saveButtonRef.current) === null || _a === void 0 ? void 0 : _a.focus());
|
|
129
|
+
setIsSaveModalOpen(val => !val);
|
|
130
|
+
}, [isSaveModalOpen]);
|
|
131
|
+
const handleSaveFilters = useCallback((filterName) => {
|
|
132
|
+
const stateForApply = externalMode ? currentState : {};
|
|
133
|
+
if (!externalMode) {
|
|
134
|
+
Object.keys(currentState).forEach(key => {
|
|
135
|
+
if (!inhibitedFilters.has(key)) {
|
|
136
|
+
stateForApply[key] = currentState[key];
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
onSave && onSave(filterName, stateForApply);
|
|
141
|
+
}, [externalMode, currentState, onSave, inhibitedFilters]);
|
|
142
|
+
const sidePanelItemChangeHandler = useCallback((id) => externalMode ? handleExternalFiltersStateChange(id) : handleInternalFiltersStateChange(id), [externalMode, handleExternalFiltersStateChange, handleInternalFiltersStateChange]);
|
|
143
|
+
const handleErrorCheck = useCallback((id) => (isError) => {
|
|
144
|
+
if (isError && errorItems.has(id) || !isError && !errorItems.has(id)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const newErrorItems = new Set(errorItems);
|
|
148
|
+
newErrorItems[isError ? "add" : "delete"](id);
|
|
149
|
+
setErrorItems(newErrorItems);
|
|
150
|
+
}, [errorItems]);
|
|
151
|
+
const tabsContent = useMemo(() => filteredCurrentFilters
|
|
152
|
+
.map((item) => (_jsx(FiltersSidePanelItem, { item: item, itemState: currentState[item.props.id], changeHandler: sidePanelItemChangeHandler(item.props.id), errorCheck: handleErrorCheck(item.props.id) }, item.props.id))), [filteredCurrentFilters, currentState, sidePanelItemChangeHandler, handleErrorCheck]);
|
|
153
|
+
const defaultStateObject = useMemo(() => createStateObject(filteredCurrentFilters, "defaultState"), [filteredCurrentFilters]);
|
|
154
|
+
const getSelectedIds = useCallback(() => {
|
|
155
|
+
const selected = [];
|
|
156
|
+
filteredCurrentFilters.forEach((el) => {
|
|
157
|
+
const itemState = currentState[el.props.id];
|
|
158
|
+
const defaultState = defaultStateObject[el.props.id];
|
|
159
|
+
if (!isElementsEqual(itemState, defaultState) && !inhibitedFilters.has(el.props.id)) {
|
|
160
|
+
selected.push(el.props.id);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return selected;
|
|
164
|
+
}, [currentState, defaultStateObject, filteredCurrentFilters, inhibitedFilters]);
|
|
165
|
+
const tabOptions = useMemo(() => [
|
|
166
|
+
getAllOption(translate),
|
|
167
|
+
Object.assign(Object.assign({}, getSelectedOption(translate)), { quantity: getSelectedIds().length || undefined })
|
|
168
|
+
], [getSelectedIds, translate]);
|
|
169
|
+
const onTabChange = (newVal) => {
|
|
170
|
+
setActiveTabId(newVal);
|
|
171
|
+
};
|
|
172
|
+
const selectedTabsContent = useMemo(() => selectedIds.length ? filteredCurrentFilters.filter((el) => selectedIds.includes(el.props.id))
|
|
173
|
+
.map((item) => (_jsx(FiltersSidePanelItem, { item: item, itemState: currentState[item.props.id], changeHandler: sidePanelItemChangeHandler(item.props.id), errorCheck: handleErrorCheck(item.props.id) }, item.props.id)))
|
|
174
|
+
: _jsx(FiltersEmptySelectedList, {}), [selectedIds, filteredCurrentFilters, currentState, sidePanelItemChangeHandler, handleErrorCheck]);
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (!isOpen) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (activeTabId === SELECTED_TAB_ID) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
setSelectedIds(getSelectedIds());
|
|
183
|
+
}, [activeTabId, getSelectedIds, isOpen]);
|
|
184
|
+
const resetInitialComponentState = useCallback(() => {
|
|
185
|
+
setIsSaveModalOpen(false);
|
|
186
|
+
setActiveTabId(ALL_SELECT_OPTION_ID);
|
|
187
|
+
setFiltersInternalState(createStateObject(filters, "state"));
|
|
188
|
+
setInitialExternalState(externalState);
|
|
189
|
+
setSelectedIds([]);
|
|
190
|
+
setSelectedIds(getSelectedIds());
|
|
191
|
+
}, [externalState, filters, getSelectedIds]);
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (isOpen !== prevIsOpenRef.current) {
|
|
194
|
+
prevIsOpenRef.current = isOpen;
|
|
195
|
+
isOpen && resetInitialComponentState();
|
|
196
|
+
}
|
|
197
|
+
}, [isOpen, resetInitialComponentState]);
|
|
198
|
+
const handleHidePanel = useCallback((reason, shieldId) => {
|
|
199
|
+
if (isSaveModalOpen) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (reason === SidePanelCloseReason.ClickOutside && shieldId === dataShieldId || reason === SidePanelCloseReason.Escape) {
|
|
203
|
+
onClose();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}, [isSaveModalOpen, dataShieldId, onClose]);
|
|
207
|
+
return _jsxs(Fragment, { children: [_jsx(Shield, { className: "zen-high-level-shield", dataShieldId: dataShieldId, isVisible: isOpen }), createPortal(_jsx(SidePanel, { triggerRef: triggerRef, isOpen: isOpen, label: translate("All Filters"), onHidePanel: handleHidePanel, className: classNames(["zen-side-panel-filters", dark ? "zen-dark" : ""]), onTransitionEnd: handleReadyForFocus, children: _jsxs("div", { className: "zen-side-panel-filters-wrapper", children: [_jsxs("div", { className: "zen-side-panel-filters__header", children: [_jsx("div", { className: "zen-side-panel-filters__title-wrapper", children: _jsx("div", { className: "zen-side-panel-filters__title zen-ellipsis", children: translate("All Filters") }) }), _jsxs("div", { className: "zen-side-panel-filters__header-buttons", children: [onSave && _jsx(Button, { type: "tertiary", ref: saveButtonRef, className: "zen-side-panel-filters__save-button zen-side-panel-filters__header-button", title: translate("Save"), "aria-label": translate("Save"), onClick: toggleSaveModal, children: _jsx(IconDisk, { description: translate("Save"), className: "svgIcon", size: iconDriveClassName ? "huge" : "large" }) }), onPin && _jsx(Button, { type: "tertiary", className: classNames(["zen-side-panel-filters__pin-button", isPinned ? "zen-side-panel-filters__header-button--active" : "", "zen-side-panel-filters__header-button"]), title: translate("Pin"), "aria-label": translate("Pin"), onClick: onPin, children: _jsx(IconPin2, { description: translate("Pin"), className: "svgIcon", size: iconDriveClassName ? "huge" : "large" }) }), _jsx(TextIconButton, { type: "tertiary-black", className: "zen-side-panel-filters__close-button", icon: IconClose, iconSize: "large", onClick: externalMode ? handleExternalModeClose : onClose, iconPosition: ButtonIconPosition.Start, title: translate("Close") })] })] }), _jsx(Tabs, { activeTabId: activeTabId, className: "zen-side-panel-filters__tab-header", onTabChange: onTabChange, tabs: tabOptions }), _jsxs("div", { className: "zen-side-panel-filters__content", children: [_jsx("div", { id: `panel-${ALL_SELECT_OPTION_ID}`, className: classNames(["zen-side-panel-filters__tab-content", activeTabId === ALL_SELECT_OPTION_ID ? "zen-side-panel-filters__tab-content--active" : "zen-side-panel-filters__tab-content--hidden"]), role: "tabpanel", "aria-labelledby": ALL_SELECT_OPTION_ID, children: activeTabId === ALL_SELECT_OPTION_ID ? tabsContent : null }), _jsx("div", { id: `panel-${SELECTED_TAB_ID}`, className: classNames(["zen-side-panel-filters__tab-content", activeTabId === SELECTED_TAB_ID ? "zen-side-panel-filters__tab-content--active" : "zen-side-panel-filters__tab-content--hidden"]), role: "tabpanel", "aria-labelledby": SELECTED_TAB_ID, children: activeTabId === SELECTED_TAB_ID ? selectedTabsContent : null })] }), _jsx("div", { className: classNames(["zen-side-panel-filters__footer", isMobile ? "zen-side-panel-filters__footer--mobile" : "", isLongTextLanguages && !isMobile ? "zen-side-panel-filters__footer--long-text" : ""]), children: isMobile ? _jsxs(FooterButtons, { children: [_jsx(Button, { className: "zen-side-panel-filters__apply-button", onClick: handleApplyClick, type: "primary", disabled: errorItems.size > 0, children: translate("Apply") }), _jsx(Button, { className: "zen-side-panel-filters__cancel-button", type: "secondary", onClick: handleCancelClick, children: translate("Cancel") }), _jsx(Button, { className: "zen-side-panel-filters__clear-button", onClick: handleClearClick, type: "tertiary", children: translate("Reset") })] }) : _jsxs(_Fragment, { children: [_jsx("div", { className: "zen-side-panel-filters__footer-section", children: _jsx(Button, { type: "tertiary", className: "zen-side-panel-filters__clear-button", onClick: handleClearClick, children: translate("Reset") }) }), _jsxs("div", { className: "zen-side-panel-filters__footer-section", children: [_jsx(Button, { className: "zen-side-panel-filters__cancel-button", type: "secondary", onClick: handleCancelClick, children: translate("Cancel") }), _jsx(Button, { className: "zen-side-panel-filters__apply-button zen-side-panel-filters__apply-button--desktop", onClick: handleApplyClick, type: "primary", disabled: errorItems.size > 0, children: translate("Apply") })] })] }) })] }) }), (_a = document.fullscreenElement) !== null && _a !== void 0 ? _a : document.body), _jsx(FiltersSaveModal, { className: CUSTOM_POPUP_COMPONENT_CLASSNAME, isOpen: isSaveModalOpen, onClose: toggleSaveModal, onSave: handleSaveFilters })] });
|
|
208
|
+
};
|