@trackunit/filters-filter-bar 2.6.2 → 2.6.3
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 +24 -27
- package/index.esm.js +26 -29
- package/package.json +9 -9
package/index.cjs.js
CHANGED
|
@@ -1911,6 +1911,12 @@ const useFilterUrlSync = () => {
|
|
|
1911
1911
|
}), [getFilterValuesFromUrl, getFilterValuesToUrl]);
|
|
1912
1912
|
};
|
|
1913
1913
|
|
|
1914
|
+
const filterBarPersistedSchema = zod.z.object({
|
|
1915
|
+
values: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
1916
|
+
});
|
|
1917
|
+
// A fresh object per call — callers (e.g. loadValues) mutate the returned `values` object
|
|
1918
|
+
// directly, so this must never be a shared reference reused across calls.
|
|
1919
|
+
const createDefaultFilterBarConfigPersisted = () => ({ values: {} });
|
|
1914
1920
|
/**
|
|
1915
1921
|
* Custom hook for managing the persistence of filter bar configurations.
|
|
1916
1922
|
*/
|
|
@@ -1929,13 +1935,17 @@ const useFilterBarPersistence = ({ name, setValue, refreshData, isDefaultValue,
|
|
|
1929
1935
|
},
|
|
1930
1936
|
});
|
|
1931
1937
|
const storageKey = reactComponents.useStorageKey(`filter-${name}`, clientSideUserId);
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1938
|
+
// Custom mode (inputLoadData/inputSaveData provided) must never touch localStorage at all —
|
|
1939
|
+
// useLocalStorage's write-on-mount behavior would create an entry even if its setter is never
|
|
1940
|
+
// called, so this reads/writes explicitly via the non-hook accessors instead, preserving the
|
|
1941
|
+
// exact current imperative control flow (including custom mode's complete storage bypass).
|
|
1942
|
+
const getFromLocalStorage = react.useCallback(() => sharedUtils.readLocalStorageValue({
|
|
1943
|
+
key: storageKey,
|
|
1944
|
+
defaultState: createDefaultFilterBarConfigPersisted(),
|
|
1945
|
+
schema: filterBarPersistedSchema,
|
|
1946
|
+
}), [storageKey]);
|
|
1937
1947
|
const lastName = react.useRef(name);
|
|
1938
|
-
const [initialStoredFilters] = react.useState(() =>
|
|
1948
|
+
const [initialStoredFilters] = react.useState(() => !inputLoadData ? getFromLocalStorage() : null);
|
|
1939
1949
|
const { getFilterValuesFromUrl, getFilterValuesToUrl } = useFilterUrlSync();
|
|
1940
1950
|
const lastSavedStateRef = react.useRef(undefined);
|
|
1941
1951
|
const saveData = react.useCallback((filterBarConfig, filterBarDefinitions) => {
|
|
@@ -1958,38 +1968,25 @@ const useFilterBarPersistence = ({ name, setValue, refreshData, isDefaultValue,
|
|
|
1958
1968
|
inputSaveData(newValues);
|
|
1959
1969
|
}
|
|
1960
1970
|
else {
|
|
1961
|
-
|
|
1962
|
-
localStorage.setItem(storageKey, reactComponents.storageSerializer.serialize(toPersist));
|
|
1971
|
+
sharedUtils.writeLocalStorageValue({ key: storageKey, value: toPersist, schema: filterBarPersistedSchema });
|
|
1963
1972
|
const urlObject = getFilterValuesToUrl(newValues, sharedUtils.objectValues(filterBarDefinitions), false, isDefaultValue);
|
|
1964
1973
|
updateSearchParam(encode(urlObject));
|
|
1965
1974
|
}
|
|
1966
1975
|
}
|
|
1967
1976
|
}, [storageKey, inputSaveData, getFilterValuesToUrl, updateSearchParam, encode, isDefaultValue]);
|
|
1968
1977
|
const loadFromLocalStorage = react.useCallback(() => {
|
|
1969
|
-
let
|
|
1978
|
+
let stored;
|
|
1970
1979
|
if (lastName.current !== name) {
|
|
1971
|
-
|
|
1972
|
-
storedFilters = localStorage.getItem(storageKey) || "{}";
|
|
1980
|
+
stored = getFromLocalStorage();
|
|
1973
1981
|
lastName.current = name;
|
|
1974
1982
|
}
|
|
1975
1983
|
else {
|
|
1976
|
-
|
|
1977
|
-
}
|
|
1978
|
-
if (storedFilters && storedFilters !== "undefined") {
|
|
1979
|
-
try {
|
|
1980
|
-
const deserialized = reactComponents.storageSerializer.deserialize(storedFilters);
|
|
1981
|
-
if (typeof deserialized === "object" && deserialized !== null && !Array.isArray(deserialized)) {
|
|
1982
|
-
const record = Object.fromEntries(Object.entries(deserialized));
|
|
1983
|
-
return record.values ?? {};
|
|
1984
|
-
}
|
|
1985
|
-
return {};
|
|
1986
|
-
}
|
|
1987
|
-
catch {
|
|
1988
|
-
return {};
|
|
1989
|
-
}
|
|
1984
|
+
stored = initialStoredFilters ?? createDefaultFilterBarConfigPersisted();
|
|
1990
1985
|
}
|
|
1991
|
-
return
|
|
1992
|
-
|
|
1986
|
+
// Callers (loadValues) mutate the returned object directly — return a fresh shallow copy
|
|
1987
|
+
// each time so a mutation doesn't leak into the cached initialStoredFilters for next time.
|
|
1988
|
+
return { ...stored.values };
|
|
1989
|
+
}, [name, initialStoredFilters, getFromLocalStorage]);
|
|
1993
1990
|
const loadFromSearchURL = react.useCallback(() => {
|
|
1994
1991
|
if (searchValue !== undefined) {
|
|
1995
1992
|
try {
|
package/index.esm.js
CHANGED
|
@@ -3,13 +3,13 @@ import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-l
|
|
|
3
3
|
import { useMemo, useState, useEffect, useCallback, Fragment as Fragment$1, useRef } from 'react';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { Filter, FilterBody, RadioFilterItem, CheckBoxFilterItem, FilterHeader as FilterHeader$1, FilterFooter } from '@trackunit/react-filter-components';
|
|
6
|
-
import { Button, Icon, useList, List, Text, useTextSearch, cvaMenuList, cvaMenu, ZStack, IconButton, Badge, useViewportBreakpoints, MenuTree, Popover, PopoverTrigger, Tooltip, PopoverContent, useCustomEncoding, useSearchParamSync, useStorageKey,
|
|
6
|
+
import { Button, Icon, useList, List, Text, useTextSearch, cvaMenuList, cvaMenu, ZStack, IconButton, Badge, useViewportBreakpoints, MenuTree, Popover, PopoverTrigger, Tooltip, PopoverContent, useCustomEncoding, useSearchParamSync, useStorageKey, useWatch } from '@trackunit/react-components';
|
|
7
7
|
import { useAnalytics, useCurrentUser } from '@trackunit/react-core-hooks';
|
|
8
8
|
import { capitalize } from 'string-ts';
|
|
9
9
|
import { createEvent } from '@trackunit/iris-app-runtime-core-api';
|
|
10
10
|
import { Search, NumberField, RadioGroup } from '@trackunit/react-form-components';
|
|
11
11
|
import { DayRangePicker } from '@trackunit/react-date-and-time-components';
|
|
12
|
-
import { nonNullable, capitalize as capitalize$1, objectValues, truthy, objectKeys } from '@trackunit/shared-utils';
|
|
12
|
+
import { nonNullable, capitalize as capitalize$1, objectValues, truthy, objectKeys, readLocalStorageValue, writeLocalStorageValue } from '@trackunit/shared-utils';
|
|
13
13
|
import { customFieldFilterKey } from '@trackunit/iris-app-api';
|
|
14
14
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
15
15
|
import { dequal } from 'dequal';
|
|
@@ -1909,6 +1909,12 @@ const useFilterUrlSync = () => {
|
|
|
1909
1909
|
}), [getFilterValuesFromUrl, getFilterValuesToUrl]);
|
|
1910
1910
|
};
|
|
1911
1911
|
|
|
1912
|
+
const filterBarPersistedSchema = z.object({
|
|
1913
|
+
values: z.record(z.string(), z.unknown()),
|
|
1914
|
+
});
|
|
1915
|
+
// A fresh object per call — callers (e.g. loadValues) mutate the returned `values` object
|
|
1916
|
+
// directly, so this must never be a shared reference reused across calls.
|
|
1917
|
+
const createDefaultFilterBarConfigPersisted = () => ({ values: {} });
|
|
1912
1918
|
/**
|
|
1913
1919
|
* Custom hook for managing the persistence of filter bar configurations.
|
|
1914
1920
|
*/
|
|
@@ -1927,13 +1933,17 @@ const useFilterBarPersistence = ({ name, setValue, refreshData, isDefaultValue,
|
|
|
1927
1933
|
},
|
|
1928
1934
|
});
|
|
1929
1935
|
const storageKey = useStorageKey(`filter-${name}`, clientSideUserId);
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1936
|
+
// Custom mode (inputLoadData/inputSaveData provided) must never touch localStorage at all —
|
|
1937
|
+
// useLocalStorage's write-on-mount behavior would create an entry even if its setter is never
|
|
1938
|
+
// called, so this reads/writes explicitly via the non-hook accessors instead, preserving the
|
|
1939
|
+
// exact current imperative control flow (including custom mode's complete storage bypass).
|
|
1940
|
+
const getFromLocalStorage = useCallback(() => readLocalStorageValue({
|
|
1941
|
+
key: storageKey,
|
|
1942
|
+
defaultState: createDefaultFilterBarConfigPersisted(),
|
|
1943
|
+
schema: filterBarPersistedSchema,
|
|
1944
|
+
}), [storageKey]);
|
|
1935
1945
|
const lastName = useRef(name);
|
|
1936
|
-
const [initialStoredFilters] = useState(() =>
|
|
1946
|
+
const [initialStoredFilters] = useState(() => !inputLoadData ? getFromLocalStorage() : null);
|
|
1937
1947
|
const { getFilterValuesFromUrl, getFilterValuesToUrl } = useFilterUrlSync();
|
|
1938
1948
|
const lastSavedStateRef = useRef(undefined);
|
|
1939
1949
|
const saveData = useCallback((filterBarConfig, filterBarDefinitions) => {
|
|
@@ -1956,38 +1966,25 @@ const useFilterBarPersistence = ({ name, setValue, refreshData, isDefaultValue,
|
|
|
1956
1966
|
inputSaveData(newValues);
|
|
1957
1967
|
}
|
|
1958
1968
|
else {
|
|
1959
|
-
|
|
1960
|
-
localStorage.setItem(storageKey, storageSerializer.serialize(toPersist));
|
|
1969
|
+
writeLocalStorageValue({ key: storageKey, value: toPersist, schema: filterBarPersistedSchema });
|
|
1961
1970
|
const urlObject = getFilterValuesToUrl(newValues, objectValues(filterBarDefinitions), false, isDefaultValue);
|
|
1962
1971
|
updateSearchParam(encode(urlObject));
|
|
1963
1972
|
}
|
|
1964
1973
|
}
|
|
1965
1974
|
}, [storageKey, inputSaveData, getFilterValuesToUrl, updateSearchParam, encode, isDefaultValue]);
|
|
1966
1975
|
const loadFromLocalStorage = useCallback(() => {
|
|
1967
|
-
let
|
|
1976
|
+
let stored;
|
|
1968
1977
|
if (lastName.current !== name) {
|
|
1969
|
-
|
|
1970
|
-
storedFilters = localStorage.getItem(storageKey) || "{}";
|
|
1978
|
+
stored = getFromLocalStorage();
|
|
1971
1979
|
lastName.current = name;
|
|
1972
1980
|
}
|
|
1973
1981
|
else {
|
|
1974
|
-
|
|
1975
|
-
}
|
|
1976
|
-
if (storedFilters && storedFilters !== "undefined") {
|
|
1977
|
-
try {
|
|
1978
|
-
const deserialized = storageSerializer.deserialize(storedFilters);
|
|
1979
|
-
if (typeof deserialized === "object" && deserialized !== null && !Array.isArray(deserialized)) {
|
|
1980
|
-
const record = Object.fromEntries(Object.entries(deserialized));
|
|
1981
|
-
return record.values ?? {};
|
|
1982
|
-
}
|
|
1983
|
-
return {};
|
|
1984
|
-
}
|
|
1985
|
-
catch {
|
|
1986
|
-
return {};
|
|
1987
|
-
}
|
|
1982
|
+
stored = initialStoredFilters ?? createDefaultFilterBarConfigPersisted();
|
|
1988
1983
|
}
|
|
1989
|
-
return
|
|
1990
|
-
|
|
1984
|
+
// Callers (loadValues) mutate the returned object directly — return a fresh shallow copy
|
|
1985
|
+
// each time so a mutation doesn't leak into the cached initialStoredFilters for next time.
|
|
1986
|
+
return { ...stored.values };
|
|
1987
|
+
}, [name, initialStoredFilters, getFromLocalStorage]);
|
|
1991
1988
|
const loadFromSearchURL = useCallback(() => {
|
|
1992
1989
|
if (searchValue !== undefined) {
|
|
1993
1990
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/filters-filter-bar",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.3",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"string-ts": "^2.0.0",
|
|
13
13
|
"zod": "^3.25.76",
|
|
14
14
|
"@trackunit/iris-app-api": "2.4.5",
|
|
15
|
-
"@trackunit/react-core-hooks": "1.21.
|
|
16
|
-
"@trackunit/react-filter-components": "2.6.
|
|
17
|
-
"@trackunit/react-date-and-time-components": "2.6.
|
|
18
|
-
"@trackunit/shared-utils": "1.16.
|
|
19
|
-
"@trackunit/react-form-components": "2.6.
|
|
20
|
-
"@trackunit/iris-app-runtime-core-api": "1.17.
|
|
15
|
+
"@trackunit/react-core-hooks": "1.21.9",
|
|
16
|
+
"@trackunit/react-filter-components": "2.6.3",
|
|
17
|
+
"@trackunit/react-date-and-time-components": "2.6.3",
|
|
18
|
+
"@trackunit/shared-utils": "1.16.16",
|
|
19
|
+
"@trackunit/react-form-components": "2.6.3",
|
|
20
|
+
"@trackunit/iris-app-runtime-core-api": "1.17.16",
|
|
21
21
|
"@trackunit/geo-json-utils": "1.15.13",
|
|
22
|
-
"@trackunit/i18n-library-translation": "2.4.
|
|
22
|
+
"@trackunit/i18n-library-translation": "2.4.9",
|
|
23
23
|
"@trackunit/css-class-variance-utilities": "1.14.13",
|
|
24
|
-
"@trackunit/react-components": "2.9.
|
|
24
|
+
"@trackunit/react-components": "2.9.3"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"@apollo/client": "^3.13.8",
|