paramsync 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +72 -1286
  2. package/README.npm.md +153 -0
  3. package/package.json +15 -4
package/README.npm.md ADDED
@@ -0,0 +1,153 @@
1
+ # paramsync
2
+
3
+ Type-safe, zero-overhead URL Search Parameters state manager for React and Next.js App Router applications.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/paramsync.svg?style=flat&colorA=18181B&colorB=2563EB)](https://www.npmjs.com/package/paramsync)
6
+ [![npm downloads](https://img.shields.io/npm/dm/paramsync.svg?style=flat&colorA=18181B&colorB=2563EB)](https://www.npmjs.com/package/paramsync)
7
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/paramsync?style=flat&colorA=18181B&colorB=2563EB)](https://bundlephobia.com/package/paramsync)
8
+ [![license](https://img.shields.io/npm/l/paramsync.svg?style=flat&colorA=18181B&colorB=2563EB)](https://github.com/3b3zeem/paramsync)
9
+
10
+ ---
11
+
12
+ ## What is paramsync?
13
+
14
+ In Next.js App Router applications, managing state through URL search parameters using standard `useSearchParams()` and `router.replace()` often introduces keystroke latency during live search, UI stutter, and cluttered URLs filled with empty or default values.
15
+
16
+ `paramsync` provides a seamless `[value, setValue]` state hook that binds React state directly to the URL:
17
+ - **0ms Input Latency:** Controlled inputs update local state instantaneously while background URL updates are debounced.
18
+ - **Clean URL Policy:** Default values, empty strings, and empty arrays are automatically purged from the query string.
19
+ - **Batch Transitions:** Multiple filter changes can be committed simultaneously in a single navigation transition via `useBatchQueryParams`.
20
+ - **Server Component Compatible:** Parsers have zero DOM dependencies and execute safely in React Server Components and Route Handlers.
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install paramsync
28
+ # or
29
+ pnpm add paramsync
30
+ # or
31
+ yarn add paramsync
32
+ ```
33
+
34
+ ### Peer Dependencies
35
+ - `react` >= 18.0.0
36
+ - `next` >= 13.0.0 (App Router)
37
+
38
+ ---
39
+
40
+ ## Quick Example
41
+
42
+ ```tsx
43
+ 'use client';
44
+
45
+ import { useQueryState, parseAsString, parseAsInteger } from 'paramsync';
46
+
47
+ export default function SearchFeed() {
48
+ // Live search with 300ms URL debounce (zero typing lag)
49
+ const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''), {
50
+ debounceMs: 300,
51
+ });
52
+
53
+ // Numeric page parameter
54
+ const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));
55
+
56
+ return (
57
+ <div>
58
+ <input
59
+ type="text"
60
+ value={search}
61
+ onChange={(e) => {
62
+ setPage(1); // Reset page index on search
63
+ setSearch(e.target.value);
64
+ }}
65
+ placeholder="Filter results..."
66
+ />
67
+
68
+ <button disabled={page <= 1} onClick={() => setPage((p) => p - 1)}>
69
+ Prev
70
+ </button>
71
+ <span>Page {page}</span>
72
+ <button onClick={() => setPage((p) => p + 1)}>
73
+ Next
74
+ </button>
75
+ </div>
76
+ );
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## API Summary
83
+
84
+ ### Built-in Parsers
85
+
86
+ | Parser | Parse Signature | Clean URL Behavior | Example |
87
+ | :--- | :--- | :--- | :--- |
88
+ | `parseAsString` | `string \| null` | Omitted if `""` or default | `?q=laptop` |
89
+ | `parseAsInteger` | `number \| null` | Omitted if default | `?page=2` |
90
+ | `parseAsFloat` | `number \| null` | Omitted if default | `?rating=4.5` |
91
+ | `parseAsBoolean` | `boolean \| null` | Omitted if default | `?inStock=true` |
92
+ | `parseAsArray(parser, sep?)` | `T[]` | Omitted if `[]` or default | `?tags=shoes,sale` |
93
+ | `parseAsNumberRange(min, max, sep?)` | `{ min, max }` | Omitted if matches bounds | `?price=50-250` |
94
+ | `parseAsSort(field, order?, sep?)` | `{ field, order }` | Omitted if matches default | `?sort=price.asc` |
95
+ | `createParser(config)` | `T` | Custom serializer | User-defined |
96
+
97
+ > Calling `.withDefault(fallback)` on any parser narrows the returned state type from `T | null` to non-nullable `T`.
98
+
99
+ ### Hooks
100
+
101
+ #### `useQueryState(key, parser, options?)`
102
+ Manages an individual URL parameter with optimistic local state.
103
+
104
+ ```tsx
105
+ const [value, setValue, reset, isPending] = useQueryState('q', parseAsString.withDefault(''), {
106
+ debounceMs: 300, // Debounce URL commit (0ms local state feedback)
107
+ history: 'replace', // 'replace' | 'push'
108
+ scroll: false, // Scroll to top on update
109
+ });
110
+ ```
111
+
112
+ #### `useBatchQueryParams(options?)`
113
+ Executes multiple parameter changes in a single URL transition (for modals or drawers):
114
+
115
+ ```tsx
116
+ const { setBatchParams, resetAllParams, isPending } = useBatchQueryParams();
117
+
118
+ // Commit multiple filter updates in a single transition
119
+ setBatchParams({
120
+ q: 'shoes',
121
+ categories: { value: ['running'], parser: parseAsArray(parseAsString) },
122
+ price: { value: { min: 50, max: 200 }, parser: parseAsNumberRange(0, 1000) },
123
+ page: null, // Deletes 'page' from URL (resets to page 1)
124
+ });
125
+
126
+ // Wipe all non-essential parameters at once
127
+ resetAllParams(['tab', 'utm_source']);
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Clean URL Policy
133
+
134
+ `paramsync` automatically deletes a parameter from the query string when:
135
+ 1. Its value equals `defaultValue`.
136
+ 2. Its value is an empty string `""`.
137
+ 3. Its value is an empty array `[]`.
138
+ 4. Its value is `null` or `undefined`.
139
+
140
+ ---
141
+
142
+ ## Documentation & Repository
143
+
144
+ For complete architectural guides, Server Components (RSC) data fetching patterns, TanStack Query integration, dynamic facet filtering, and recipes:
145
+
146
+ - **Repository & Full Docs:** [https://github.com/3b3zeem/paramsync](https://github.com/3b3zeem/paramsync)
147
+ - **Issues & Feedback:** [https://github.com/3b3zeem/paramsync/issues](https://github.com/3b3zeem/paramsync/issues)
148
+
149
+ ---
150
+
151
+ ## License
152
+
153
+ MIT © [Ahmed Mostafa](https://github.com/3b3zeem/paramsync)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paramsync",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Zero-overhead, type-safe URL Search Params state manager for React & Next.js App Router applications.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -26,8 +26,9 @@
26
26
  "test": "vitest run",
27
27
  "test:watch": "vitest",
28
28
  "typecheck": "tsc --noEmit",
29
- "playground": "next dev playground -p 3000",
30
- "prepublishOnly": "npm run typecheck && npm run test && npm run build"
29
+ "prepublishOnly": "npm run typecheck && npm run test && npm run build",
30
+ "prepack": "node scripts/prepare-npm-readme.js",
31
+ "postpack": "node scripts/restore-github-readme.js"
31
32
  },
32
33
  "repository": {
33
34
  "type": "git",
@@ -41,12 +42,22 @@
41
42
  "react",
42
43
  "nextjs",
43
44
  "app-router",
45
+ "next-navigation",
44
46
  "searchparams",
45
- "url-state",
47
+ "use-search-params",
48
+ "use-query-params",
49
+ "use-query-state",
46
50
  "query-state",
51
+ "url-state",
52
+ "url-params",
47
53
  "filters",
54
+ "facet-filters",
55
+ "filter-drawer",
56
+ "sorting",
48
57
  "pagination",
49
58
  "nuqs",
59
+ "nuqs-alternative",
60
+ "type-safe",
50
61
  "paramsync"
51
62
  ],
52
63
  "author": "Ahmed Mostafa <ahmedmostafaabdel3azem@gmail.com>",