Skip to content

feat: add onChange API for collection state with useCollectionURLState#292

Draft
IzumiSy wants to merge 7 commits into
mainfrom
feat/collection-state-synchronizer
Draft

feat: add onChange API for collection state with useCollectionURLState#292
IzumiSy wants to merge 7 commits into
mainfrom
feat/collection-state-synchronizer

Conversation

@IzumiSy
Copy link
Copy Markdown
Contributor

@IzumiSy IzumiSy commented May 26, 2026

Summary

Add an onChange callback to useCollectionVariables that notifies on every user-initiated state change (filters, sort, pageSize). Includes a built-in useCollectionURLState hook that provides a read/write accessor for URL-based state.

Design

Instead of a persistence interface that the hook calls internally, the API follows standard React conventions:

  • params — synchronous initial state (no delayed hydration)
  • onChange — explicit notification on state changes (unidirectional data flow)

Helper hooks like useCollectionURLState return a { read, write } accessor that wires directly into params and onChange:

const urlState = useCollectionURLState({ prefix: "dt1" });
const { variables, control } = useCollectionVariables({
  params: { ...urlState.read(), pageSize: urlState.read().pageSize ?? 20 },
  tableMetadata: productMetadata,
  onChange: urlState.write,
});

API

useCollectionVariables options

interface UseCollectionOptions<TFieldName extends string = string> {
  params?: {
    initialFilters?: Filter<TFieldName>[];
    initialSort?: { field: TFieldName; direction: "Asc" | "Desc" }[];
    pageSize?: number;
  };
  /** Called on every user-initiated state change. */
  onChange?: (state: CollectionSnapshot<TFieldName>) => void;
}

useCollectionURLState

interface CollectionURLStateAccessor<TFieldName extends string = string> {
  read(): { initialFilters?: Filter<TFieldName>[]; initialSort?: SortState[]; pageSize?: number };
  write: (state: CollectionSnapshot<TFieldName>) => void;
}

function useCollectionURLState<TFieldName>(options?: {
  prefix?: string;
  debounceMs?: number;
}): CollectionURLStateAccessor<TFieldName>;

URL format:

  • Page size: p=20
  • Sort: s=name:asc
  • Filters: f.field:operator=value (repeated params for multi-value filters)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 26, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@tailor-platform/app-shell@292
npm i https://pkg.pr.new/@tailor-platform/app-shell-sdk-plugin@292
npm i https://pkg.pr.new/@tailor-platform/app-shell-vite-plugin@292

commit: 5decd69

@IzumiSy IzumiSy changed the title feat: add CollectionStateSynchronizer API and useSearchParamsSynchronizer feat: rename Synchronizer to Persistence, simplify to read/write pattern May 26, 2026
@IzumiSy IzumiSy changed the title feat: rename Synchronizer to Persistence, simplify to read/write pattern feat: add CollectionStatePersistence API with useSearchParamsPersistence May 26, 2026
@IzumiSy IzumiSy changed the title feat: add CollectionStatePersistence API with useSearchParamsPersistence feat: add CollectionStatePersistence API with useCollectionURLPersistence May 27, 2026
IzumiSy added 5 commits May 27, 2026 10:27
…izer

Introduce a pluggable synchronizer interface for persisting collection
state (filters, sort, pageSize) to external stores.

- Add CollectionSnapshot and CollectionStateSynchronizer types
- Add synchronizer option to UseCollectionOptions / useCollectionVariables
- Implement useSearchParamsSynchronizer (URL search params persistence)
  with prefix and debounce support
- Add tests for synchronizer integration and useSearchParamsSynchronizer
…le synchronizer

- Add collectionReducer with source tracking (init/user/sync) to eliminate ref flags
- Extract useSynchronizerBridge hook for subscribe/write-back logic
- Refactor useCollectionVariables to use useReducer + bridge
- Refactor useCursorPagination to accept external pageSize parameter
- Update useSearchParamsSynchronizer to use subscribe/write pattern
- Update tests for new architecture
- CollectionStateSynchronizer → CollectionStatePersistence
- useSearchParamsSynchronizer → useSearchParamsPersistence
- Simplify to read()/write() pattern (no subscribe)
- Inline use-collection-state into use-collection-variables
- Remove react-router dependency from persistence layer
Restore original useState pattern for filters/sort/pageSize to minimize
diff from main. Persistence read/write is the only addition.
- rename useSearchParamsPersistence to useCollectionURLPersistence
- rename hook files to use-collection-url-persistence
- update exports, tests, and nextjs example usage
- keep API unreleased so no deprecation alias
@IzumiSy IzumiSy force-pushed the feat/collection-state-synchronizer branch from 032133b to 4093ece Compare May 27, 2026 01:27
IzumiSy added 2 commits May 27, 2026 10:37
- remove unnecessary setPageSize wrapper in use-collection-variables
- restore cursor pagination tests removed by unrelated changes
- Remove CollectionStatePersistence interface
- Add onChange callback to UseCollectionOptions
- Make CollectionSnapshot fields required
- Rename useCollectionURLPersistence to useCollectionURLState
- useCollectionURLState returns read/write accessor (read() for params, write for onChange)
- Merge persistence tests into use-collection-variables.test.ts
@IzumiSy IzumiSy changed the title feat: add CollectionStatePersistence API with useCollectionURLPersistence feat: add onChange API for collection state with useCollectionURLState May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant