@trackunit/filters-filter-bar 1.3.210 → 1.3.211

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 CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var i18nLibraryTranslation = require('@trackunit/i18n-library-translation');
5
+ var reactFilterComponents = require('@trackunit/react-filter-components');
5
6
  var reactComponents = require('@trackunit/react-components');
6
7
  var reactCoreHooks = require('@trackunit/react-core-hooks');
7
- var reactFilterComponents = require('@trackunit/react-filter-components');
8
8
  var react = require('react');
9
9
  var stringTs = require('string-ts');
10
10
  var reactCoreContextsApi = require('@trackunit/react-core-contexts-api');
@@ -320,6 +320,137 @@ const setupLibraryTranslations = () => {
320
320
  i18nLibraryTranslation.registerTranslations(translations);
321
321
  };
322
322
 
323
+ /**
324
+ * Returns the two first values, appends counter if more.
325
+ *
326
+ * @param {string[]} [input] Array of values to reduce
327
+ * @returns {*} {string}
328
+ */
329
+ const reduceFilterText = (input) => {
330
+ if (!Array.isArray(input)) {
331
+ return input;
332
+ }
333
+ // Only first two elements
334
+ const firstTwo = input.slice(0, 2);
335
+ const remainder = input.slice(2, input.length).length;
336
+ const firstTwoJoined = firstTwo.join(", ");
337
+ const remainderStr = remainder > 0 ? `, +${remainder}` : "";
338
+ return firstTwoJoined + remainderStr;
339
+ };
340
+
341
+ /**
342
+ * Filter is a React component that renders a filter element based on the provided filter definition and state.
343
+ *
344
+ * @returns {ReactElement} - Returns the Filter component.
345
+ */
346
+ const FilterComponent = ({ filter, filterBarActions, filterState, readOnly = false, visualStyle = "button", className, asIcon, size, }) => {
347
+ const values = filterBarActions.getValuesByKey(filter.filterKey);
348
+ const valuesLength = values && Array.isArray(values) ? values.length : undefined;
349
+ const getFilterText = () => {
350
+ if (!values) {
351
+ return undefined;
352
+ }
353
+ if (filter.valueAsText) {
354
+ return reduceFilterText(filter.valueAsText(values));
355
+ }
356
+ else if (filter.type === "valueNameArray") {
357
+ return reduceFilterText(values.map(value => value.name));
358
+ }
359
+ else if (filter.type === "valueName") {
360
+ return values.name;
361
+ }
362
+ return values.toString();
363
+ };
364
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
365
+ const setValue = (callback) => {
366
+ const newValue = callback(filterBarActions.getValuesByKey(filter.filterKey));
367
+ if (filter.type === "string") {
368
+ filterBarActions.setStringValue(filter.filterKey, newValue);
369
+ }
370
+ else if (filter.type === "stringArray") {
371
+ filterBarActions.setArrayValue(filter.filterKey, newValue);
372
+ }
373
+ else if (filter.type === "dateRange") {
374
+ filterBarActions.setDateRange(filter.filterKey, newValue);
375
+ }
376
+ else if (filter.type === "area") {
377
+ filterBarActions.setArea(newValue);
378
+ }
379
+ else if (filter.type === "valueNameArray") {
380
+ filterBarActions.setArrayObjectValue(filter.filterKey, newValue);
381
+ }
382
+ else if (filter.type === "valueName") {
383
+ filterBarActions.setObjectValue(filter.filterKey, newValue);
384
+ }
385
+ else if (filter.type === "minMax") {
386
+ filterBarActions.setMinMaxValue(filter.filterKey, newValue);
387
+ }
388
+ else if (filter.type === "boolean") {
389
+ filterBarActions.setBooleanValue(filter.filterKey, newValue);
390
+ }
391
+ else {
392
+ filterBarActions.setNumberValue(filter.filterKey, newValue);
393
+ }
394
+ };
395
+ const text = getFilterText();
396
+ const activeFilterText = Array.isArray(text) ? text.join(", ") : text;
397
+ const showDirectly = filter.showDirectly || false;
398
+ return showDirectly ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: filter.component({
399
+ filterDefinition: filter,
400
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
401
+ value: values,
402
+ setValue,
403
+ filterBarActions,
404
+ filterState,
405
+ }) })) : (jsxRuntime.jsx(reactFilterComponents.Filter, { activeLabel: activeFilterText, activeOptionsCount: valuesLength, asIcon: asIcon, className: className, dataTestId: `${filter.filterKey}-filter-button`, isActive: filterBarActions.appliedFilterKeys().includes(filter.filterKey), popoverProps: { placement: visualStyle === "list-item" ? "right-start" : "bottom-start" }, readOnly: readOnly, size: size, title: filter.title, visualStyle: visualStyle, withStickyHeader: true, children: filter.component({
406
+ filterDefinition: filter,
407
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
408
+ value: values,
409
+ setValue,
410
+ filterBarActions,
411
+ filterState,
412
+ }) }));
413
+ };
414
+
415
+ /**
416
+ * FiltersRenderer renders an array of Filter components from filter definitions
417
+ * It ignores hidden filters.
418
+ *
419
+ * Note: This component does not provide any styling or layout - use a wrapper for proper list styling.
420
+ *
421
+ * @param {object} props - The component props
422
+ * @param {FilterDefinition[]} props.filters - Array of filter definitions to render
423
+ * @param {FilterBarConfig & FilterMapActions & FilterMapGetter} props.filterBarConfig - The filter bar configuration
424
+ * @param {ComponentProps<typeof FilterComponent>["visualStyle"]} [props.visualStyle] - The visual style of the filters
425
+ * @returns {ReactElement[] | null} - Returns an array of Filter components or null
426
+ */
427
+ const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
428
+ return filters.length === 0
429
+ ? null
430
+ : filters
431
+ .filter(filter => !filter.isHidden)
432
+ .map(filter => (jsxRuntime.jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
433
+ };
434
+
435
+ /**
436
+ * ResetFiltersButton is a React component that provides a button for resetting filters.
437
+ *
438
+ * @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
439
+ */
440
+ const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
441
+ const [t] = useTranslation();
442
+ return (jsxRuntime.jsxs(reactComponents.Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
443
+ resetFiltersToInitialState();
444
+ }, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsxRuntime.jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
445
+ };
446
+
447
+ /**
448
+ *
449
+ */
450
+ const AppliedFiltersRenderer = ({ appliedFilters, filterBarConfig, }) => {
451
+ return (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] }));
452
+ };
453
+
323
454
  /**
324
455
  * Events — each with a name, and eventType.
325
456
  * Adding a Description is encouraged.
@@ -664,98 +795,6 @@ const FilterButtonTooltipLabel = ({ filterBarConfig, }) => {
664
795
  }
665
796
  };
666
797
 
667
- /**
668
- * Returns the two first values, appends counter if more.
669
- *
670
- * @param {string[]} [input] Array of values to reduce
671
- * @returns {*} {string}
672
- */
673
- const reduceFilterText = (input) => {
674
- if (!Array.isArray(input)) {
675
- return input;
676
- }
677
- // Only first two elements
678
- const firstTwo = input.slice(0, 2);
679
- const remainder = input.slice(2, input.length).length;
680
- const firstTwoJoined = firstTwo.join(", ");
681
- const remainderStr = remainder > 0 ? `, +${remainder}` : "";
682
- return firstTwoJoined + remainderStr;
683
- };
684
-
685
- /**
686
- * Filter is a React component that renders a filter element based on the provided filter definition and state.
687
- *
688
- * @returns {ReactElement} - Returns the Filter component.
689
- */
690
- const FilterComponent = ({ filter, filterBarActions, filterState, readOnly = false, visualStyle = "button", className, asIcon, size, }) => {
691
- const values = filterBarActions.getValuesByKey(filter.filterKey);
692
- const valuesLength = values && Array.isArray(values) ? values.length : undefined;
693
- const getFilterText = () => {
694
- if (!values) {
695
- return undefined;
696
- }
697
- if (filter.valueAsText) {
698
- return reduceFilterText(filter.valueAsText(values));
699
- }
700
- else if (filter.type === "valueNameArray") {
701
- return reduceFilterText(values.map(value => value.name));
702
- }
703
- else if (filter.type === "valueName") {
704
- return values.name;
705
- }
706
- return values.toString();
707
- };
708
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
709
- const setValue = (callback) => {
710
- const newValue = callback(filterBarActions.getValuesByKey(filter.filterKey));
711
- if (filter.type === "string") {
712
- filterBarActions.setStringValue(filter.filterKey, newValue);
713
- }
714
- else if (filter.type === "stringArray") {
715
- filterBarActions.setArrayValue(filter.filterKey, newValue);
716
- }
717
- else if (filter.type === "dateRange") {
718
- filterBarActions.setDateRange(filter.filterKey, newValue);
719
- }
720
- else if (filter.type === "area") {
721
- filterBarActions.setArea(newValue);
722
- }
723
- else if (filter.type === "valueNameArray") {
724
- filterBarActions.setArrayObjectValue(filter.filterKey, newValue);
725
- }
726
- else if (filter.type === "valueName") {
727
- filterBarActions.setObjectValue(filter.filterKey, newValue);
728
- }
729
- else if (filter.type === "minMax") {
730
- filterBarActions.setMinMaxValue(filter.filterKey, newValue);
731
- }
732
- else if (filter.type === "boolean") {
733
- filterBarActions.setBooleanValue(filter.filterKey, newValue);
734
- }
735
- else {
736
- filterBarActions.setNumberValue(filter.filterKey, newValue);
737
- }
738
- };
739
- const text = getFilterText();
740
- const activeFilterText = Array.isArray(text) ? text.join(", ") : text;
741
- const showDirectly = filter.showDirectly || false;
742
- return showDirectly ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: filter.component({
743
- filterDefinition: filter,
744
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
745
- value: values,
746
- setValue,
747
- filterBarActions,
748
- filterState,
749
- }) })) : (jsxRuntime.jsx(reactFilterComponents.Filter, { activeLabel: activeFilterText, activeOptionsCount: valuesLength, asIcon: asIcon, className: className, dataTestId: `${filter.filterKey}-filter-button`, isActive: filterBarActions.appliedFilterKeys().includes(filter.filterKey), popoverProps: { placement: visualStyle === "list-item" ? "right-start" : "bottom-start" }, readOnly: readOnly, size: size, title: filter.title, visualStyle: visualStyle, withStickyHeader: true, children: filter.component({
750
- filterDefinition: filter,
751
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
752
- value: values,
753
- setValue,
754
- filterBarActions,
755
- filterState,
756
- }) }));
757
- };
758
-
759
798
  /**
760
799
  * Custom React hook for grouping and filtering a list of filters.
761
800
  *
@@ -837,26 +876,6 @@ const useFiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters =
837
876
  ]);
838
877
  };
839
878
 
840
- /**
841
- * FiltersRenderer renders an array of Filter components from filter definitions
842
- * It ignores hidden filters.
843
- *
844
- * Note: This component does not provide any styling or layout - use a wrapper for proper list styling.
845
- *
846
- * @param {object} props - The component props
847
- * @param {FilterDefinition[]} props.filters - Array of filter definitions to render
848
- * @param {FilterBarConfig & FilterMapActions & FilterMapGetter} props.filterBarConfig - The filter bar configuration
849
- * @param {ComponentProps<typeof FilterComponent>["visualStyle"]} [props.visualStyle] - The visual style of the filters
850
- * @returns {ReactElement[] | null} - Returns an array of Filter components or null
851
- */
852
- const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
853
- return filters.length === 0
854
- ? null
855
- : filters
856
- .filter(filter => !filter.isHidden)
857
- .map(filter => (jsxRuntime.jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
858
- };
859
-
860
879
  /**
861
880
  * FiltersList is a React component that displays a list of filters within a filter bar.
862
881
  *
@@ -869,18 +888,6 @@ const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTe
869
888
  }) }));
870
889
  };
871
890
 
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
891
  /**
885
892
  *
886
893
  */
@@ -988,7 +995,7 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
988
995
  }, {});
