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,