Skip to content

Commit e19c31c

Browse files
authored
usePersistentReactDataTableState added (#87)
1 parent 5d85ab6 commit e19c31c

7 files changed

Lines changed: 162 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- added the `usePersistentReactDataTableState` hook which saves it's own state into the local storage
13+
- added `initialAfterSearchFilter` property to give the possebility, to set a different initial after filter search (fall back is still `initialColumnFilters`)
14+
1015
### Changed
1116

1217
- migrated to eslint 9 flat config

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@dnd-kit/core": "^6.1.0",
5050
"@dnd-kit/modifiers": "^7.0.0",
5151
"@dnd-kit/sortable": "^8.0.0",
52+
"@neolution-ch/javascript-utils": "^2.2.0",
5253
"@neolution-ch/react-pattern-ui": "^5.3.0",
5354
"@tanstack/react-table": "^8.12.0",
5455
"@tanstack/react-virtual": "^3.13.12",

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./lib/translations/translations";
22
export * from "./lib/useReactDataTableState/useReactDataTableState";
33
export * from "./lib/useReactDataTableState/useReactDataTableStateProps";
4+
export * from "./lib/useReactDataTableState/usePersistentReactDataTableState";
45
export * from "./lib/useReactDataTable/useReactDataTable";
56
export * from "./lib/useReactDataTable/useReactDataTableProps";
67
export * from "./lib/useReactDataTable/useReactDataTableResult";
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { getLocalStorageItem, setLocalStorageItem } from "@neolution-ch/javascript-utils";
2+
import { OptionalNullable } from "../types/NullableTypes";
3+
import { useReactDataTableStateProps } from "./useReactDataTableStateProps";
4+
import { useReactDataTableStateResult } from "./useReactDataTableStateResult";
5+
import { useReactDataTableState } from "./useReactDataTableState";
6+
import { FilterModel } from "../types/TableState";
7+
import { useCallback } from "react";
8+
9+
/**
10+
* A custom hook that will initialize all the state needed for the react data table and will persist it to local storage
11+
* @param props The properties to configure the initial state
12+
* @returns the state and the setters
13+
*/
14+
const usePersistentReactDataTableState = <TData, TFilter extends FilterModel = Record<string, never>>(
15+
props: OptionalNullable<useReactDataTableStateProps<TData, TFilter>> & { localStorageKey: string },
16+
): useReactDataTableStateResult<TData, TFilter> => {
17+
const {
18+
initialColumnFilters,
19+
initialSorting,
20+
initialPagination,
21+
initialRowSelection,
22+
initialExpanded,
23+
initialColumnPinning,
24+
initialAfterSearchFilter,
25+
localStorageKey,
26+
} = props as useReactDataTableStateProps<TData, TFilter> & { localStorageKey: string };
27+
28+
const {
29+
pagination,
30+
setPagination,
31+
columnFilters,
32+
columnPinning,
33+
expanded,
34+
rowSelection,
35+
sorting,
36+
setColumnFilters,
37+
afterSearchFilter,
38+
setAfterSearchFilter,
39+
setColumnPinning,
40+
setExpanded,
41+
setRowSelection,
42+
setSorting,
43+
} = useReactDataTableState<TData, TFilter>({
44+
initialColumnPinning:
45+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialColumnPinning"]>(`${localStorageKey}_columnPinning`) ??
46+
initialColumnPinning,
47+
initialExpanded:
48+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialExpanded"]>(`${localStorageKey}_expanded`) ?? initialExpanded,
49+
initialPagination:
50+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialPagination"]>(`${localStorageKey}_pagination`) ??
51+
initialPagination,
52+
initialRowSelection:
53+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialRowSelection"]>(`${localStorageKey}_rowSelection`) ??
54+
initialRowSelection,
55+
initialSorting:
56+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialSorting"]>(`${localStorageKey}_sorting`) ?? initialSorting,
57+
initialColumnFilters:
58+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialColumnFilters"]>(`${localStorageKey}_columnFilters`) ??
59+
initialColumnFilters,
60+
initialAfterSearchFilter:
61+
getLocalStorageItem<useReactDataTableStateProps<TData, TFilter>["initialAfterSearchFilter"]>(
62+
`${localStorageKey}_afterSearchFilter`,
63+
) ?? initialAfterSearchFilter,
64+
} as useReactDataTableStateProps<TData, TFilter> as OptionalNullable<useReactDataTableStateProps<TData, TFilter>>);
65+
66+
return {
67+
pagination,
68+
setPagination: useCallback(
69+
(newPagination) => {
70+
setPagination(newPagination);
71+
setLocalStorageItem(`${props.localStorageKey}_pagination`, newPagination);
72+
},
73+
[props.localStorageKey, setPagination],
74+
),
75+
columnFilters,
76+
setColumnFilters: useCallback(
77+
(newColumnFilters) => {
78+
setColumnFilters(newColumnFilters);
79+
setLocalStorageItem(`${props.localStorageKey}_columnFilters`, newColumnFilters);
80+
},
81+
[props.localStorageKey, setColumnFilters],
82+
),
83+
afterSearchFilter,
84+
setAfterSearchFilter: useCallback(
85+
(newAfterSearchFilter) => {
86+
setAfterSearchFilter(newAfterSearchFilter);
87+
setLocalStorageItem(`${props.localStorageKey}_afterSearchFilter`, newAfterSearchFilter);
88+
},
89+
[props.localStorageKey, setAfterSearchFilter],
90+
),
91+
columnPinning,
92+
setColumnPinning: useCallback(
93+
(newColumnPinning) => {
94+
setColumnPinning(newColumnPinning);
95+
setLocalStorageItem(`${props.localStorageKey}_columnPinning`, newColumnPinning);
96+
},
97+
[props.localStorageKey, setColumnPinning],
98+
),
99+
expanded,
100+
setExpanded: useCallback(
101+
(newExpanded) => {
102+
setExpanded(newExpanded);
103+
setLocalStorageItem(`${props.localStorageKey}_expanded`, newExpanded);
104+
},
105+
[props.localStorageKey, setExpanded],
106+
),
107+
rowSelection,
108+
setRowSelection: useCallback(
109+
(newRowSelection) => {
110+
setRowSelection(newRowSelection);
111+
setLocalStorageItem(`${props.localStorageKey}_rowSelection`, newRowSelection);
112+
},
113+
[props.localStorageKey, setRowSelection],
114+
),
115+
sorting,
116+
setSorting: useCallback(
117+
(newSorting) => {
118+
setSorting(newSorting);
119+
setLocalStorageItem(`${props.localStorageKey}_sorting`, newSorting);
120+
},
121+
[props.localStorageKey, setSorting],
122+
),
123+
};
124+
};
125+
126+
export { usePersistentReactDataTableState };

src/lib/useReactDataTableState/useReactDataTableState.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@ import { OptionalNullable } from "../types/NullableTypes";
1414
const useReactDataTableState = <TData, TFilter extends FilterModel = Record<string, never>>(
1515
props: OptionalNullable<useReactDataTableStateProps<TData, TFilter>>,
1616
): useReactDataTableStateResult<TData, TFilter> => {
17-
const { initialColumnFilters, initialSorting, initialPagination, initialRowSelection, initialExpanded, initialColumnPinning } =
18-
props as useReactDataTableStateProps<TData, TFilter>;
17+
const {
18+
initialColumnFilters,
19+
initialSorting,
20+
initialPagination,
21+
initialRowSelection,
22+
initialExpanded,
23+
initialColumnPinning,
24+
initialAfterSearchFilter,
25+
} = props as useReactDataTableStateProps<TData, TFilter>;
1926

2027
const [columnFilters, setColumnFilters] = useState<TFilter>((initialColumnFilters ?? {}) as TFilter);
21-
const [afterSearchFilter, setAfterSearchFilter] = useState<TFilter>((initialColumnFilters ?? {}) as TFilter);
28+
const [afterSearchFilter, setAfterSearchFilter] = useState<TFilter>((initialAfterSearchFilter ?? initialColumnFilters ?? {}) as TFilter);
2229
const [sorting, setSorting] = useState<SortingState<TData> | undefined>(initialSorting);
2330
const [rowSelection, setRowSelection] = useState<RowSelectionState>(initialRowSelection ?? ({} as RowSelectionState));
2431
const [expanded, setExpanded] = useState<ExpandedState>(initialExpanded ?? ({} as ExpandedState));

src/lib/useReactDataTableState/useReactDataTableStateProps.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export interface useReactDataTableStateProps<TData, TFilter extends FilterModel>
1212
*/
1313
initialColumnFilters: ColumnFilterState<TFilter>;
1414

15+
/**
16+
* the initial after search filter
17+
*/
18+
initialAfterSearchFilter?: ColumnFilterState<TFilter>;
19+
1520
/**
1621
* the initial sorting
1722
*/

yarn.lock

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,14 @@
21012101
eslint-plugin-unicorn "^61.0.2"
21022102
typescript-eslint "^8.46.1"
21032103

2104+
"@neolution-ch/javascript-utils@^2.2.0":
2105+
version "2.2.0"
2106+
resolved "https://registry.yarnpkg.com/@neolution-ch/javascript-utils/-/javascript-utils-2.2.0.tgz#11260342ef66f6ca1b3933282683b687bfe5a20a"
2107+
integrity sha512-2QO1l94EjiSbQEVDAKtWlaKJgWFj8hXY43AOKvYpNYJ7y6BbOZAwhbjEFKwgSpfVizpuyqHSsTPSHSKG8WNYhQ==
2108+
dependencies:
2109+
date-fns "^2.30.0"
2110+
uuid "^9.0.1"
2111+
21042112
"@neolution-ch/react-pattern-ui@^5.3.0":
21052113
version "5.3.0"
21062114
resolved "https://registry.yarnpkg.com/@neolution-ch/react-pattern-ui/-/react-pattern-ui-5.3.0.tgz#c900bdfc6947cfbe108910425b4dcb4027cdf34f"
@@ -6610,7 +6618,7 @@ data-view-byte-offset@^1.0.1:
66106618
es-errors "^1.3.0"
66116619
is-data-view "^1.0.1"
66126620

6613-
date-fns@^2.29.3:
6621+
date-fns@^2.29.3, date-fns@^2.30.0:
66146622
version "2.30.0"
66156623
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
66166624
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
@@ -15893,6 +15901,11 @@ uuid@^3.3.2:
1589315901
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
1589415902
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
1589515903

15904+
uuid@^9.0.1:
15905+
version "9.0.1"
15906+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
15907+
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
15908+
1589615909
v8-to-istanbul@^8.1.0:
1589715910
version "8.1.1"
1589815911
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"

0 commit comments

Comments
 (0)