989
996
  switch (appliedFilterKeys.length) {
990
997
  case 0:
991
- return t("filtersBar.appliedFiltersTooltip.none");
998
+ return jsxRuntime.jsx("div", { className: "text-xs font-medium", children: t("filtersBar.appliedFiltersTooltip.none") });
992
999
  case 1:
993
1000
  return (jsxRuntime.jsx(SingleFilterTooltipLabel, { filter: filtersMap[appliedFilterKeys[0]], filterBarConfig: filterBarConfig, filterKey: appliedFilterKeys[0] }));
994
1001
  default:
@@ -1020,7 +1027,7 @@ const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [],
1020
1027
  }
1021
1028
  }, placement: "bottom-start", children: modalState => {
1022
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, filters: appliedFilters }), 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, filterBarDefinitionCount: filterBarDefinitionCount, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
1023
- } }), 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] }));
1030
+ } }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ? jsxRuntime.jsx(AppliedFiltersRenderer, { appliedFilters: appliedFilters, filterBarConfig: filterBarConfig }) : null] }));
1024
1031
  };
1025
1032
 
1026
1033
  /**
@@ -1280,7 +1287,7 @@ const HierarchicalCheckboxFilter = ({ filterDefinition, filterBarActions, option
1280
1287
  /**
1281
1288
  * The FilterBar component serves as a wrapper for managing filters.
1282
1289
  */
