From 343d1add689f7d0ea870f320696729261efe8f40 Mon Sep 17 00:00:00 2001 From: Tobias Merki <103021062+neotob@users.noreply.github.com> Date: Sun, 21 Dec 2025 21:43:53 -1000 Subject: [PATCH] usePersistentReactDataTableState added --- CHANGELOG.md | 4 + package.json | 1 + src/index.ts | 1 + .../usePersistentReactDataTableState.ts | 97 +++++++++++++++++++ yarn.lock | 15 ++- 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/lib/useReactDataTableState/usePersistentReactDataTableState.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c88a310..72d4649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- added the `usePersistentReactDataTableState` hook which saves it's own state into the local storage + ## [5.14.0] - 2025-12-15 ### Fixed diff --git a/package.json b/package.json index 23ede09..d071cc2 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", + "@neolution-ch/javascript-utils": "^2.2.0", "@neolution-ch/react-pattern-ui": "^5.3.0", "@tanstack/react-table": "^8.12.0", "@tanstack/react-virtual": "^3.13.12", diff --git a/src/index.ts b/src/index.ts index d5c2c1e..e62657c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ export * from "./lib/translations/translations"; export * from "./lib/useReactDataTableState/useReactDataTableState"; +export * from "./lib/useReactDataTableState/usePersistentReactDataTableState"; export * from "./lib/useReactDataTable/useReactDataTable"; export * from "./lib/ReactDataTable/ReactDataTable"; export * from "./lib/utils/getStronglyTypedColumnFilter"; diff --git a/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts b/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts new file mode 100644 index 0000000..ba5ceea --- /dev/null +++ b/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts @@ -0,0 +1,97 @@ +import { getLocalStorageItem, setLocalStorageItem } from "@neolution-ch/javascript-utils"; +import { OptionalNullable } from "../types/NullableTypes"; +import { useReactDataTableStateProps } from "./useReactDataTableStateProps"; +import { useReactDataTableStateResult } from "./useReactDataTableStateResult"; +import { useReactDataTableState } from "./useReactDataTableState"; +import { useEffect } from "react"; + +const usePersistentReactDataTableState = >( + props: OptionalNullable> & { localStorageKey: string }, +): useReactDataTableStateResult => { + const { + pagination, + setPagination, + columnFilters, + columnPinning, + expanded, + rowSelection, + sorting, + setColumnFilters, + afterSearchFilter, + setAfterSearchFilter, + setColumnPinning, + setExpanded, + setRowSelection, + setSorting, + } = useReactDataTableState({ + initialColumnPinning: + getLocalStorageItem["initialColumnPinning"]>(`${props.localStorageKey}_columnPinning`) ?? + props?.initialColumnPinning, + initialExpanded: + getLocalStorageItem["initialExpanded"]>(`${props.localStorageKey}_expanded`) ?? + props?.initialExpanded, + initialPagination: + getLocalStorageItem["initialPagination"]>(`${props.localStorageKey}_pagination`) ?? + props?.initialPagination, + initialRowSelection: + getLocalStorageItem["initialRowSelection"]>(`${props.localStorageKey}_rowSelection`) ?? + props?.initialRowSelection, + initialSorting: + getLocalStorageItem["initialSorting"]>(`${props.localStorageKey}_sorting`) ?? + props?.initialSorting, + } as OptionalNullable>); + + useEffect(() => { + // We can't set these values directly in the useReactDataTableState hook above, + // because the filter would be taken as default value also for the reset function. + const storedColumnFilters = getLocalStorageItem(`${props.localStorageKey}_columnFilters`); + if (storedColumnFilters) { + setColumnFilters(storedColumnFilters); + } + + const storedAfterSearchFilter = getLocalStorageItem(`${props.localStorageKey}_afterSearchFilter`); + if (storedAfterSearchFilter) { + setAfterSearchFilter(storedAfterSearchFilter); + } + }, [props.localStorageKey, setColumnFilters, setAfterSearchFilter]); + + return { + pagination, + setPagination: (newPagination) => { + setPagination(newPagination); + setLocalStorageItem(`${props.localStorageKey}_pagination`, newPagination); + }, + columnFilters, + setColumnFilters: (newColumnFilters) => { + setColumnFilters(newColumnFilters); + setLocalStorageItem(`${props.localStorageKey}_columnFilters`, newColumnFilters); + }, + afterSearchFilter, + setAfterSearchFilter: (newAfterSearchFilter) => { + setAfterSearchFilter(newAfterSearchFilter); + setLocalStorageItem(`${props.localStorageKey}_afterSearchFilter`, newAfterSearchFilter); + }, + columnPinning, + setColumnPinning: (newColumnPinning) => { + setColumnPinning(newColumnPinning); + setLocalStorageItem(`${props.localStorageKey}_columnPinning`, newColumnPinning); + }, + expanded, + setExpanded: (newExpanded) => { + setExpanded(newExpanded); + setLocalStorageItem(`${props.localStorageKey}_expanded`, newExpanded); + }, + rowSelection, + setRowSelection: (newRowSelection) => { + setRowSelection(newRowSelection); + setLocalStorageItem(`${props.localStorageKey}_rowSelection`, newRowSelection); + }, + sorting, + setSorting: (newSorting) => { + setSorting(newSorting); + setLocalStorageItem(`${props.localStorageKey}_sorting`, newSorting); + }, + }; +}; + +export { usePersistentReactDataTableState }; diff --git a/yarn.lock b/yarn.lock index eede2fc..72c8455 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1778,6 +1778,14 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@neolution-ch/javascript-utils@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@neolution-ch/javascript-utils/-/javascript-utils-2.2.0.tgz#11260342ef66f6ca1b3933282683b687bfe5a20a" + integrity sha512-2QO1l94EjiSbQEVDAKtWlaKJgWFj8hXY43AOKvYpNYJ7y6BbOZAwhbjEFKwgSpfVizpuyqHSsTPSHSKG8WNYhQ== + dependencies: + date-fns "^2.30.0" + uuid "^9.0.1" + "@neolution-ch/react-pattern-ui@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@neolution-ch/react-pattern-ui/-/react-pattern-ui-5.3.0.tgz#c900bdfc6947cfbe108910425b4dcb4027cdf34f" @@ -5787,7 +5795,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -date-fns@^2.29.3: +date-fns@^2.29.3, date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== @@ -14035,6 +14043,11 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-to-istanbul@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"