diff --git a/.changeset/witty-turkeys-mix.md b/.changeset/witty-turkeys-mix.md
new file mode 100644
index 00000000..562a3349
--- /dev/null
+++ b/.changeset/witty-turkeys-mix.md
@@ -0,0 +1,5 @@
+---
+"@genseki/react": patch
+---
+
+fix: nuqs provider
diff --git a/legacies/react/src/react/providers/table.spec.tsx b/legacies/react/src/react/providers/table.spec.tsx
new file mode 100644
index 00000000..6fc24b71
--- /dev/null
+++ b/legacies/react/src/react/providers/table.spec.tsx
@@ -0,0 +1,86 @@
+import React from 'react'
+import { renderToStaticMarkup } from 'react-dom/server'
+
+import { describe, expect, it, vi } from 'vitest'
+
+import { TableStatesContextProvider, TableStatesProvider, useTableStatesContext } from './table'
+
+import type { UsePaginationReturn } from '../hooks/use-pagination'
+import type { UseSearchReturn } from '../hooks/use-search'
+import type { UseSort } from '../hooks/use-sort'
+
+const mockedPagination: UsePaginationReturn = {
+ pagination: { page: 2, pageSize: 25 },
+ setPagination: vi.fn(),
+}
+
+const mockedSearch: UseSearchReturn = {
+ search: 'seed-search',
+ setSearch: vi.fn(),
+}
+
+const mockedSort: { sort: UseSort['Sort']; setSort: UseSort['SetSort'] } = {
+ sort: [{ id: 'name', desc: false }],
+ setSort: vi.fn(),
+}
+
+vi.mock('../hooks/use-pagination', () => ({
+ usePagination: () => mockedPagination,
+}))
+
+vi.mock('../hooks/use-search', () => ({
+ useSearch: () => mockedSearch,
+}))
+
+vi.mock('../hooks/use-sort', () => ({
+ useSort: () => mockedSort,
+}))
+
+function TableStateProbe() {
+ const state = useTableStatesContext()
+
+ return (
+
+ {JSON.stringify({
+ page: state.pagination.page,
+ pageSize: state.pagination.pageSize,
+ search: state.search,
+ sort: state.sort,
+ })}
+
+ )
+}
+
+describe('TableStatesContextProvider', () => {
+ it('renders without NuqsAdapter and does not throw', () => {
+ expect(() =>
+ renderToStaticMarkup(
+
+
+
+ )
+ ).not.toThrow()
+ })
+})
+
+describe('TableStatesProvider', () => {
+ it('keeps legacy provider API behavior via nuqs-backed hooks', () => {
+ const html = renderToStaticMarkup(
+
+
+
+ )
+
+ expect(html).toContain('"page":2')
+ expect(html).toContain('"pageSize":25')
+ expect(html).toContain('"search":"seed-search"')
+ expect(html).toContain('"id":"name"')
+ })
+})
diff --git a/legacies/react/src/react/providers/table.tsx b/legacies/react/src/react/providers/table.tsx
index 22cb63bb..8f220f14 100644
--- a/legacies/react/src/react/providers/table.tsx
+++ b/legacies/react/src/react/providers/table.tsx
@@ -35,12 +35,19 @@ interface TableStatesProviderProps {
children?: React.ReactNode
}
+export interface TableStatesContextProviderProps extends TableStatesProviderProps {
+ pagination: UsePaginationReturn['pagination']
+ setPagination: UsePaginationReturn['setPagination']
+ sort: UseSort['Sort']
+ setSort: UseSort['SetSort']
+ search: UseSearchReturn['search']
+ setSearch: UseSearchReturn['setSearch']
+}
+
const TableStatesContext = createContext(null!)
-export const TableStatesProvider = (props: TableStatesProviderProps) => {
- const { pagination, setPagination } = usePagination()
- const { sort, setSort } = useSort()
- const { search, setSearch } = useSearch()
+export const TableStatesContextProvider = (props: TableStatesContextProviderProps) => {
+ const { children, pagination, setPagination, sort, setSort, search, setSearch } = props
// row selection does not maintain a state wih URL search parameter like pagination and search
const [rowSelection, setRowSelection] = useState({})
@@ -66,11 +73,30 @@ export const TableStatesProvider = (props: TableStatesProviderProps) => {
isRowsSelected,
}}
>
- {props.children}
+ {children}
)
}
+export const TableStatesProvider = (props: TableStatesProviderProps) => {
+ const { pagination, setPagination } = usePagination()
+ const { sort, setSort } = useSort()
+ const { search, setSearch } = useSearch()
+
+ return (
+
+ {props.children}
+
+ )
+}
+
/**
* @description Hook to access the Tanstack table context which provides pagination, search, and row selection state
*/
diff --git a/legacies/react/src/react/views/collections/list/hooks/use-collection-list.ts b/legacies/react/src/react/views/collections/list/hooks/use-collection-list.ts
index 8a6d60d2..00f625a1 100644
--- a/legacies/react/src/react/views/collections/list/hooks/use-collection-list.ts
+++ b/legacies/react/src/react/views/collections/list/hooks/use-collection-list.ts
@@ -1,9 +1,9 @@
import { keepPreviousData, useQuery, type UseQueryResult } from '@tanstack/react-query'
import type { CollectionListResponse } from '../../../../../core/collection'
-import { usePagination, type UsePaginationReturn } from '../../../../hooks/use-pagination'
-import { useSearch, type UseSearchReturn } from '../../../../hooks/use-search'
-import { useSort } from '../../../../hooks/use-sort'
+import type { UsePaginationReturn } from '../../../../hooks/use-pagination'
+import type { UseSearchReturn } from '../../../../hooks/use-search'
+import { useTableStatesContext } from '../../../../providers/table'
export function useCollectionListQuery(
args: { slug: string } & {
@@ -11,9 +11,7 @@ export function useCollectionListQuery(
search?: UseSearchReturn['search']
}
) {
- const { sort } = useSort()
- const { pagination } = usePagination()
- const { search } = useSearch()
+ const { sort, pagination, search } = useTableStatesContext()
const queryKey = {
...(args.pagination || pagination),
diff --git a/legacies/react/src/react/views/collections/list/table/pagination.tsx b/legacies/react/src/react/views/collections/list/table/pagination.tsx
index 3390badf..7d159673 100644
--- a/legacies/react/src/react/views/collections/list/table/pagination.tsx
+++ b/legacies/react/src/react/views/collections/list/table/pagination.tsx
@@ -1,7 +1,7 @@
'use client'
import { PageSizeSelect, Pagination } from '../../../../components'
-import { usePagination } from '../../../../hooks/use-pagination'
+import { useTableStatesContext } from '../../../../providers/table'
import { useCollection } from '../../context'
import { useCollectionListQuery } from '../hooks/use-collection-list'
@@ -12,7 +12,7 @@ export interface CollectionListPaginationProps {
export function CollectionListPagination(props: CollectionListPaginationProps) {
const context = useCollection()
- const { pagination, setPagination } = usePagination()
+ const { pagination, setPagination } = useTableStatesContext()
const query = useCollectionListQuery({ slug: context.slug })
diff --git a/legacies/react/src/react/views/collections/list/toolbar/search.tsx b/legacies/react/src/react/views/collections/list/toolbar/search.tsx
index 041c62cc..56d661cc 100644
--- a/legacies/react/src/react/views/collections/list/toolbar/search.tsx
+++ b/legacies/react/src/react/views/collections/list/toolbar/search.tsx
@@ -7,7 +7,7 @@ import { useControllableState } from '@radix-ui/react-use-controllable-state'
import { Input } from '../../../../../../v2'
import { InputGroup, InputGroupAddon, InputGroupControl } from '../../../../components'
import { useDebounce } from '../../../../hooks/use-debounce'
-import { useSearch } from '../../../../hooks/use-search'
+import { useTableStatesContext } from '../../../../providers/table'
export interface CollectionListSearchProps {
placeholder?: string
@@ -22,7 +22,7 @@ export interface CollectionListSearchProps {
* @param props.isLoading A loading state
*/
export function CollectionListSearch(props: CollectionListSearchProps) {
- const { search: paramSearch, setSearch: setParamSearch } = useSearch()
+ const { search: paramSearch, setSearch: setParamSearch } = useTableStatesContext()
const [search, onSearch] = useControllableState({
prop: props.search,
onChange: props.onSearchChange,