1283
- const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, title, allowShowFiltersDirectly = true, }) => {
1290
+ const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, allowShowFiltersDirectly = true, title, }) => {
1284
1291
  return (jsxRuntime.jsx(FiltersMenu, { allowShowFiltersDirectly: allowShowFiltersDirectly, className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
1285
1292
  };
1286
1293
 
@@ -1296,6 +1303,7 @@ const mockFilterBar = {
1296
1303
  getFilterBarName: doNothing,
1297
1304
  initialState: { customerType: [] },
1298
1305
  name: "test",
1306
+ hasDefaultValue: doNothing,
1299
1307
  objectArrayIncludesValue: doNothing,
1300
1308
  resetFiltersToInitialState: doNothing,
1301
1309
  resetIndividualFilterToInitialState: doNothing,
@@ -1399,6 +1407,131 @@ const createInitialState = ({ name, mainFilters, setValue, }) => {
1399
1407
  };
1400
1408
  };
1401
1409
 
1410
+ const areaFilterGeoJsonGeometrySchema = zod.z.union([geoJsonUtils.geoJsonPolygonSchema, geoJsonUtils.geoJsonMultiPolygonSchema]);
1411
+
1412
+ const hasValue = (value) => {
1413
+ if (value === undefined || value === null) {
1414
+ return false;
1415
+ }
1416
+ // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1417
+ if (typeof value === "object" && Object.keys(value).length === 0) {
1418
+ return false;
1419
+ }
1420
+ return !(Array.isArray(value) && value.length === 0);
1421
+ };
1422
+ const isNotRightType = (filterDefinition, foundFilter) => {
1423
+ return ((filterDefinition.type === "valueNameArray" && !isValueNameArray(foundFilter)) ||
1424
+ (filterDefinition.type === "valueName" && !isValueName(foundFilter)) ||
1425
+ (filterDefinition.type === "stringArray" && !isStringArrayFilterValue(foundFilter)) ||
1426
+ (filterDefinition.type === "dateRange" && !isDateRangeValue(foundFilter)) ||
1427
+ (filterDefinition.type === "area" && !isAreaFilterValue(foundFilter)) ||
1428
+ (filterDefinition.type === "minMax" && !isMinMaxFilterValue(foundFilter)) ||
1429
+ (filterDefinition.type === "boolean" && !isBooleanValue(foundFilter)) ||
1430
+ (filterDefinition.type === "string" && typeof foundFilter !== "string") ||
1431
+ (filterDefinition.type === "number" && typeof foundFilter !== "number"));
1432
+ };
1433
+ /**
1434
+ *
1435
+ */
1436
+ const isMinMaxFilterValue = (value) => {
1437
+ return value
1438
+ ? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1439
+ typeof value === "object" && (Object.keys(value).includes("min") || Object.keys(value).includes("max"))
1440
+ : false;
1441
+ };
1442
+ /**
1443
+ *
1444
+ */
1445
+ const isDateRangeValue = (value) => {
1446
+ return value
1447
+ ? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1448
+ typeof value === "object" && (Object.keys(value).includes("from") || Object.keys(value).includes("to"))
1449
+ : false;
1450
+ };
1451
+ /**
1452
+ * {
1453
+ type: "Polygon";
1454
+ coordinates: [number, number][][];
1455
+ }
1456
+ */
1457
+ const isAreaFilterValue = (value) => {
1458
+ return areaFilterGeoJsonGeometrySchema.safeParse(value).success;
1459
+ };
1460
+ /**
1461
+ *
1462
+ */
1463
+ const isArrayFilterValue = (value) => {
1464
+ return Array.isArray(value);
1465
+ };
1466
+ /**
1467
+ *
1468
+ */
1469
+ const isStringArrayFilterValue = (value) => {
1470
+ return isArrayFilterValue(value) && value.every(item => typeof item === "string");
1471
+ };
1472
+ /**
1473
+ *
1474
+ */
1475
+ const isBooleanValue = (value) => {
1476
+ // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1477
+ return value ? typeof value === "object" && Object.keys(value).includes("booleanValue") : false;
1478
+ };
1479
+ /**
1480
+ * Type guard to check if a value is a single ValueName object
1481
+ */
1482
+ const isValueName = (value) => {
1483
+ return (typeof value === "object" &&
1484
+ value !== null &&
1485
+ // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1486
+ Object.keys(value).includes("name") &&
1487
+ // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1488
+ Object.keys(value).includes("value"));
1489
+ };
1490
+ /**
1491
+ * Type guard to check if a value is an array of ValueName objects
1492
+ */
1493
+ const isValueNameArray = (value) => {
1494
+ return isArrayFilterValue(value) && value.every(isValueName);
1495
+ };
1496
+ /**
1497
+ * Validates a filter configuration against filter definitions.
1498
+ *
1499
+ * @template TFilterBarDefinition - The type of the filter bar definition.
1500
+ * @param {FilterBarConfig<TFilterBarDefinition>} filter - The filter configuration to validate.
1501
+ * @param {FilterDefinition[]} filterDefinitions - An array of filter definitions to validate against.
1502
+ * @returns {boolean} - Returns `true` if the filter configuration is valid, otherwise `false`.
1503
+ */
1504
+ const validateFilter = ({ values, starredFilterKeys, filterDefinitions, }) => {
1505
+ const stateKeys = [];
1506
+ let inBadState = false;
1507
+ // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1508
+ for (const key of Object.keys(values)) {
1509
+ if (filterDefinitions.find(filterDefinition => filterDefinition.filterKey === key)) {
1510
+ stateKeys.push(key);
1511
+ }
1512
+ else {
1513
+ inBadState = true;
1514
+ }
1515
+ }
1516
+ filterDefinitions.forEach(filterDefinition => {
1517
+ const foundFilter = values[filterDefinition.filterKey];
1518
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1519
+ if (foundFilter && hasValue(foundFilter) && isNotRightType(filterDefinition, foundFilter)) {
1520
+ inBadState = true;
1521
+ }
1522
+ });
1523
+ if (starredFilterKeys.length > 0) {
1524
+ const allKeys = filterDefinitions.map(f => f.filterKey);
1525
+ const filteredStarredFilterKeys = starredFilterKeys.filter(key => allKeys.includes(key));
1526
+ if (filteredStarredFilterKeys.length !== starredFilterKeys.length) {
1527
+ inBadState = true;
1528
+ }
1529
+ }
1530
+ stateKeys.sort((a, b) => a.localeCompare(b));
1531
+ const filterKeysNotEqual = !isEqual(stateKeys, filterDefinitions.map(f => f.filterKey).sort((a, b) => a.localeCompare(b)));
1532
+ return !(inBadState || filterKeysNotEqual);
1533
+ };
1534
+
1402
1535
  /**
1403
1536
  * Custom hook for managing a filter bar's actions .
1404
1537
  *
@@ -1419,6 +1552,33 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
1419
1552
  const filter = filterBarConfig.values[key];
1420
1553
  return filter?.includes(value) || false;
1421
1554
  },
1555
+ hasDefaultValue(key) {
1556
+ // eslint-disable-next-line local-rules/no-typescript-assertion
1557
+ const filterValue = filterBarConfig.values[key];
1558
+ const filterDefinition = filterBarDefinition[key];
1559
+ if (dequal.dequal(filterValue, filterBarDefinition[key]?.defaultValue) || dequal.dequal(filterValue, initialState?.[key])) {
1560
+ return true;
1561
+ }
1562
+ if (filterDefinition && filterDefinition.defaultValue === undefined) {
1563
+ return false;
1564
+ }
1565
+ if (!filterValue) {
1566
+ return true;
1567
+ }
1568
+ if (Array.isArray(filterValue)) {
1569
+ return filterValue.length === 0;
1570
+ }
1571
+ if (isMinMaxFilterValue(filterValue)) {
1572
+ return filterValue.min === undefined && filterValue.max === undefined;
1573
+ }
1574
+ if (isValueName(filterValue)) {
1575
+ return filterValue.value === "";
1576
+ }
1577
+ if (typeof filterValue === "object") {
1578
+ return sharedUtils.objectKeys(filterValue).length === 0;
1579
+ }
1580
+ return false;
1581
+ },
1422
1582
  getValuesByKey(key) {
1423
1583
  return filterBarConfig.values[key];
1424
1584
  },
@@ -1683,131 +1843,6 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
1683
1843
  return react.useMemo(() => ({ filterMapGetter, filterMapActions }), [filterMapGetter, filterMapActions]);
1684
1844
  };
1685
1845
 
1686
- const areaFilterGeoJsonGeometrySchema = zod.z.union([geoJsonUtils.geoJsonPolygonSchema, geoJsonUtils.geoJsonMultiPolygonSchema]);
1687
-
1688
- const hasValue = (value) => {
1689
- if (value === undefined || value === null) {
1690
- return false;
1691
- }
1692
- // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1693
- if (typeof value === "object" && Object.keys(value).length === 0) {
1694
- return false;
1695
- }
1696
- return !(Array.isArray(value) && value.length === 0);
1697
- };
1698
- const isNotRightType = (filterDefinition, foundFilter) => {
1699
- return ((filterDefinition.type === "valueNameArray" && !isValueNameArray(foundFilter)) ||
1700
- (filterDefinition.type === "valueName" && !isValueName(foundFilter)) ||
1701
- (filterDefinition.type === "stringArray" && !isStringArrayFilterValue(foundFilter)) ||
1702
- (filterDefinition.type === "dateRange" && !isDateRangeValue(foundFilter)) ||
1703
- (filterDefinition.type === "area" && !isAreaFilterValue(foundFilter)) ||
1704
- (filterDefinition.type === "minMax" && !isMinMaxFilterValue(foundFilter)) ||
1705
- (filterDefinition.type === "boolean" && !isBooleanValue(foundFilter)) ||
1706
- (filterDefinition.type === "string" && typeof foundFilter !== "string") ||
1707
- (filterDefinition.type === "number" && typeof foundFilter !== "number"));
1708
- };
1709
- /**
1710
- *
1711
- */
1712
- const isMinMaxFilterValue = (value) => {
1713
- return value
1714
- ? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1715
- typeof value === "object" && (Object.keys(value).includes("min") || Object.keys(value).includes("max"))
1716
- : false;
1717
- };
1718
- /**
1719
- *
1720
- */
1721
- const isDateRangeValue = (value) => {
1722
- return value
1723
- ? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1724
- typeof value === "object" && (Object.keys(value).includes("from") || Object.keys(value).includes("to"))
1725
- : false;
1726
- };
1727
- /**
1728
- * {
1729
- type: "Polygon";
1730
- coordinates: [number, number][][];
1731
- }
1732
- */
1733
- const isAreaFilterValue = (value) => {
1734
- return areaFilterGeoJsonGeometrySchema.safeParse(value).success;
1735
- };
1736
- /**
1737
- *
1738
- */
1739
- const isArrayFilterValue = (value) => {
1740
- return Array.isArray(value);
1741
- };
1742
- /**
1743
- *
1744
- */
1745
- const isStringArrayFilterValue = (value) => {
1746
- return isArrayFilterValue(value) && value.every(item => typeof item === "string");
1747
- };
1748
- /**
1749
- *
1750
- */
1751
- const isBooleanValue = (value) => {
1752
- // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1753
- return value ? typeof value === "object" && Object.keys(value).includes("booleanValue") : false;
1754
- };
1755
- /**
1756
- * Type guard to check if a value is a single ValueName object
1757
- */
1758
- const isValueName = (value) => {
1759
- return (typeof value === "object" &&
1760
- value !== null &&
1761
- // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1762
- Object.keys(value).includes("name") &&
1763
- // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1764
- Object.keys(value).includes("value"));
1765
- };
1766
- /**
1767
- * Type guard to check if a value is an array of ValueName objects
1768
- */
1769
- const isValueNameArray = (value) => {
1770
- return isArrayFilterValue(value) && value.every(isValueName);
1771
- };
1772
- /**
1773
- * Validates a filter configuration against filter definitions.
1774
- *
1775
- * @template TFilterBarDefinition - The type of the filter bar definition.
1776
- * @param {FilterBarConfig<TFilterBarDefinition>} filter - The filter configuration to validate.
1777
- * @param {FilterDefinition[]} filterDefinitions - An array of filter definitions to validate against.
1778
- * @returns {boolean} - Returns `true` if the filter configuration is valid, otherwise `false`.
1779
- */
1780
- const validateFilter = ({ values, starredFilterKeys, filterDefinitions, }) => {
1781
- const stateKeys = [];
1782
- let inBadState = false;
1783
- // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
1784
- for (const key of Object.keys(values)) {
1785
- if (filterDefinitions.find(filterDefinition => filterDefinition.filterKey === key)) {
1786
- stateKeys.push(key);
1787
- }
1788
- else {
1789
- inBadState = true;
1790
- }
1791
- }
1792
- filterDefinitions.forEach(filterDefinition => {
1793
- const foundFilter = values[filterDefinition.filterKey];
1794
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1795
- if (foundFilter && hasValue(foundFilter) && isNotRightType(filterDefinition, foundFilter)) {
1796
- inBadState = true;
1797
- }
1798
- });
1799
- if (starredFilterKeys.length > 0) {
1800
- const allKeys = filterDefinitions.map(f => f.filterKey);
1801
- const filteredStarredFilterKeys = starredFilterKeys.filter(key => allKeys.includes(key));
1802
- if (filteredStarredFilterKeys.length !== starredFilterKeys.length) {
1803
- inBadState = true;
1804
- }
1805
- }
1806
- stateKeys.sort((a, b) => a.localeCompare(b));
1807
- const filterKeysNotEqual = !isEqual(stateKeys, filterDefinitions.map(f => f.filterKey).sort((a, b) => a.localeCompare(b)));
1808
- return !(inBadState || filterKeysNotEqual);
1809
- };
1810
-
1811
1846
  const getPersistenceKey = (name, clientSideUserId) => `filter-${name}-${clientSideUserId}`;
1812
1847
  /**
1813
1848
  * Custom hook for managing the persistence of filter bar configurations.
@@ -2097,6 +2132,7 @@ const mergeFilters = (filterBarDefinition, extraFilters) => {
2097
2132
  */
2098
2133
  setupLibraryTranslations();
2099
2134
 
2135
+ exports.AppliedFiltersRenderer = AppliedFiltersRenderer;
2100
2136
  exports.DefaultCheckboxFilter = DefaultCheckboxFilter;
2101
2137
  exports.DefaultDateRangeFilter = DefaultDateRangeFilter;
2102
2138
  exports.DefaultMinMaxFilter = DefaultMinMaxFilter;
@@ -2114,6 +2150,7 @@ exports.FiltersMenuContent = FiltersMenuContent;
2114
2150
  exports.FiltersRenderer = FiltersRenderer;
2115
2151
  exports.GroupedFiltersList = GroupedFiltersList;
2116
2152
  exports.HierarchicalCheckboxFilter = HierarchicalCheckboxFilter;
2153
+ exports.MultipleFilterTooltipLabel = MultipleFilterTooltipLabel;
2117
2154
  exports.ResetFiltersButton = ResetFiltersButton;
2118
2155
  exports.areaFilterGeoJsonGeometrySchema = areaFilterGeoJsonGeometrySchema;
2119
2156
  exports.isAreaFilterValue = isAreaFilterValue;