@trackunit/filters-filter-bar 1.7.102 → 1.8.6
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 +51 -13
- package/index.esm.js +52 -14
- package/package.json +13 -13
- package/src/lib/components/FiltersMenu.d.ts +1 -5
package/index.cjs.js
CHANGED
|
@@ -451,7 +451,7 @@ const ResetFiltersButtonWithIcon = ({ resetFiltersToInitialState, dataTestId, cl
|
|
|
451
451
|
*/
|
|
452
452
|
const AppliedFiltersRenderer = ({ appliedFilters, filterBarConfig, showResetButton = true, }) => {
|
|
453
453
|
const filtersToRender = react.useMemo(() => appliedFilters.filter(filter => !filter.showDirectly), [appliedFilters]);
|
|
454
|
-
return (jsxRuntime.jsxs(
|
|
454
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [filtersToRender.length > 0 ? (jsxRuntime.jsx("div", { className: "h-4 w-[1px] bg-neutral-300", "data-testid": "applied-filters-buttons" })) : null, jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: filtersToRender }), appliedFilters.length > 0 && showResetButton ? (jsxRuntime.jsx(ResetFiltersButtonWithIcon, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] }));
|
|
455
455
|
};
|
|
456
456
|
|
|
457
457
|
/**
|
|
@@ -926,13 +926,23 @@ const FiltersMenuContent = ({ filterBarConfig, setShowCustomFilters, setSearchTe
|
|
|
926
926
|
const Separator = () => jsxRuntime.jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
927
927
|
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
928
928
|
const [t] = useTranslation();
|
|
929
|
-
|
|
929
|
+
// Count actual applied values, not just filter keys - same logic as badge
|
|
930
|
+
const appliedValuesCount = react.useMemo(() => {
|
|
931
|
+
return filterBarConfig.appliedFilterKeys().reduce((total, key) => {
|
|
932
|
+
const values = filterBarConfig.getValuesByKey(key);
|
|
933
|
+
if (Array.isArray(values)) {
|
|
934
|
+
return total + values.length;
|
|
935
|
+
}
|
|
936
|
+
return total + (values !== undefined ? 1 : 0);
|
|
937
|
+
}, 0);
|
|
938
|
+
}, [filterBarConfig]);
|
|
939
|
+
switch (appliedValuesCount) {
|
|
930
940
|
case 0:
|
|
931
941
|
return t("filtersBar.appliedFiltersTooltip.none");
|
|
932
942
|
case 1:
|
|
933
|
-
return
|
|
943
|
+
return t("filtersMenu.appliedFiltersLabel.singular");
|
|
934
944
|
default:
|
|
935
|
-
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count:
|
|
945
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: appliedValuesCount }) });
|
|
936
946
|
}
|
|
937
947
|
};
|
|
938
948
|
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
@@ -1029,7 +1039,7 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
|
|
|
1029
1039
|
}, {});
|
|
1030
1040
|
switch (appliedFilterKeys.length) {
|
|
1031
1041
|
case 0:
|
|
1032
|
-
return jsxRuntime.jsx("div", { className: "text-xs
|
|
1042
|
+
return jsxRuntime.jsx("div", { className: "text-xs", children: t("filtersBar.appliedFiltersTooltip.none") });
|
|
1033
1043
|
case 1:
|
|
1034
1044
|
return (jsxRuntime.jsx(SingleFilterTooltipLabel, { filter: filtersMap[appliedFilterKeys[0]], filterBarConfig: filterBarConfig, filterKey: appliedFilterKeys[0] }));
|
|
1035
1045
|
default:
|
|
@@ -1043,11 +1053,21 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
|
|
|
1043
1053
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
1044
1054
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
1045
1055
|
*/
|
|
1046
|
-
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className,
|
|
1056
|
+
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact = false, title, dataTestId = "filters-menu", className, buttonProps, allowShowFiltersDirectly = true, includeFilterKeys, }) => {
|
|
1047
1057
|
const [t] = useTranslation();
|
|
1048
|
-
const { isSm } = reactComponents.useViewportBreakpoints();
|
|
1049
1058
|
const [showCustomFilters, setShowCustomFilters] = react.useState(false);
|
|
1059
|
+
const { isSm } = reactComponents.useViewportBreakpoints();
|
|
1050
1060
|
const filterBarDefinitionCount = react.useMemo(() => sharedUtils.objectValues(filterBarDefinition).length, [filterBarDefinition]);
|
|
1061
|
+
const totalAppliedValuesCount = react.useMemo(() => {
|
|
1062
|
+
const appliedKeys = filterBarConfig.appliedFilterKeys();
|
|
1063
|
+
return appliedKeys.reduce((total, key) => {
|
|
1064
|
+
const values = filterBarConfig.getValuesByKey(key);
|
|
1065
|
+
if (Array.isArray(values)) {
|
|
1066
|
+
return total + values.length;
|
|
1067
|
+
}
|
|
1068
|
+
return total + (Boolean(values) ? 1 : 0);
|
|
1069
|
+
}, 0);
|
|
1070
|
+
}, [filterBarConfig]);
|
|
1051
1071
|
const { appliedFilters, showDirectlyFilters, hasCustomFields, filtersToShowGrouped, searchResultsGrouped, searchText, appliedCustomFields, removeCustomFieldsGroup, setSearchText, } = useFiltersMenu({
|
|
1052
1072
|
filterBarDefinition,
|
|
1053
1073
|
filterBarConfig,
|
|
@@ -1055,14 +1075,14 @@ const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [],
|
|
|
1055
1075
|
includeFilterKeys,
|
|
1056
1076
|
allowShowFiltersDirectly,
|
|
1057
1077
|
});
|
|
1058
|
-
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex items-
|
|
1078
|
+
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex items-start gap-2", className), "data-testid": dataTestId, children: [jsxRuntime.jsx(reactComponents.Popover, { onOpenStateChange: open => {
|
|
1059
1079
|
if (!open) {
|
|
1060
1080
|
setShowCustomFilters(false);
|
|
1061
1081
|
setSearchText("");
|
|
1062
1082
|
}
|
|
1063
1083
|
}, placement: "bottom-start", children: modalState => {
|
|
1064
|
-
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:
|
|
1065
|
-
} }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null,
|
|
1084
|
+
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: modalState.isOpen, label: jsxRuntime.jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filters: appliedFilters }), placement: "bottom", children: !isSm ? (jsxRuntime.jsx(reactComponents.Button, { "aria-label": title ?? t("filtersBar.filtersHeading"), prefix: jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Funnel", size: "small" }), size: "small", suffix: totalAppliedValuesCount > 0 ? (jsxRuntime.jsx(reactComponents.Badge, { color: "primary", count: totalAppliedValuesCount, hideZero: true, size: "condensed" })) : null, variant: "secondary", ...buttonProps })) : (jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Funnel", size: "small" }), size: "small", suffix: totalAppliedValuesCount > 0 ? (jsxRuntime.jsx(reactComponents.Badge, { color: "primary", count: totalAppliedValuesCount, hideZero: true, size: "condensed" })) : null, variant: "secondary", ...buttonProps, children: title !== "" ? (title ?? t("filtersBar.filtersHeading")) : null })) }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { cellPadding: 100, children: jsxRuntime.jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filterBarDefinitionCount: filterBarDefinitionCount, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
1085
|
+
} }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, compact === false ? (jsxRuntime.jsx(AppliedFiltersRenderer, { appliedFilters: appliedFilters, filterBarConfig: filterBarConfig })) : null] }));
|
|
1066
1086
|
};
|
|
1067
1087
|
|
|
1068
1088
|
/**
|
|
@@ -1080,17 +1100,35 @@ const FilterTableComponent = ({ filterKey, filterBarDefinition, filterBarConfig,
|
|
|
1080
1100
|
}
|
|
1081
1101
|
return [];
|
|
1082
1102
|
}, [filterKey, filterBarDefinition, ensureFilterKey]);
|
|
1103
|
+
// Helper function to get manually applied filter count (excluding default values)
|
|
1104
|
+
const getManuallyAppliedFilterCount = react.useCallback((keys) => {
|
|
1105
|
+
return keys.reduce((total, key) => {
|
|
1106
|
+
const filterValues = filterBarConfig.getValuesByKey(key);
|
|
1107
|
+
const isDefaultValue = filterBarConfig.isDefaultValue(key, filterValues);
|
|
1108
|
+
if (isDefaultValue) {
|
|
1109
|
+
return total; // Don't count default values
|
|
1110
|
+
}
|
|
1111
|
+
if (Array.isArray(filterValues)) {
|
|
1112
|
+
return total + filterValues.length;
|
|
1113
|
+
}
|
|
1114
|
+
return total + (filterValues ? 1 : 0);
|
|
1115
|
+
}, 0);
|
|
1116
|
+
}, [filterBarConfig]);
|
|
1083
1117
|
if (Array.isArray(filterKey)) {
|
|
1084
|
-
const
|
|
1118
|
+
const appliedFilterKeys = filterBarConfig.appliedFilterKeys();
|
|
1119
|
+
const activeFilterKeys = filterKey.filter(key => appliedFilterKeys.includes(key));
|
|
1120
|
+
const multipleFiltersAppliedCount = getManuallyAppliedFilterCount(activeFilterKeys);
|
|
1121
|
+
const multipleFiltersIsActive = multipleFiltersAppliedCount > 0;
|
|
1085
1122
|
return (jsxRuntime.jsx(reactComponents.Popover, { placement: "bottom-start", children: modalState => {
|
|
1086
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: modalState.isOpen || !
|
|
1123
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { className: "relative", children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: modalState.isOpen || !multipleFiltersIsActive, label: jsxRuntime.jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filterKeys: filterKey, filters: filters }), placement: "bottom", children: jsxRuntime.jsx(reactComponents.IconButton, { icon: jsxRuntime.jsx(reactComponents.Icon, { name: "Funnel", size: "small" }), size: "extraSmall", variant: multipleFiltersIsActive ? "ghost" : "ghost-neutral" }) }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: jsxRuntime.jsx(reactComponents.MenuList, { children: filters.map((value, index) => value && (jsxRuntime.jsx(FilterComponent, { filter: value, filterBarActions: filterBarConfig, filterState: filterBarConfig, visualStyle: "list-item" }, index))) }) })] }));
|
|
1087
1124
|
} }));
|
|
1088
1125
|
}
|
|
1089
1126
|
const filter = filterBarDefinition[ensureFilterKey(filterKey)];
|
|
1090
1127
|
if (!filter) {
|
|
1091
1128
|
return null;
|
|
1092
1129
|
}
|
|
1093
|
-
|
|
1130
|
+
const isActive = filterBarConfig.appliedFilterKeys().includes(filterKey);
|
|
1131
|
+
return (jsxRuntime.jsx("div", { onClick: event => event.stopPropagation(), children: jsxRuntime.jsx("div", { className: "relative", children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: !isActive, label: jsxRuntime.jsx(SingleFilterTooltipLabel, { filter: filter, filterBarConfig: filterBarConfig, filterKey: filterKey }), placement: "bottom", children: jsxRuntime.jsx(FilterComponent, { asIcon: "Funnel", filter: filter, filterBarActions: filterBarConfig, filterState: filterBarConfig, size: "extraSmall" }) }) }) }));
|
|
1094
1132
|
};
|
|
1095
1133
|
|
|
1096
1134
|
/**
|
package/index.esm.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
|
|
3
3
|
import { useMemo, useRef, useState, useEffect, useCallback, Fragment as Fragment$1 } from 'react';
|
|
4
4
|
import { Filter, FilterBody, RadioFilterItem, CheckBoxFilterItem, FilterHeader as FilterHeader$1, FilterFooter } from '@trackunit/react-filter-components';
|
|
5
|
-
import { Button, Icon, List, Text, Card, CardBody, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip,
|
|
5
|
+
import { Button, Icon, List, Text, Card, CardBody, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip, Badge, PopoverContent, IconButton, MenuList } from '@trackunit/react-components';
|
|
6
6
|
import { useAnalytics, useTextSearch, useCurrentUser, useCustomEncoding } from '@trackunit/react-core-hooks';
|
|
7
7
|
import { capitalize } from 'string-ts';
|
|
8
8
|
import { createEvent } from '@trackunit/react-core-contexts-api';
|
|
@@ -449,7 +449,7 @@ const ResetFiltersButtonWithIcon = ({ resetFiltersToInitialState, dataTestId, cl
|
|
|
449
449
|
*/
|
|
450
450
|
const AppliedFiltersRenderer = ({ appliedFilters, filterBarConfig, showResetButton = true, }) => {
|
|
451
451
|
const filtersToRender = useMemo(() => appliedFilters.filter(filter => !filter.showDirectly), [appliedFilters]);
|
|
452
|
-
return (jsxs(
|
|
452
|
+
return (jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [filtersToRender.length > 0 ? (jsx("div", { className: "h-4 w-[1px] bg-neutral-300", "data-testid": "applied-filters-buttons" })) : null, jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: filtersToRender }), appliedFilters.length > 0 && showResetButton ? (jsx(ResetFiltersButtonWithIcon, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] }));
|
|
453
453
|
};
|
|
454
454
|
|
|
455
455
|
/**
|
|
@@ -924,13 +924,23 @@ const FiltersMenuContent = ({ filterBarConfig, setShowCustomFilters, setSearchTe
|
|
|
924
924
|
const Separator = () => jsx("hr", { className: "border-secondary-200", role: "separator" });
|
|
925
925
|
const FiltersAppliedCountLabel = ({ filterBarConfig, }) => {
|
|
926
926
|
const [t] = useTranslation();
|
|
927
|
-
|
|
927
|
+
// Count actual applied values, not just filter keys - same logic as badge
|
|
928
|
+
const appliedValuesCount = useMemo(() => {
|
|
929
|
+
return filterBarConfig.appliedFilterKeys().reduce((total, key) => {
|
|
930
|
+
const values = filterBarConfig.getValuesByKey(key);
|
|
931
|
+
if (Array.isArray(values)) {
|
|
932
|
+
return total + values.length;
|
|
933
|
+
}
|
|
934
|
+
return total + (values !== undefined ? 1 : 0);
|
|
935
|
+
}, 0);
|
|
936
|
+
}, [filterBarConfig]);
|
|
937
|
+
switch (appliedValuesCount) {
|
|
928
938
|
case 0:
|
|
929
939
|
return t("filtersBar.appliedFiltersTooltip.none");
|
|
930
940
|
case 1:
|
|
931
|
-
return
|
|
941
|
+
return t("filtersMenu.appliedFiltersLabel.singular");
|
|
932
942
|
default:
|
|
933
|
-
return jsx(Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count:
|
|
943
|
+
return jsx(Fragment, { children: t("filtersMenu.appliedFiltersLabel.plural", { count: appliedValuesCount }) });
|
|
934
944
|
}
|
|
935
945
|
};
|
|
936
946
|
const CustomFieldsHiddenGroup = ({ appliedCustomFields, filterBarConfig, onShow, }) => {
|
|
@@ -1027,7 +1037,7 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
|
|
|
1027
1037
|
}, {});
|
|
1028
1038
|
switch (appliedFilterKeys.length) {
|
|
1029
1039
|
case 0:
|
|
1030
|
-
return jsx("div", { className: "text-xs
|
|
1040
|
+
return jsx("div", { className: "text-xs", children: t("filtersBar.appliedFiltersTooltip.none") });
|
|
1031
1041
|
case 1:
|
|
1032
1042
|
return (jsx(SingleFilterTooltipLabel, { filter: filtersMap[appliedFilterKeys[0]], filterBarConfig: filterBarConfig, filterKey: appliedFilterKeys[0] }));
|
|
1033
1043
|
default:
|
|
@@ -1041,11 +1051,21 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
|
|
|
1041
1051
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
1042
1052
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
1043
1053
|
*/
|
|
1044
|
-
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact, title, dataTestId = "filters-menu", className,
|
|
1054
|
+
const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [], compact = false, title, dataTestId = "filters-menu", className, buttonProps, allowShowFiltersDirectly = true, includeFilterKeys, }) => {
|
|
1045
1055
|
const [t] = useTranslation();
|
|
1046
|
-
const { isSm } = useViewportBreakpoints();
|
|
1047
1056
|
const [showCustomFilters, setShowCustomFilters] = useState(false);
|
|
1057
|
+
const { isSm } = useViewportBreakpoints();
|
|
1048
1058
|
const filterBarDefinitionCount = useMemo(() => objectValues(filterBarDefinition).length, [filterBarDefinition]);
|
|
1059
|
+
const totalAppliedValuesCount = useMemo(() => {
|
|
1060
|
+
const appliedKeys = filterBarConfig.appliedFilterKeys();
|
|
1061
|
+
return appliedKeys.reduce((total, key) => {
|
|
1062
|
+
const values = filterBarConfig.getValuesByKey(key);
|
|
1063
|
+
if (Array.isArray(values)) {
|
|
1064
|
+
return total + values.length;
|
|
1065
|
+
}
|
|
1066
|
+
return total + (Boolean(values) ? 1 : 0);
|
|
1067
|
+
}, 0);
|
|
1068
|
+
}, [filterBarConfig]);
|
|
1049
1069
|
const { appliedFilters, showDirectlyFilters, hasCustomFields, filtersToShowGrouped, searchResultsGrouped, searchText, appliedCustomFields, removeCustomFieldsGroup, setSearchText, } = useFiltersMenu({
|
|
1050
1070
|
filterBarDefinition,
|
|
1051
1071
|
filterBarConfig,
|
|
@@ -1053,14 +1073,14 @@ const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [],
|
|
|
1053
1073
|
includeFilterKeys,
|
|
1054
1074
|
allowShowFiltersDirectly,
|
|
1055
1075
|
});
|
|
1056
|
-
return (jsxs("div", { className: twMerge("flex items-
|
|
1076
|
+
return (jsxs("div", { className: twMerge("flex items-start gap-2", className), "data-testid": dataTestId, children: [jsx(Popover, { onOpenStateChange: open => {
|
|
1057
1077
|
if (!open) {
|
|
1058
1078
|
setShowCustomFilters(false);
|
|
1059
1079
|
setSearchText("");
|
|
1060
1080
|
}
|
|
1061
1081
|
}, placement: "bottom-start", children: modalState => {
|
|
1062
|
-
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled:
|
|
1063
|
-
} }), showDirectlyFilters.length > 0 ? (jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null,
|
|
1082
|
+
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled: modalState.isOpen, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filters: appliedFilters }), placement: "bottom", children: !isSm ? (jsx(Button, { "aria-label": title ?? t("filtersBar.filtersHeading"), prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Funnel", size: "small" }), size: "small", suffix: totalAppliedValuesCount > 0 ? (jsx(Badge, { color: "primary", count: totalAppliedValuesCount, hideZero: true, size: "condensed" })) : null, variant: "secondary", ...buttonProps })) : (jsx(Button, { prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Funnel", size: "small" }), size: "small", suffix: totalAppliedValuesCount > 0 ? (jsx(Badge, { color: "primary", count: totalAppliedValuesCount, hideZero: true, size: "condensed" })) : null, variant: "secondary", ...buttonProps, children: title !== "" ? (title ?? t("filtersBar.filtersHeading")) : null })) }) }) }), jsx(PopoverContent, { cellPadding: 100, children: jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filterBarDefinitionCount: filterBarDefinitionCount, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
1083
|
+
} }), showDirectlyFilters.length > 0 ? (jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, compact === false ? (jsx(AppliedFiltersRenderer, { appliedFilters: appliedFilters, filterBarConfig: filterBarConfig })) : null] }));
|
|
1064
1084
|
};
|
|
1065
1085
|
|
|
1066
1086
|
/**
|
|
@@ -1078,17 +1098,35 @@ const FilterTableComponent = ({ filterKey, filterBarDefinition, filterBarConfig,
|
|
|
1078
1098
|
}
|
|
1079
1099
|
return [];
|
|
1080
1100
|
}, [filterKey, filterBarDefinition, ensureFilterKey]);
|
|
1101
|
+
// Helper function to get manually applied filter count (excluding default values)
|
|
1102
|
+
const getManuallyAppliedFilterCount = useCallback((keys) => {
|
|
1103
|
+
return keys.reduce((total, key) => {
|
|
1104
|
+
const filterValues = filterBarConfig.getValuesByKey(key);
|
|
1105
|
+
const isDefaultValue = filterBarConfig.isDefaultValue(key, filterValues);
|
|
1106
|
+
if (isDefaultValue) {
|
|
1107
|
+
return total; // Don't count default values
|
|
1108
|
+
}
|
|
1109
|
+
if (Array.isArray(filterValues)) {
|
|
1110
|
+
return total + filterValues.length;
|
|
1111
|
+
}
|
|
1112
|
+
return total + (filterValues ? 1 : 0);
|
|
1113
|
+
}, 0);
|
|
1114
|
+
}, [filterBarConfig]);
|
|
1081
1115
|
if (Array.isArray(filterKey)) {
|
|
1082
|
-
const
|
|
1116
|
+
const appliedFilterKeys = filterBarConfig.appliedFilterKeys();
|
|
1117
|
+
const activeFilterKeys = filterKey.filter(key => appliedFilterKeys.includes(key));
|
|
1118
|
+
const multipleFiltersAppliedCount = getManuallyAppliedFilterCount(activeFilterKeys);
|
|
1119
|
+
const multipleFiltersIsActive = multipleFiltersAppliedCount > 0;
|
|
1083
1120
|
return (jsx(Popover, { placement: "bottom-start", children: modalState => {
|
|
1084
|
-
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { children: jsx(Tooltip, { disabled: modalState.isOpen || !
|
|
1121
|
+
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { className: "relative", children: jsx(Tooltip, { disabled: modalState.isOpen || !multipleFiltersIsActive, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filterKeys: filterKey, filters: filters }), placement: "bottom", children: jsx(IconButton, { icon: jsx(Icon, { name: "Funnel", size: "small" }), size: "extraSmall", variant: multipleFiltersIsActive ? "ghost" : "ghost-neutral" }) }) }) }), jsx(PopoverContent, { children: jsx(MenuList, { children: filters.map((value, index) => value && (jsx(FilterComponent, { filter: value, filterBarActions: filterBarConfig, filterState: filterBarConfig, visualStyle: "list-item" }, index))) }) })] }));
|
|
1085
1122
|
} }));
|
|
1086
1123
|
}
|
|
1087
1124
|
const filter = filterBarDefinition[ensureFilterKey(filterKey)];
|
|
1088
1125
|
if (!filter) {
|
|
1089
1126
|
return null;
|
|
1090
1127
|
}
|
|
1091
|
-
|
|
1128
|
+
const isActive = filterBarConfig.appliedFilterKeys().includes(filterKey);
|
|
1129
|
+
return (jsx("div", { onClick: event => event.stopPropagation(), children: jsx("div", { className: "relative", children: jsx(Tooltip, { disabled: !isActive, label: jsx(SingleFilterTooltipLabel, { filter: filter, filterBarConfig: filterBarConfig, filterKey: filterKey }), placement: "bottom", children: jsx(FilterComponent, { asIcon: "Funnel", filter: filter, filterBarActions: filterBarConfig, filterState: filterBarConfig, size: "extraSmall" }) }) }) }));
|
|
1092
1130
|
};
|
|
1093
1131
|
|
|
1094
1132
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/filters-filter-bar",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.6",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"tailwind-merge": "^2.0.0",
|
|
14
14
|
"string-ts": "^2.0.0",
|
|
15
15
|
"zod": "^3.23.8",
|
|
16
|
-
"@trackunit/iris-app-api": "1.
|
|
17
|
-
"@trackunit/react-core-hooks": "1.
|
|
18
|
-
"@trackunit/react-filter-components": "1.6
|
|
19
|
-
"@trackunit/react-date-and-time-components": "1.
|
|
20
|
-
"@trackunit/shared-utils": "1.
|
|
21
|
-
"@trackunit/react-form-components": "1.
|
|
22
|
-
"@trackunit/react-core-contexts-api": "1.
|
|
23
|
-
"@trackunit/geo-json-utils": "1.
|
|
24
|
-
"@trackunit/i18n-library-translation": "1.
|
|
25
|
-
"@trackunit/css-class-variance-utilities": "1.
|
|
26
|
-
"@trackunit/react-components": "1.
|
|
27
|
-
"@trackunit/react-test-setup": "1.
|
|
16
|
+
"@trackunit/iris-app-api": "1.7.4",
|
|
17
|
+
"@trackunit/react-core-hooks": "1.7.5",
|
|
18
|
+
"@trackunit/react-filter-components": "1.7.6",
|
|
19
|
+
"@trackunit/react-date-and-time-components": "1.10.6",
|
|
20
|
+
"@trackunit/shared-utils": "1.9.4",
|
|
21
|
+
"@trackunit/react-form-components": "1.8.6",
|
|
22
|
+
"@trackunit/react-core-contexts-api": "1.8.5",
|
|
23
|
+
"@trackunit/geo-json-utils": "1.7.4",
|
|
24
|
+
"@trackunit/i18n-library-translation": "1.7.5",
|
|
25
|
+
"@trackunit/css-class-variance-utilities": "1.7.4",
|
|
26
|
+
"@trackunit/react-components": "1.9.6",
|
|
27
|
+
"@trackunit/react-test-setup": "1.4.4",
|
|
28
28
|
"@tanstack/react-router": "1.114.29"
|
|
29
29
|
},
|
|
30
30
|
"module": "./index.esm.js",
|
|
@@ -22,10 +22,6 @@ interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> ext
|
|
|
22
22
|
* If true, the starred filters will be displayed in a compact mode
|
|
23
23
|
*/
|
|
24
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;
|
|
29
25
|
/**
|
|
30
26
|
* The title of the filter bar default is "Filters" (translated)
|
|
31
27
|
*/
|
|
@@ -45,5 +41,5 @@ interface FiltersMenuProps<TFilterBarDefinition extends FilterBarDefinition> ext
|
|
|
45
41
|
* @template TFilterBarDefinition - The type representing the filter bar definition.
|
|
46
42
|
* @returns {ReactElement} - Returns the FilterMenu component.
|
|
47
43
|
*/
|
|
48
|
-
export declare const FiltersMenu: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarDefinition, filterBarConfig, hiddenFilters, compact, title, dataTestId, className,
|
|
44
|
+
export declare const FiltersMenu: <TFilterBarDefinition extends FilterBarDefinition>({ filterBarDefinition, filterBarConfig, hiddenFilters, compact, title, dataTestId, className, buttonProps, allowShowFiltersDirectly, includeFilterKeys, }: FiltersMenuProps<TFilterBarDefinition>) => ReactElement;
|
|
49
45
|
export {};
|