@trackunit/filters-filter-bar 1.3.200 → 1.3.201
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/index.cjs.js +145 -80
- package/index.esm.js +144 -82
- package/package.json +7 -7
- package/src/lib/FilterBar.d.ts +5 -1
- package/src/lib/components/FilterButtonTooltipLabel.d.ts +7 -0
- package/src/lib/components/FiltersMenu.d.ts +15 -3
- package/src/lib/components/FiltersMenuContent.d.ts +17 -0
- package/src/lib/components/index.d.ts +2 -0
- package/src/lib/hooks/useFiltersMenu.d.ts +25 -0
- package/src/lib/index.d.ts +1 -0
package/index.cjs.js
CHANGED
|
@@ -645,6 +645,25 @@ const DefaultRadioFilter = ({ filterDefinition, filterBarActions, options, loadi
|
|
|
645
645
|
}, value: selectedRadioId?.key || "", children: jsxRuntime.jsx(DynamicFilterList, { checked: index => filterBarActions.objectIncludesValue(filterDefinition.filterKey, res[index]?.key || ""), className: "m-1 mt-0", count: index => res[index]?.count, keyMapper: index => res[index]?.key || "", labelMapper: index => res[index]?.label || "", rowCount: res.length, showRequestMoreUseSearch: showRequestMoreUseSearch, type: "Radio" }) })) })] }));
|
|
646
646
|
};
|
|
647
647
|
|
|
648
|
+
/**
|
|
649
|
+
* Tooltip label for the filter button
|
|
650
|
+
*/
|
|
651
|
+
const FilterButtonTooltipLabel = ({ filterBarConfig, }) => {
|
|
652
|
+
const [t] = useTranslation();
|
|
653
|
+
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
654
|
+
case 0:
|
|
655
|
+
return t("filtersBar.appliedFiltersTooltip.none");
|
|
656
|
+
case 1:
|
|
657
|
+
return filterBarConfig.appliedFilterKeys()[0]
|
|
658
|
+
? t("filtersBar.appliedFiltersTooltip.singular", {
|
|
659
|
+
filterName: filterBarConfig.getFilterTitle(filterBarConfig.appliedFilterKeys()[0]),
|
|
660
|
+
})
|
|
661
|
+
: null; // should never happen though
|
|
662
|
+
default:
|
|
663
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [t("filtersBar.appliedFiltersTooltip.plural", { count: filterBarConfig.appliedFilterKeys().length }), jsxRuntime.jsx("ul", { className: "list-inside", children: filterBarConfig.appliedFilterKeys().map((appliedFilterKey, index) => (jsxRuntime.jsx("li", { className: "list-disc", children: filterBarConfig.getFilterTitle(appliedFilterKey) }, index))) })] }));
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
648
667
|
/**
|
|
649
668
|
* Returns the two first values, appends counter if more.
|
|
650
669
|
*
|
|
@@ -760,6 +779,64 @@ const useGroupFilters = (filterDefinitions, hiddenFilters) => {
|
|
|
760
779
|
};
|
|
761
780
|
const uniqueKeysFromGroups = (filters) => [...new Set(filters.map(filter => filter.group))];
|
|
762
781
|
|
|
782
|
+
/**
|
|
783
|
+
* This hook is used to manage the filters menu.
|
|
784
|
+
* It returns the filters that should be shown in the menu, the filters that should be shown directly in the filter bar,
|
|
785
|
+
* and the filters that should be shown in the search results.
|
|
786
|
+
*/
|
|
787
|
+
const useFiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], allowShowFiltersDirectly = true, }) => {
|
|
788
|
+
const hideInMenu = react.useMemo(() => {
|
|
789
|
+
return sharedUtils.objectValues(filterBarDefinition)
|
|
790
|
+
.map(filter => {
|
|
791
|
+
const showInFilterBar = filter.showInFilterBar ? filter.showInFilterBar() : true;
|
|
792
|
+
const showInStarredMenu = filter.showInStarredMenu ? filter.showInStarredMenu() : true;
|
|
793
|
+
const showMenuAnywayBecauseFilterHasChanged = filterBarConfig.appliedFilterKeys().includes(filter.filterKey);
|
|
794
|
+
return (!showInFilterBar || !showInStarredMenu) && !showMenuAnywayBecauseFilterHasChanged
|
|
795
|
+
? filter.filterKey
|
|
796
|
+
: null;
|
|
797
|
+
})
|
|
798
|
+
.filter(sharedUtils.truthy);
|
|
799
|
+
}, [filterBarConfig, filterBarDefinition]);
|
|
800
|
+
const removeCustomFieldsGroup = react.useCallback((groupOfFilters) => groupOfFilters.filter(group => group.key !== "CUSTOM_FIELDS"), []);
|
|
801
|
+
const { filtersGrouped } = useGroupFilters(sharedUtils.objectValues(filterBarDefinition), [...hideInMenu, ...hiddenFilters]);
|
|
802
|
+
const { appliedFilters, filtersToShow, showDirectlyFilters, hasCustomFields } = react.useMemo(() => {
|
|
803
|
+
const allFilters = filtersGrouped.map(group => group.filters).flat();
|
|
804
|
+
return {
|
|
805
|
+
appliedFilters: allFilters.filter(filter => filterBarConfig.appliedFilterKeys().includes(filter.filterKey)),
|
|
806
|
+
filtersToShow: allFilters.filter(filter => !filter.showDirectly),
|
|
807
|
+
showDirectlyFilters: allFilters.filter(filter => filter.showDirectly && allowShowFiltersDirectly),
|
|
808
|
+
hasCustomFields: allFilters.some(filter => filter.group === "CUSTOM_FIELDS"),
|
|
809
|
+
};
|
|
810
|
+
}, [filterBarConfig, filtersGrouped, allowShowFiltersDirectly]);
|
|
811
|
+
const [searchResults, searchText, setSearchText] = reactCoreHooks.useTextSearch(filtersToShow, item => [item.title]);
|
|
812
|
+
const { filtersGrouped: searchResultsGrouped } = useGroupFilters(searchResults, []);
|
|
813
|
+
const { filtersGrouped: filtersToShowGrouped } = useGroupFilters(filtersToShow, []);
|
|
814
|
+
const appliedCustomFields = react.useMemo(() => appliedFilters.filter(filter => filter.group === "CUSTOM_FIELDS"), [appliedFilters]);
|
|
815
|
+
return react.useMemo(() => {
|
|
816
|
+
return {
|
|
817
|
+
appliedFilters,
|
|
818
|
+
hasCustomFields,
|
|
819
|
+
showDirectlyFilters,
|
|
820
|
+
appliedCustomFields,
|
|
821
|
+
searchText,
|
|
822
|
+
setSearchText,
|
|
823
|
+
filtersToShowGrouped,
|
|
824
|
+
searchResultsGrouped,
|
|
825
|
+
removeCustomFieldsGroup,
|
|
826
|
+
};
|
|
827
|
+
}, [
|
|
828
|
+
appliedFilters,
|
|
829
|
+
hasCustomFields,
|
|
830
|
+
showDirectlyFilters,
|
|
831
|
+
appliedCustomFields,
|
|
832
|
+
searchText,
|
|
833
|
+
setSearchText,
|
|
834
|
+
filtersToShowGrouped,
|
|
835
|
+
searchResultsGrouped,
|
|
836
|
+
removeCustomFieldsGroup,
|
|
837
|
+
]);
|
|
838
|
+
};
|
|
839
|
+
|
|
763
840
|
/**
|
|
764
841
|
* FiltersRenderer renders an array of Filter components from filter definitions
|
|
765
842
|
* It ignores hidden filters.
|
|
@@ -780,6 +857,60 @@ const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
|
|
|
780
857
|
.map(filter => (jsxRuntime.jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
|
|
781
858
|
};
|
|
782
859
|
|
|
860
|
+
/**
|
|
861
|
+
* FiltersList is a React component that displays a list of filters within a filter bar.
|
|
862
|
+
*
|
|
863
|
+
* @returns {ReactElement} - Returns the FiltersList component.
|
|
864
|
+
*/
|
|
865
|
+
const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTestId = "grouped-filters-list", }) => {
|
|
866
|
+
return (jsxRuntime.jsx("div", { className: className, "data-testid": dataTestId, role: "menu", children: filtersGrouped.map((group, idx) => {
|
|
867
|
+
const isLastGroup = idx === filtersGrouped.length - 1;
|
|
868
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-400 h-7 px-3 py-2", dataTestId: `${group.key}-group-title`, size: "small", uppercase: true, weight: "bold", children: group.title }), jsxRuntime.jsx("ul", { "aria-labelledby": `${group.key}-group-title`, className: "grid", "data-testid": `${group.key}-group-list`, children: jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: group.filters, visualStyle: "list-item" }) })] }), isLastGroup ? null : jsxRuntime.jsx("div", { className: "bg-secondary-200 h-[1px] w-full", role: "separator" })] }, group.key));
|
|
869
|
+
}) }));
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
874
|
+
*
|
|
875
|
+
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
876
|
+
*/
|
|
877
|
+
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
878
|
+
const [t] = useTranslation();
|
|
879
|
+
return (jsxRuntime.jsxs(reactComponents.Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
880
|
+
resetFiltersToInitialState();
|
|
881
|
+
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsxRuntime.jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
*
|
|
886
|
+
*/
|
|
887
|
+
const FiltersMenuContent = ({ filterBarConfig, setShowCustomFilters, setSearchText, searchText, searchResultsGrouped, filtersToShowGrouped, removeCustomFieldsGroup, hasCustomFields, appliedCustomFields, showCustomFilters, }) => {
|
|
888
|
+
const [t] = useTranslation();
|
|
889
|
+
return (jsxRuntime.jsxs(reactComponents.Card, { className: "max-h-[min(600px,_calc(100dvh-32px))] w-[300px] overflow-y-hidden", dataTestId: "starred-filters-menu-popover", children: [jsxRuntime.jsxs("div", { className: " flex-col gap-1 p-1", children: [jsxRuntime.jsx(reactFormComponents.Search, { autoFocus: true, dataTestId: "starred-filters-menu-search", fieldSize: "small", id: "search-filters-list", onChange: e => setSearchText(e.currentTarget.value), onClear: () => setSearchText(""), placeholder: t("filtersBar.searchFiltersPlaceholder"), value: searchText }), jsxRuntime.jsxs("div", { className: "flex h-7 items-center justify-between gap-1 px-3", children: [jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-400", size: "small", children: jsxRuntime.jsx(FiltersAppliedCountLabel, { filterBarConfig: filterBarConfig }) }), filterBarConfig.appliedFilterKeys().length > 0 ? (jsxRuntime.jsx(ResetFiltersButton, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] })] }), jsxRuntime.jsx(Separator, {}), jsxRuntime.jsxs(reactComponents.CardBody, { className: "gap-1 p-1", density: "none", disableGap: true, children: [jsxRuntime.jsx(GroupedFiltersList, { className: "flex flex-col gap-1", filterBarConfig: filterBarConfig, filtersGrouped: searchText
|
|
890
|
+
? searchResultsGrouped
|
|
891
|
+
: showCustomFilters
|
|
892
|
+
? filtersToShowGrouped
|
|
893
|
+
: removeCustomFieldsGroup(filtersToShowGrouped) }), hasCustomFields && !showCustomFilters && !searchText ? (jsxRuntime.jsx(CustomFieldsHiddenGroup, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, onShow: () => {
|
|
894
|
+
setShowCustomFilters(true);
|
|
895
|
+
} })) : null] })] }));
|
|
896
|
+
};
|
|
897
|
+
const Separator = () => jsxRuntime.jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
898
|
+
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
899
|
+
const [t] = useTranslation();
|
|
900
|
+
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
901
|
+
case 0:
|
|
902
|
+
return t("filtersBar.appliedFiltersTooltip.none");
|
|
903
|
+
case 1:
|
|
904
|
+
return filterBarConfig.appliedFilterKeys()[0] ? t("filtersMenu.appliedFiltersLabel.singular") : null;
|
|
905
|
+
default:
|
|
906
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: filterBarConfig.appliedFilterKeys().length }) });
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
910
|
+
const [t] = useTranslation();
|
|
911
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Separator, {}), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(reactComponents.Button, { "aria-controls": "filters-list", className: "text-primary-600 w-full justify-between px-3", onClick: onShow, prefix: jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-400", size: "small", uppercase: true, weight: "bold", children: t("filtersBar.groups.CUSTOM_FIELDS") }), size: "small", variant: "ghost-neutral", children: t("filtersBar.showAll") }), appliedCustomFields.length > 0 ? (jsxRuntime.jsx("ul", { "aria-label": "Visible custom fields", "data-testid": "applied-custom-fields-list", children: jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedCustomFields, visualStyle: "list-item" }) })) : null] })] }));
|
|
912
|
+
};
|
|
913
|
+
|
|
783
914
|
/**
|
|
784
915
|
* TooltipValues component that displays formatted tooltip values based on the provided input.
|
|
785
916
|
*
|
|
@@ -873,100 +1004,31 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, }) => {
|
|
|
873
1004
|
}
|
|
874
1005
|
};
|
|
875
1006
|
|
|
876
|
-
/**
|
|
877
|
-
* FiltersList is a React component that displays a list of filters within a filter bar.
|
|
878
|
-
*
|
|
879
|
-
* @returns {ReactElement} - Returns the FiltersList component.
|
|
880
|
-
*/
|
|
881
|
-
const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTestId = "grouped-filters-list", }) => {
|
|
882
|
-
return (jsxRuntime.jsx("div", { className: className, "data-testid": dataTestId, role: "menu", children: filtersGrouped.map((group, idx) => {
|
|
883
|
-
const isLastGroup = idx === filtersGrouped.length - 1;
|
|
884
|
-
return (jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-400 h-7 px-3 py-2", dataTestId: `${group.key}-group-title`, size: "small", uppercase: true, weight: "bold", children: group.title }), jsxRuntime.jsx("ul", { "aria-labelledby": `${group.key}-group-title`, className: "grid", "data-testid": `${group.key}-group-list`, children: jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: group.filters, visualStyle: "list-item" }) })] }), isLastGroup ? null : jsxRuntime.jsx("div", { className: "bg-secondary-200 h-[1px] w-full", role: "separator" })] }, group.key));
|
|
885
|
-
}) }));
|
|
886
|
-
};
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
890
|
-
*
|
|
891
|
-
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
892
|
-
*/
|
|
893
|
-
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
894
|
-
const [t] = useTranslation();
|
|
895
|
-
return (jsxRuntime.jsxs(reactComponents.Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
896
|
-
resetFiltersToInitialState();
|
|
897
|
-
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsxRuntime.jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
898
|
-
};
|
|
899
|
-
|
|
900
1007
|
/**
|
|
901
1008
|
* FilterMenu is a React component that displays a list of filters in a popover menu based on the provided filter bar configuration.
|
|
902
1009
|
*
|
|
903
1010
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
904
1011
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
905
1012
|
*/
|
|
906
|
-
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className, }) => {
|
|
1013
|
+
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className, showAppliedFiltersCount = true, buttonProps, allowShowFiltersDirectly = true, }) => {
|
|
907
1014
|
const [t] = useTranslation();
|
|
908
1015
|
const { isSm } = reactComponents.useViewportBreakpoints();
|
|
909
1016
|
const [showCustomFilters, setShowCustomFilters] = react.useState(false);
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
const showInStarredMenu = filter.showInStarredMenu ? filter.showInStarredMenu() : true; // TODO: Starred menu concept should be completely removed everywhere
|
|
917
|
-
const showMenuAnywayBecauseFilterHasChanged = filterBarConfig.appliedFilterKeys().includes(filter.filterKey);
|
|
918
|
-
return (!showInFilterBar || !showInStarredMenu) && !showMenuAnywayBecauseFilterHasChanged
|
|
919
|
-
? filter.filterKey
|
|
920
|
-
: null;
|
|
921
|
-
})
|
|
922
|
-
.filter(sharedUtils.truthy);
|
|
923
|
-
}, [filterBarConfig, filterBarDefinition]);
|
|
924
|
-
const { filtersGrouped } = useGroupFilters(sharedUtils.objectValues(filterBarDefinition), [...hideInMenu, ...hiddenFilters]);
|
|
925
|
-
const { appliedFilters, filtersToShow, showDirectlyFilters, hasCustomFields } = react.useMemo(() => {
|
|
926
|
-
const allFilters = filtersGrouped.map(group => group.filters).flat();
|
|
927
|
-
return {
|
|
928
|
-
appliedFilters: allFilters.filter(filter => filterBarConfig.appliedFilterKeys().includes(filter.filterKey)),
|
|
929
|
-
filtersToShow: allFilters.filter(filter => !filter.showDirectly),
|
|
930
|
-
showDirectlyFilters: allFilters.filter(filter => filter.showDirectly),
|
|
931
|
-
hasCustomFields: allFilters.some(filter => filter.group === "CUSTOM_FIELDS"),
|
|
932
|
-
};
|
|
933
|
-
}, [filterBarConfig, filtersGrouped]);
|
|
934
|
-
const [searchResults, searchText, setSearchText] = reactCoreHooks.useTextSearch(filtersToShow, item => [item.title]);
|
|
935
|
-
const { filtersGrouped: searchResultsGrouped } = useGroupFilters(searchResults, []);
|
|
936
|
-
const { filtersGrouped: filtersToShowGrouped } = useGroupFilters(filtersToShow, []);
|
|
937
|
-
const appliedCustomFields = react.useMemo(() => appliedFilters.filter(filter => filter.group === "CUSTOM_FIELDS"), [appliedFilters]);
|
|
1017
|
+
const { appliedFilters, showDirectlyFilters, hasCustomFields, filtersToShowGrouped, searchResultsGrouped, searchText, appliedCustomFields, removeCustomFieldsGroup, setSearchText, } = useFiltersMenu({
|
|
1018
|
+
filterBarDefinition,
|
|
1019
|
+
filterBarConfig,
|
|
1020
|
+
hiddenFilters,
|
|
1021
|
+
allowShowFiltersDirectly,
|
|
1022
|
+
});
|
|
938
1023
|
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex items-center gap-2", className), "data-testid": dataTestId, children: [jsxRuntime.jsx(reactComponents.Popover, { onOpenStateChange: open => {
|
|
939
1024
|
if (!open) {
|
|
940
1025
|
setShowCustomFilters(false);
|
|
941
1026
|
setSearchText("");
|
|
942
1027
|
}
|
|
943
1028
|
}, placement: "bottom-start", children: modalState => {
|
|
944
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: !compact || modalState.isOpen, label: jsxRuntime.jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig }), children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && filterBarConfig.appliedFilterKeys().length > 0 && isSm ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxRuntime.jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", children: jsxRuntime.jsx("span", { className: "hidden sm:block", children: title ?? t("filtersBar.filtersHeading") }) }) }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { cellPadding: 100, children: jsxRuntime.
|
|
945
|
-
? searchResultsGrouped
|
|
946
|
-
: showCustomFilters
|
|
947
|
-
? filtersToShowGrouped
|
|
948
|
-
: removeCustomFields(filtersToShowGrouped) }), hasCustomFields && !showCustomFilters && !searchText ? (jsxRuntime.jsx(CustomFieldsHiddenGroup, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, onShow: () => {
|
|
949
|
-
setShowCustomFilters(true);
|
|
950
|
-
} })) : null] })] }) })] }));
|
|
1029
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: !compact || modalState.isOpen, label: jsxRuntime.jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig }), children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && showAppliedFiltersCount && filterBarConfig.appliedFilterKeys().length > 0 && isSm ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxRuntime.jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", ...buttonProps, children: title !== "" ? (jsxRuntime.jsx("span", { className: "hidden sm:block", children: title ?? t("filtersBar.filtersHeading") })) : null }) }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { cellPadding: 100, children: jsxRuntime.jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
951
1030
|
} }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [appliedFilters.filter(filter => !filter.showDirectly).length > 0 ? (jsxRuntime.jsx("div", { className: "h-4 w-[1px] bg-slate-300", "data-testid": "applied-filters-buttons" })) : null, jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedFilters }), filterBarConfig.appliedFilterKeys().length > 0 ? (jsxRuntime.jsx(ResetFiltersButton, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] })) : null] }));
|
|
952
1031
|
};
|
|
953
|
-
const Separator = () => jsxRuntime.jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
954
|
-
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
955
|
-
const [t] = useTranslation();
|
|
956
|
-
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
957
|
-
case 0:
|
|
958
|
-
return t("filtersBar.appliedFiltersTooltip.none");
|
|
959
|
-
case 1:
|
|
960
|
-
return filterBarConfig.appliedFilterKeys()[0] ? t("filtersMenu.appliedFiltersLabel.singular") : null;
|
|
961
|
-
default:
|
|
962
|
-
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: filterBarConfig.appliedFilterKeys().length }) });
|
|
963
|
-
}
|
|
964
|
-
};
|
|
965
|
-
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
966
|
-
const [t] = useTranslation();
|
|
967
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Separator, {}), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(reactComponents.Button, { "aria-controls": "filters-list", className: "text-primary-600 w-full justify-between px-3", onClick: onShow, prefix: jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-400", size: "small", uppercase: true, weight: "bold", children: t("filtersBar.groups.CUSTOM_FIELDS") }), size: "small", variant: "ghost-neutral", children: t("filtersBar.showAll") }), appliedCustomFields.length > 0 ? (jsxRuntime.jsx("ul", { "aria-label": "Visible custom fields", "data-testid": "applied-custom-fields-list", children: jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedCustomFields, visualStyle: "list-item" }) })) : null] })] }));
|
|
968
|
-
};
|
|
969
|
-
const removeCustomFields = (filtersGrouped) => filtersGrouped.filter(group => group.key !== "CUSTOM_FIELDS");
|
|
970
1032
|
|
|
971
1033
|
/**
|
|
972
1034
|
* Filter is a React component that renders a filter element based on the provided filter definition and state.
|
|
@@ -1225,8 +1287,8 @@ const HierarchicalCheckboxFilter = ({ filterDefinition, filterBarActions, option
|
|
|
1225
1287
|
/**
|
|
1226
1288
|
* The FilterBar component serves as a wrapper for managing filters.
|
|
1227
1289
|
*/
|
|
1228
|
-
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, title, }) => {
|
|
1229
|
-
return (jsxRuntime.jsx(FiltersMenu, { className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
|
|
1290
|
+
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, title, allowShowFiltersDirectly = true, }) => {
|
|
1291
|
+
return (jsxRuntime.jsx(FiltersMenu, { allowShowFiltersDirectly: allowShowFiltersDirectly, className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
|
|
1230
1292
|
};
|
|
1231
1293
|
|
|
1232
1294
|
// Can't import jest.fn so must define a function that does nothing but mimics the jest.fn
|
|
@@ -1888,8 +1950,8 @@ const useFilterBar = ({ name, onValuesChange, filterBarDefinition, }) => {
|
|
|
1888
1950
|
setValue: (key, callback) => setValue(setFilterBarConfig, key, callback),
|
|
1889
1951
|
});
|
|
1890
1952
|
react.useEffect(() => {
|
|
1891
|
-
onValuesChange?.(filterBarConfig.values);
|
|
1892
1953
|
saveData(filterBarConfig, filterBarDefinition);
|
|
1954
|
+
onValuesChange?.(filterBarConfig.values);
|
|
1893
1955
|
}, [filterBarConfig, filterBarDefinition, onValuesChange, saveData]);
|
|
1894
1956
|
return react.useMemo(() => {
|
|
1895
1957
|
return {
|
|
@@ -2048,12 +2110,14 @@ exports.DefaultMinMaxFilter = DefaultMinMaxFilter;
|
|
|
2048
2110
|
exports.DefaultRadioFilter = DefaultRadioFilter;
|
|
2049
2111
|
exports.DynamicFilterList = DynamicFilterList;
|
|
2050
2112
|
exports.FilterBar = FilterBar;
|
|
2113
|
+
exports.FilterButtonTooltipLabel = FilterButtonTooltipLabel;
|
|
2051
2114
|
exports.FilterComponent = FilterComponent;
|
|
2052
2115
|
exports.FilterEvents = FilterEvents;
|
|
2053
2116
|
exports.FilterHeader = FilterHeader;
|
|
2054
2117
|
exports.FilterResults = FilterResults;
|
|
2055
2118
|
exports.FilterTableComponent = FilterTableComponent;
|
|
2056
2119
|
exports.FiltersMenu = FiltersMenu;
|
|
2120
|
+
exports.FiltersMenuContent = FiltersMenuContent;
|
|
2057
2121
|
exports.FiltersRenderer = FiltersRenderer;
|
|
2058
2122
|
exports.GroupedFiltersList = GroupedFiltersList;
|
|
2059
2123
|
exports.HierarchicalCheckboxFilter = HierarchicalCheckboxFilter;
|
|
@@ -2072,5 +2136,6 @@ exports.mockFilterBar = mockFilterBar;
|
|
|
2072
2136
|
exports.toggleFilterValue = toggleFilterValue;
|
|
2073
2137
|
exports.useFilterBar = useFilterBar;
|
|
2074
2138
|
exports.useFilterBarAsync = useFilterBarAsync;
|
|
2139
|
+
exports.useFiltersMenu = useFiltersMenu;
|
|
2075
2140
|
exports.useSearchParamAsFilter = useSearchParamAsFilter;
|
|
2076
2141
|
exports.validateFilter = validateFilter;
|
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
|
|
3
|
-
import { VirtualizedList, Text, Button, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip, Icon, PopoverContent,
|
|
3
|
+
import { VirtualizedList, Text, Button, Card, CardBody, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip, Icon, PopoverContent, IconButton, MenuList } from '@trackunit/react-components';
|
|
4
4
|
import { useAnalytics, useTextSearch, useCurrentUser } from '@trackunit/react-core-hooks';
|
|
5
5
|
import { FilterBody, RadioFilterItem, CheckBoxFilterItem, FilterHeader as FilterHeader$1, FilterFooter, Filter } from '@trackunit/react-filter-components';
|
|
6
6
|
import { useRef, useMemo, useState, useEffect, useCallback, Fragment as Fragment$1 } from 'react';
|
|
@@ -643,6 +643,25 @@ const DefaultRadioFilter = ({ filterDefinition, filterBarActions, options, loadi
|
|
|
643
643
|
}, value: selectedRadioId?.key || "", children: jsx(DynamicFilterList, { checked: index => filterBarActions.objectIncludesValue(filterDefinition.filterKey, res[index]?.key || ""), className: "m-1 mt-0", count: index => res[index]?.count, keyMapper: index => res[index]?.key || "", labelMapper: index => res[index]?.label || "", rowCount: res.length, showRequestMoreUseSearch: showRequestMoreUseSearch, type: "Radio" }) })) })] }));
|
|
644
644
|
};
|
|
645
645
|
|
|
646
|
+
/**
|
|
647
|
+
* Tooltip label for the filter button
|
|
648
|
+
*/
|
|
649
|
+
const FilterButtonTooltipLabel = ({ filterBarConfig, }) => {
|
|
650
|
+
const [t] = useTranslation();
|
|
651
|
+
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
652
|
+
case 0:
|
|
653
|
+
return t("filtersBar.appliedFiltersTooltip.none");
|
|
654
|
+
case 1:
|
|
655
|
+
return filterBarConfig.appliedFilterKeys()[0]
|
|
656
|
+
? t("filtersBar.appliedFiltersTooltip.singular", {
|
|
657
|
+
filterName: filterBarConfig.getFilterTitle(filterBarConfig.appliedFilterKeys()[0]),
|
|
658
|
+
})
|
|
659
|
+
: null; // should never happen though
|
|
660
|
+
default:
|
|
661
|
+
return (jsxs(Fragment, { children: [t("filtersBar.appliedFiltersTooltip.plural", { count: filterBarConfig.appliedFilterKeys().length }), jsx("ul", { className: "list-inside", children: filterBarConfig.appliedFilterKeys().map((appliedFilterKey, index) => (jsx("li", { className: "list-disc", children: filterBarConfig.getFilterTitle(appliedFilterKey) }, index))) })] }));
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
646
665
|
/**
|
|
647
666
|
* Returns the two first values, appends counter if more.
|
|
648
667
|
*
|
|
@@ -758,6 +777,64 @@ const useGroupFilters = (filterDefinitions, hiddenFilters) => {
|
|
|
758
777
|
};
|
|
759
778
|
const uniqueKeysFromGroups = (filters) => [...new Set(filters.map(filter => filter.group))];
|
|
760
779
|
|
|
780
|
+
/**
|
|
781
|
+
* This hook is used to manage the filters menu.
|
|
782
|
+
* It returns the filters that should be shown in the menu, the filters that should be shown directly in the filter bar,
|
|
783
|
+
* and the filters that should be shown in the search results.
|
|
784
|
+
*/
|
|
785
|
+
const useFiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], allowShowFiltersDirectly = true, }) => {
|
|
786
|
+
const hideInMenu = useMemo(() => {
|
|
787
|
+
return objectValues(filterBarDefinition)
|
|
788
|
+
.map(filter => {
|
|
789
|
+
const showInFilterBar = filter.showInFilterBar ? filter.showInFilterBar() : true;
|
|
790
|
+
const showInStarredMenu = filter.showInStarredMenu ? filter.showInStarredMenu() : true;
|
|
791
|
+
const showMenuAnywayBecauseFilterHasChanged = filterBarConfig.appliedFilterKeys().includes(filter.filterKey);
|
|
792
|
+
return (!showInFilterBar || !showInStarredMenu) && !showMenuAnywayBecauseFilterHasChanged
|
|
793
|
+
? filter.filterKey
|
|
794
|
+
: null;
|
|
795
|
+
})
|
|
796
|
+
.filter(truthy);
|
|
797
|
+
}, [filterBarConfig, filterBarDefinition]);
|
|
798
|
+
const removeCustomFieldsGroup = useCallback((groupOfFilters) => groupOfFilters.filter(group => group.key !== "CUSTOM_FIELDS"), []);
|
|
799
|
+
const { filtersGrouped } = useGroupFilters(objectValues(filterBarDefinition), [...hideInMenu, ...hiddenFilters]);
|
|
800
|
+
const { appliedFilters, filtersToShow, showDirectlyFilters, hasCustomFields } = useMemo(() => {
|
|
801
|
+
const allFilters = filtersGrouped.map(group => group.filters).flat();
|
|
802
|
+
return {
|
|
803
|
+
appliedFilters: allFilters.filter(filter => filterBarConfig.appliedFilterKeys().includes(filter.filterKey)),
|
|
804
|
+
filtersToShow: allFilters.filter(filter => !filter.showDirectly),
|
|
805
|
+
showDirectlyFilters: allFilters.filter(filter => filter.showDirectly && allowShowFiltersDirectly),
|
|
806
|
+
hasCustomFields: allFilters.some(filter => filter.group === "CUSTOM_FIELDS"),
|
|
807
|
+
};
|
|
808
|
+
}, [filterBarConfig, filtersGrouped, allowShowFiltersDirectly]);
|
|
809
|
+
const [searchResults, searchText, setSearchText] = useTextSearch(filtersToShow, item => [item.title]);
|
|
810
|
+
const { filtersGrouped: searchResultsGrouped } = useGroupFilters(searchResults, []);
|
|
811
|
+
const { filtersGrouped: filtersToShowGrouped } = useGroupFilters(filtersToShow, []);
|
|
812
|
+
const appliedCustomFields = useMemo(() => appliedFilters.filter(filter => filter.group === "CUSTOM_FIELDS"), [appliedFilters]);
|
|
813
|
+
return useMemo(() => {
|
|
814
|
+
return {
|
|
815
|
+
appliedFilters,
|
|
816
|
+
hasCustomFields,
|
|
817
|
+
showDirectlyFilters,
|
|
818
|
+
appliedCustomFields,
|
|
819
|
+
searchText,
|
|
820
|
+
setSearchText,
|
|
821
|
+
filtersToShowGrouped,
|
|
822
|
+
searchResultsGrouped,
|
|
823
|
+
removeCustomFieldsGroup,
|
|
824
|
+
};
|
|
825
|
+
}, [
|
|
826
|
+
appliedFilters,
|
|
827
|
+
hasCustomFields,
|
|
828
|
+
showDirectlyFilters,
|
|
829
|
+
appliedCustomFields,
|
|
830
|
+
searchText,
|
|
831
|
+
setSearchText,
|
|
832
|
+
filtersToShowGrouped,
|
|
833
|
+
searchResultsGrouped,
|
|
834
|
+
removeCustomFieldsGroup,
|
|
835
|
+
]);
|
|
836
|
+
};
|
|
837
|
+
|
|
761
838
|
/**
|
|
762
839
|
* FiltersRenderer renders an array of Filter components from filter definitions
|
|
763
840
|
* It ignores hidden filters.
|
|
@@ -778,6 +855,60 @@ const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
|
|
|
778
855
|
.map(filter => (jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
|
|
779
856
|
};
|
|
780
857
|
|
|
858
|
+
/**
|
|
859
|
+
* FiltersList is a React component that displays a list of filters within a filter bar.
|
|
860
|
+
*
|
|
861
|
+
* @returns {ReactElement} - Returns the FiltersList component.
|
|
862
|
+
*/
|
|
863
|
+
const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTestId = "grouped-filters-list", }) => {
|
|
864
|
+
return (jsx("div", { className: className, "data-testid": dataTestId, role: "menu", children: filtersGrouped.map((group, idx) => {
|
|
865
|
+
const isLastGroup = idx === filtersGrouped.length - 1;
|
|
866
|
+
return (jsxs("div", { className: "flex flex-col gap-1", children: [jsxs("div", { children: [jsx(Text, { className: "text-secondary-400 h-7 px-3 py-2", dataTestId: `${group.key}-group-title`, size: "small", uppercase: true, weight: "bold", children: group.title }), jsx("ul", { "aria-labelledby": `${group.key}-group-title`, className: "grid", "data-testid": `${group.key}-group-list`, children: jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: group.filters, visualStyle: "list-item" }) })] }), isLastGroup ? null : jsx("div", { className: "bg-secondary-200 h-[1px] w-full", role: "separator" })] }, group.key));
|
|
867
|
+
}) }));
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
872
|
+
*
|
|
873
|
+
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
874
|
+
*/
|
|
875
|
+
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
876
|
+
const [t] = useTranslation();
|
|
877
|
+
return (jsxs(Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
878
|
+
resetFiltersToInitialState();
|
|
879
|
+
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
*
|
|
884
|
+
*/
|
|
885
|
+
const FiltersMenuContent = ({ filterBarConfig, setShowCustomFilters, setSearchText, searchText, searchResultsGrouped, filtersToShowGrouped, removeCustomFieldsGroup, hasCustomFields, appliedCustomFields, showCustomFilters, }) => {
|
|
886
|
+
const [t] = useTranslation();
|
|
887
|
+
return (jsxs(Card, { className: "max-h-[min(600px,_calc(100dvh-32px))] w-[300px] overflow-y-hidden", dataTestId: "starred-filters-menu-popover", children: [jsxs("div", { className: " flex-col gap-1 p-1", children: [jsx(Search, { autoFocus: true, dataTestId: "starred-filters-menu-search", fieldSize: "small", id: "search-filters-list", onChange: e => setSearchText(e.currentTarget.value), onClear: () => setSearchText(""), placeholder: t("filtersBar.searchFiltersPlaceholder"), value: searchText }), jsxs("div", { className: "flex h-7 items-center justify-between gap-1 px-3", children: [jsx(Text, { className: "text-secondary-400", size: "small", children: jsx(FiltersAppliedCountLabel, { filterBarConfig: filterBarConfig }) }), filterBarConfig.appliedFilterKeys().length > 0 ? (jsx(ResetFiltersButton, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] })] }), jsx(Separator, {}), jsxs(CardBody, { className: "gap-1 p-1", density: "none", disableGap: true, children: [jsx(GroupedFiltersList, { className: "flex flex-col gap-1", filterBarConfig: filterBarConfig, filtersGrouped: searchText
|
|
888
|
+
? searchResultsGrouped
|
|
889
|
+
: showCustomFilters
|
|
890
|
+
? filtersToShowGrouped
|
|
891
|
+
: removeCustomFieldsGroup(filtersToShowGrouped) }), hasCustomFields && !showCustomFilters && !searchText ? (jsx(CustomFieldsHiddenGroup, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, onShow: () => {
|
|
892
|
+
setShowCustomFilters(true);
|
|
893
|
+
} })) : null] })] }));
|
|
894
|
+
};
|
|
895
|
+
const Separator = () => jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
896
|
+
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
897
|
+
const [t] = useTranslation();
|
|
898
|
+
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
899
|
+
case 0:
|
|
900
|
+
return t("filtersBar.appliedFiltersTooltip.none");
|
|
901
|
+
case 1:
|
|
902
|
+
return filterBarConfig.appliedFilterKeys()[0] ? t("filtersMenu.appliedFiltersLabel.singular") : null;
|
|
903
|
+
default:
|
|
904
|
+
return jsx(Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: filterBarConfig.appliedFilterKeys().length }) });
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
908
|
+
const [t] = useTranslation();
|
|
909
|
+
return (jsxs(Fragment, { children: [jsx(Separator, {}), jsxs("div", { children: [jsx(Button, { "aria-controls": "filters-list", className: "text-primary-600 w-full justify-between px-3", onClick: onShow, prefix: jsx(Text, { className: "text-secondary-400", size: "small", uppercase: true, weight: "bold", children: t("filtersBar.groups.CUSTOM_FIELDS") }), size: "small", variant: "ghost-neutral", children: t("filtersBar.showAll") }), appliedCustomFields.length > 0 ? (jsx("ul", { "aria-label": "Visible custom fields", "data-testid": "applied-custom-fields-list", children: jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedCustomFields, visualStyle: "list-item" }) })) : null] })] }));
|
|
910
|
+
};
|
|
911
|
+
|
|
781
912
|
/**
|
|
782
913
|
* TooltipValues component that displays formatted tooltip values based on the provided input.
|
|
783
914
|
*
|
|
@@ -871,100 +1002,31 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, }) => {
|
|
|
871
1002
|
}
|
|
872
1003
|
};
|
|
873
1004
|
|
|
874
|
-
/**
|
|
875
|
-
* FiltersList is a React component that displays a list of filters within a filter bar.
|
|
876
|
-
*
|
|
877
|
-
* @returns {ReactElement} - Returns the FiltersList component.
|
|
878
|
-
*/
|
|
879
|
-
const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTestId = "grouped-filters-list", }) => {
|
|
880
|
-
return (jsx("div", { className: className, "data-testid": dataTestId, role: "menu", children: filtersGrouped.map((group, idx) => {
|
|
881
|
-
const isLastGroup = idx === filtersGrouped.length - 1;
|
|
882
|
-
return (jsxs("div", { className: "flex flex-col gap-1", children: [jsxs("div", { children: [jsx(Text, { className: "text-secondary-400 h-7 px-3 py-2", dataTestId: `${group.key}-group-title`, size: "small", uppercase: true, weight: "bold", children: group.title }), jsx("ul", { "aria-labelledby": `${group.key}-group-title`, className: "grid", "data-testid": `${group.key}-group-list`, children: jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: group.filters, visualStyle: "list-item" }) })] }), isLastGroup ? null : jsx("div", { className: "bg-secondary-200 h-[1px] w-full", role: "separator" })] }, group.key));
|
|
883
|
-
}) }));
|
|
884
|
-
};
|
|
885
|
-
|
|
886
|
-
/**
|
|
887
|
-
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
888
|
-
*
|
|
889
|
-
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
890
|
-
*/
|
|
891
|
-
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
892
|
-
const [t] = useTranslation();
|
|
893
|
-
return (jsxs(Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
894
|
-
resetFiltersToInitialState();
|
|
895
|
-
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
896
|
-
};
|
|
897
|
-
|
|
898
1005
|
/**
|
|
899
1006
|
* FilterMenu is a React component that displays a list of filters in a popover menu based on the provided filter bar configuration.
|
|
900
1007
|
*
|
|
901
1008
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
902
1009
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
903
1010
|
*/
|
|
904
|
-
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className, }) => {
|
|
1011
|
+
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className, showAppliedFiltersCount = true, buttonProps, allowShowFiltersDirectly = true, }) => {
|
|
905
1012
|
const [t] = useTranslation();
|
|
906
1013
|
const { isSm } = useViewportBreakpoints();
|
|
907
1014
|
const [showCustomFilters, setShowCustomFilters] = useState(false);
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const showInStarredMenu = filter.showInStarredMenu ? filter.showInStarredMenu() : true; // TODO: Starred menu concept should be completely removed everywhere
|
|
915
|
-
const showMenuAnywayBecauseFilterHasChanged = filterBarConfig.appliedFilterKeys().includes(filter.filterKey);
|
|
916
|
-
return (!showInFilterBar || !showInStarredMenu) && !showMenuAnywayBecauseFilterHasChanged
|
|
917
|
-
? filter.filterKey
|
|
918
|
-
: null;
|
|
919
|
-
})
|
|
920
|
-
.filter(truthy);
|
|
921
|
-
}, [filterBarConfig, filterBarDefinition]);
|
|
922
|
-
const { filtersGrouped } = useGroupFilters(objectValues(filterBarDefinition), [...hideInMenu, ...hiddenFilters]);
|
|
923
|
-
const { appliedFilters, filtersToShow, showDirectlyFilters, hasCustomFields } = useMemo(() => {
|
|
924
|
-
const allFilters = filtersGrouped.map(group => group.filters).flat();
|
|
925
|
-
return {
|
|
926
|
-
appliedFilters: allFilters.filter(filter => filterBarConfig.appliedFilterKeys().includes(filter.filterKey)),
|
|
927
|
-
filtersToShow: allFilters.filter(filter => !filter.showDirectly),
|
|
928
|
-
showDirectlyFilters: allFilters.filter(filter => filter.showDirectly),
|
|
929
|
-
hasCustomFields: allFilters.some(filter => filter.group === "CUSTOM_FIELDS"),
|
|
930
|
-
};
|
|
931
|
-
}, [filterBarConfig, filtersGrouped]);
|
|
932
|
-
const [searchResults, searchText, setSearchText] = useTextSearch(filtersToShow, item => [item.title]);
|
|
933
|
-
const { filtersGrouped: searchResultsGrouped } = useGroupFilters(searchResults, []);
|
|
934
|
-
const { filtersGrouped: filtersToShowGrouped } = useGroupFilters(filtersToShow, []);
|
|
935
|
-
const appliedCustomFields = useMemo(() => appliedFilters.filter(filter => filter.group === "CUSTOM_FIELDS"), [appliedFilters]);
|
|
1015
|
+
const { appliedFilters, showDirectlyFilters, hasCustomFields, filtersToShowGrouped, searchResultsGrouped, searchText, appliedCustomFields, removeCustomFieldsGroup, setSearchText, } = useFiltersMenu({
|
|
1016
|
+
filterBarDefinition,
|
|
1017
|
+
filterBarConfig,
|
|
1018
|
+
hiddenFilters,
|
|
1019
|
+
allowShowFiltersDirectly,
|
|
1020
|
+
});
|
|
936
1021
|
return (jsxs("div", { className: twMerge("flex items-center gap-2", className), "data-testid": dataTestId, children: [jsx(Popover, { onOpenStateChange: open => {
|
|
937
1022
|
if (!open) {
|
|
938
1023
|
setShowCustomFilters(false);
|
|
939
1024
|
setSearchText("");
|
|
940
1025
|
}
|
|
941
1026
|
}, placement: "bottom-start", children: modalState => {
|
|
942
|
-
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled: !compact || modalState.isOpen, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig }), children: jsx(Button, { prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && filterBarConfig.appliedFilterKeys().length > 0 && isSm ? (jsxs("div", { children: [jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", children: jsx("span", { className: "hidden sm:block", children: title ?? t("filtersBar.filtersHeading") }) }) }) }) }), jsx(PopoverContent, { cellPadding: 100, children:
|
|
943
|
-
? searchResultsGrouped
|
|
944
|
-
: showCustomFilters
|
|
945
|
-
? filtersToShowGrouped
|
|
946
|
-
: removeCustomFields(filtersToShowGrouped) }), hasCustomFields && !showCustomFilters && !searchText ? (jsx(CustomFieldsHiddenGroup, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, onShow: () => {
|
|
947
|
-
setShowCustomFilters(true);
|
|
948
|
-
} })) : null] })] }) })] }));
|
|
1027
|
+
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled: !compact || modalState.isOpen, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig }), children: jsx(Button, { prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && showAppliedFiltersCount && filterBarConfig.appliedFilterKeys().length > 0 && isSm ? (jsxs("div", { children: [jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", ...buttonProps, children: title !== "" ? (jsx("span", { className: "hidden sm:block", children: title ?? t("filtersBar.filtersHeading") })) : null }) }) }) }), jsx(PopoverContent, { cellPadding: 100, children: jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
949
1028
|
} }), showDirectlyFilters.length > 0 ? (jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ? (jsxs(Fragment, { children: [appliedFilters.filter(filter => !filter.showDirectly).length > 0 ? (jsx("div", { className: "h-4 w-[1px] bg-slate-300", "data-testid": "applied-filters-buttons" })) : null, jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedFilters }), filterBarConfig.appliedFilterKeys().length > 0 ? (jsx(ResetFiltersButton, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] })) : null] }));
|
|
950
1029
|
};
|
|
951
|
-
const Separator = () => jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
952
|
-
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
953
|
-
const [t] = useTranslation();
|
|
954
|
-
switch (filterBarConfig.appliedFilterKeys().length) {
|
|
955
|
-
case 0:
|
|
956
|
-
return t("filtersBar.appliedFiltersTooltip.none");
|
|
957
|
-
case 1:
|
|
958
|
-
return filterBarConfig.appliedFilterKeys()[0] ? t("filtersMenu.appliedFiltersLabel.singular") : null;
|
|
959
|
-
default:
|
|
960
|
-
return jsx(Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: filterBarConfig.appliedFilterKeys().length }) });
|
|
961
|
-
}
|
|
962
|
-
};
|
|
963
|
-
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
964
|
-
const [t] = useTranslation();
|
|
965
|
-
return (jsxs(Fragment, { children: [jsx(Separator, {}), jsxs("div", { children: [jsx(Button, { "aria-controls": "filters-list", className: "text-primary-600 w-full justify-between px-3", onClick: onShow, prefix: jsx(Text, { className: "text-secondary-400", size: "small", uppercase: true, weight: "bold", children: t("filtersBar.groups.CUSTOM_FIELDS") }), size: "small", variant: "ghost-neutral", children: t("filtersBar.showAll") }), appliedCustomFields.length > 0 ? (jsx("ul", { "aria-label": "Visible custom fields", "data-testid": "applied-custom-fields-list", children: jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedCustomFields, visualStyle: "list-item" }) })) : null] })] }));
|
|
966
|
-
};
|
|
967
|
-
const removeCustomFields = (filtersGrouped) => filtersGrouped.filter(group => group.key !== "CUSTOM_FIELDS");
|
|
968
1030
|
|
|
969
1031
|
/**
|
|
970
1032
|
* Filter is a React component that renders a filter element based on the provided filter definition and state.
|
|
@@ -1223,8 +1285,8 @@ const HierarchicalCheckboxFilter = ({ filterDefinition, filterBarActions, option
|
|
|
1223
1285
|
/**
|
|
1224
1286
|
* The FilterBar component serves as a wrapper for managing filters.
|
|
1225
1287
|
*/
|
|
1226
|
-
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, title, }) => {
|
|
1227
|
-
return (jsx(FiltersMenu, { className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
|
|
1288
|
+
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, title, allowShowFiltersDirectly = true, }) => {
|
|
1289
|
+
return (jsx(FiltersMenu, { allowShowFiltersDirectly: allowShowFiltersDirectly, className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
|
|
1228
1290
|
};
|
|
1229
1291
|
|
|
1230
1292
|
// Can't import jest.fn so must define a function that does nothing but mimics the jest.fn
|
|
@@ -1886,8 +1948,8 @@ const useFilterBar = ({ name, onValuesChange, filterBarDefinition, }) => {
|
|
|
1886
1948
|
setValue: (key, callback) => setValue(setFilterBarConfig, key, callback),
|
|
1887
1949
|
});
|
|
1888
1950
|
useEffect(() => {
|
|
1889
|
-
onValuesChange?.(filterBarConfig.values);
|
|
1890
1951
|
saveData(filterBarConfig, filterBarDefinition);
|
|
1952
|
+
onValuesChange?.(filterBarConfig.values);
|
|
1891
1953
|
}, [filterBarConfig, filterBarDefinition, onValuesChange, saveData]);
|
|
1892
1954
|
return useMemo(() => {
|
|
1893
1955
|
return {
|
|
@@ -2040,4 +2102,4 @@ const mergeFilters = (filterBarDefinition, extraFilters) => {
|
|
|
2040
2102
|
*/
|
|
2041
2103
|
setupLibraryTranslations();
|
|
2042
2104
|
|
|
2043
|
-
export { DefaultCheckboxFilter, DefaultDateRangeFilter, DefaultMinMaxFilter, DefaultRadioFilter, DynamicFilterList, FilterBar, FilterComponent, FilterEvents, FilterHeader, FilterResults, FilterTableComponent, FiltersMenu, FiltersRenderer, GroupedFiltersList, HierarchicalCheckboxFilter, ResetFiltersButton, areaFilterGeoJsonGeometrySchema, isAreaFilterValue, isArrayFilterValue, isBooleanValue, isDateRangeValue, isMinMaxFilterValue, isStringArrayFilterValue, isValueName, isValueNameArray, mergeFilters, mockFilterBar, toggleFilterValue, useFilterBar, useFilterBarAsync, useSearchParamAsFilter, validateFilter };
|
|
2105
|
+
export { DefaultCheckboxFilter, DefaultDateRangeFilter, DefaultMinMaxFilter, DefaultRadioFilter, DynamicFilterList, FilterBar, FilterButtonTooltipLabel, FilterComponent, FilterEvents, FilterHeader, FilterResults, FilterTableComponent, FiltersMenu, FiltersMenuContent, FiltersRenderer, GroupedFiltersList, HierarchicalCheckboxFilter, ResetFiltersButton, areaFilterGeoJsonGeometrySchema, isAreaFilterValue, isArrayFilterValue, isBooleanValue, isDateRangeValue, isMinMaxFilterValue, isStringArrayFilterValue, isValueName, isValueNameArray, mergeFilters, mockFilterBar, toggleFilterValue, useFilterBar, useFilterBarAsync, useFiltersMenu, useSearchParamAsFilter, validateFilter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/filters-filter-bar",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.201",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
"tailwind-merge": "^2.0.0",
|
|
15
15
|
"string-ts": "^2.0.0",
|
|
16
16
|
"zod": "3.23.4",
|
|
17
|
-
"@trackunit/iris-app-api": "1.3.
|
|
17
|
+
"@trackunit/iris-app-api": "1.3.128",
|
|
18
18
|
"@trackunit/react-core-hooks": "1.3.131",
|
|
19
|
-
"@trackunit/react-filter-components": "1.3.
|
|
20
|
-
"@trackunit/react-date-and-time-components": "1.3.
|
|
19
|
+
"@trackunit/react-filter-components": "1.3.166",
|
|
20
|
+
"@trackunit/react-date-and-time-components": "1.3.168",
|
|
21
21
|
"@trackunit/shared-utils": "1.5.121",
|
|
22
|
-
"@trackunit/react-form-components": "1.3.
|
|
22
|
+
"@trackunit/react-form-components": "1.3.166",
|
|
23
23
|
"@trackunit/react-core-contexts-api": "1.4.127",
|
|
24
24
|
"@trackunit/geo-json-utils": "1.3.121",
|
|
25
|
-
"@trackunit/i18n-library-translation": "1.3.
|
|
25
|
+
"@trackunit/i18n-library-translation": "1.3.137",
|
|
26
26
|
"@trackunit/css-class-variance-utilities": "1.3.121",
|
|
27
|
-
"@trackunit/react-components": "1.4.
|
|
27
|
+
"@trackunit/react-components": "1.4.146",
|
|
28
28
|
"@trackunit/react-test-setup": "1.0.11"
|
|
29
29
|
},
|
|
30
30
|
"module": "./index.esm.js",
|
package/src/lib/FilterBar.d.ts
CHANGED
|
@@ -26,9 +26,13 @@ interface FilterBarProps<TFilterBarDefinition extends FilterBarDefinition> {
|
|
|
26
26
|
* The title of the filter bar default is "Filters" (translated)
|
|
27
27
|
*/
|
|
28
28
|
title?: string;
|
|
29
|
+
/**
|
|
30
|
+
* If true, the filters marked as showDirectly will not be shown directly in the filter bar
|
|
31
|
+
*/
|
|
32
|
+
allowShowFiltersDirectly?: boolean;
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
31
35
|
* The FilterBar component serves as a wrapper for managing filters.
|
|
32
36
|
*/
|
|
33
|
-
export declare const FilterBar: <TFilterBarDefinition extends FilterBarDefinition>({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact, title, }: FilterBarProps<TFilterBarDefinition>) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export declare const FilterBar: <TFilterBarDefinition extends FilterBarDefinition>({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact, title, allowShowFiltersDirectly, }: FilterBarProps<TFilterBarDefinition>) => import("react/jsx-runtime").JSX.Element;
|
|
34
38
|
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FilterBarConfig, FilterBarDefinition, FilterMapActions, FilterMapGetter } from "../types/FilterTypes";
|
|
2
|
+
/**
|
|
3
|
+
* Tooltip label for the filter button
|
|
4
|
+
*/
|
|
5
|
+
export declare const FilterButtonTooltipLabel: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarConfig, }: {
|
|
6
|
+
filterBarConfig: FilterBarConfig<TFilterBarDefinition> & FilterMapActions & FilterMapGetter;
|
|
7
|
+
}) => string | import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { CommonProps } from "@trackunit/react-components";
|
|
1
|
+
import { ButtonProps, CommonProps } from "@trackunit/react-components";
|
|
2
2
|
import { ReactElement } from "react";
|
|
3
3
|
import { FilterBarConfig, FilterBarDefinition, FilterMapActions, FilterMapGetter } from "../types/FilterTypes";
|
|
4
4
|
interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> extends CommonProps {
|
|
5
|
+
/**
|
|
6
|
+
* If true, the filters marked as showDirectly will not be shown directly in the filter bar
|
|
7
|
+
*/
|
|
8
|
+
allowShowFiltersDirectly?: boolean;
|
|
5
9
|
/**
|
|
6
10
|
* Configuration for the filter bar.
|
|
7
11
|
*/
|
|
@@ -9,7 +13,7 @@ interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> ext
|
|
|
9
13
|
/**
|
|
10
14
|
* The definition of the filter bar, specifying its structure and filters.
|
|
11
15
|
*/
|
|
12
|
-
filterBarDefinition:
|
|
16
|
+
filterBarDefinition: TFilterBarDefinition;
|
|
13
17
|
/**
|
|
14
18
|
* If you want some of the filters to be hidden, but still programmatically enabled
|
|
15
19
|
*/
|
|
@@ -18,10 +22,18 @@ interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> ext
|
|
|
18
22
|
* If true, the starred filters will be displayed in a compact mode
|
|
19
23
|
*/
|
|
20
24
|
compact?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* If true, the applied filters count will be shown in the filter button, only visible when compact is true
|
|
27
|
+
*/
|
|
28
|
+
showAppliedFiltersCount?: boolean;
|
|
21
29
|
/**
|
|
22
30
|
* The title of the filter bar default is "Filters" (translated)
|
|
23
31
|
*/
|
|
24
32
|
title?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The icon props for the filter button to override the icon look and feel.
|
|
35
|
+
*/
|
|
36
|
+
buttonProps?: ButtonProps;
|
|
25
37
|
}
|
|
26
38
|
/**
|
|
27
39
|
* FilterMenu is a React component that displays a list of filters in a popover menu based on the provided filter bar configuration.
|
|
@@ -29,5 +41,5 @@ interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> ext
|
|
|
29
41
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
30
42
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
31
43
|
*/
|
|
32
|
-
export declare const FiltersMenu: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarDefinition, filterBarConfig, hiddenFilters, compact, title, dataTestId, className, }: FiltersMenuProps<TFilterBarDefinition>) => ReactElement;
|
|
44
|
+
export declare const FiltersMenu: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarDefinition, filterBarConfig, hiddenFilters, compact, title, dataTestId, className, showAppliedFiltersCount, buttonProps, allowShowFiltersDirectly, }: FiltersMenuProps<TFilterBarDefinition>) => ReactElement;
|
|
33
45
|
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { GroupOfFilters } from "../hooks/useGroupFilters";
|
|
2
|
+
import { FilterBarConfig, FilterBarDefinition, FilterDefinition, FilterMapActions, FilterMapGetter } from "../types/FilterTypes";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
export declare const FiltersMenuContent: ({ filterBarConfig, setShowCustomFilters, setSearchText, searchText, searchResultsGrouped, filtersToShowGrouped, removeCustomFieldsGroup, hasCustomFields, appliedCustomFields, showCustomFilters, }: {
|
|
7
|
+
filterBarConfig: FilterBarConfig<FilterBarDefinition> & FilterMapActions & FilterMapGetter;
|
|
8
|
+
setShowCustomFilters: (show: boolean) => void;
|
|
9
|
+
setSearchText: (text: string) => void;
|
|
10
|
+
searchText: string;
|
|
11
|
+
searchResultsGrouped: GroupOfFilters[];
|
|
12
|
+
filtersToShowGrouped: GroupOfFilters[];
|
|
13
|
+
removeCustomFieldsGroup: (groupOfFilters: GroupOfFilters[]) => GroupOfFilters[];
|
|
14
|
+
hasCustomFields: boolean;
|
|
15
|
+
appliedCustomFields: FilterDefinition[];
|
|
16
|
+
showCustomFilters: boolean;
|
|
17
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,10 +4,12 @@ export * from "./DefaultFilterTypes";
|
|
|
4
4
|
export * from "./DefaultMinMaxFilter";
|
|
5
5
|
export * from "./DefaultRadioFilter";
|
|
6
6
|
export * from "./DynamicFilterList";
|
|
7
|
+
export * from "./FilterButtonTooltipLabel";
|
|
7
8
|
export * from "./FilterComponent";
|
|
8
9
|
export * from "./FilterHeader";
|
|
9
10
|
export * from "./FilterResults";
|
|
10
11
|
export * from "./FiltersMenu";
|
|
12
|
+
export * from "./FiltersMenuContent";
|
|
11
13
|
export * from "./FiltersRenderer";
|
|
12
14
|
export * from "./FilterTableComponent";
|
|
13
15
|
export * from "./GroupedFiltersList";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FilterBarConfig, FilterBarDefinition, FilterMapActions, FilterMapGetter } from "../types/FilterTypes";
|
|
2
|
+
import { GroupOfFilters } from "./useGroupFilters";
|
|
3
|
+
type UseFiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> = {
|
|
4
|
+
filterBarDefinition: TFilterBarDefinition;
|
|
5
|
+
filterBarConfig: FilterBarConfig<TFilterBarDefinition> & FilterMapActions & FilterMapGetter;
|
|
6
|
+
hiddenFilters?: string[];
|
|
7
|
+
allowShowFiltersDirectly?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* This hook is used to manage the filters menu.
|
|
11
|
+
* It returns the filters that should be shown in the menu, the filters that should be shown directly in the filter bar,
|
|
12
|
+
* and the filters that should be shown in the search results.
|
|
13
|
+
*/
|
|
14
|
+
export declare const useFiltersMenu: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarDefinition, filterBarConfig, hiddenFilters, allowShowFiltersDirectly, }: UseFiltersMenuProps<TFilterBarDefinition>) => {
|
|
15
|
+
appliedFilters: import("../types/FilterTypes").FilterDefinition[];
|
|
16
|
+
hasCustomFields: boolean;
|
|
17
|
+
showDirectlyFilters: import("../types/FilterTypes").FilterDefinition[];
|
|
18
|
+
appliedCustomFields: import("../types/FilterTypes").FilterDefinition[];
|
|
19
|
+
searchText: string;
|
|
20
|
+
setSearchText: import("react").Dispatch<string>;
|
|
21
|
+
filtersToShowGrouped: GroupOfFilters[];
|
|
22
|
+
searchResultsGrouped: GroupOfFilters[];
|
|
23
|
+
removeCustomFieldsGroup: (groupOfFilters: GroupOfFilters[]) => GroupOfFilters[];
|
|
24
|
+
};
|
|
25
|
+
export {};
|
package/src/lib/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./FilterBar";
|
|
|
3
3
|
export * from "./hooks/mockFilterBar";
|
|
4
4
|
export * from "./hooks/useFilterBar";
|
|
5
5
|
export * from "./hooks/useFilterBarAsync";
|
|
6
|
+
export * from "./hooks/useFiltersMenu";
|
|
6
7
|
export * from "./hooks/useSearchParamAsFilter";
|
|
7
8
|
export * from "./types/FilterTypes";
|
|
8
9
|
export * from "./utils/FilterEvents";
|