react-magic-search-params 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gabriel S.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,564 @@
1
+ # `react-magic-search-params` Documentation πŸͺ„ <img src="https://static-production.npmjs.com/255a118f56f5346b97e56325a1217a16.svg" width="20px" height="20px" title="This package contains built-in TypeScript declarations" alt="TypeScript icon, indicating that this package has built-in type declarations" class="aa30d277 pl3" data-nosnippet="true">
2
+
3
+
4
+ # Installation
5
+
6
+ To install this library, run:
7
+
8
+ ```bash
9
+ npm install react-magic-search-params
10
+ ```
11
+
12
+ ## Table of Contents πŸ“‘
13
+
14
+ 1. [General Introduction](#general-introduction)
15
+ 1.1 [Hook Purpose](#hook-purpose)
16
+ 1.2 [Implementation Context](#implementation-context)
17
+ 2. [Accepted Parameter Types](#accepted-parameter-types)
18
+ 2.1 [mandatory (Required)](#mandatory-required)
19
+ 2.2 [optional (Optional)](#optional-optional)
20
+ 2.3 [defaultParams](#defaultparams)
21
+ 2.4 [forceParams](#forceparams)
22
+ 2.5 [omitParamsByValues](#omitparamsbyvalues)
23
+ 2.6 [arraySerialization](#arrayserialization)
24
+ 3. [Usage Recommendation with a Constants File](#usage-recommendation-with-a-constants-file)
25
+ 4. [Main Functions](#main-functions)
26
+ 4.1 [getParams](#getparams)
27
+ 4.2 [updateParams](#updateparams)
28
+ 4.3 [clearParams](#clearparams)
29
+
30
+ 5. [Key Features and Benefits](#key-features-and-benefits)
31
+ 6. [Usage Example & Explanations](#usage-example--explanations)
32
+ 7. [Array Serialization in the URL (new)](#array-serialization-in-the-url-new)
33
+ 8. [Best Practices and Considerations](#best-practices-and-considerations-)
34
+ 9. [Unit Tests with Vitest](#unit-tests-with-vitest)
35
+ 10. [Conclusion](#conclusion-)
36
+
37
+ ---
38
+
39
+
40
+ # General Introduction
41
+
42
+ <img src="https://github.com/user-attachments/assets/1f437570-6f30-4c10-b27d-b876f5c557bd" alt="Screenshot" width="800px" />
43
+
44
+ ## Hook Purpose 🎯
45
+
46
+ The **`useMagicSearchParams` hook** enables **advanced** and **centralized** management of URL parameters.
47
+ It allows you to define and unify logic to filter, paginate, or perform any other operation that depends on query parameters (e.g. `?page=1&page_size=10`).
48
+
49
+ **Before (no autocomplete or typing)**
50
+ This section quickly illustrates how parameter handling changed before using the hook and how it simplifies with `useMagicSearchParams`.
51
+
52
+ <details>
53
+ <summary>Before (manual URL handling) ❌</summary>
54
+
55
+ ```jsx
56
+ // filepath: /example/BeforeHook.tsx
57
+
58
+ export const BeforeHookExample = () => {
59
+ const [searchParams, setSearchParams] = useSearchParams()
60
+
61
+ // Manually extract values (no typing or validation)
62
+ const page = parseInt(searchParams.get('page') || '1', 10)
63
+ const pageSize = parseInt(searchParams.get('page_size') || '10', 10)
64
+ const search = searchParams.get('search') || ''
65
+
66
+ const handleChangePage = (newPage: number) => {
67
+ searchParams.set('page', newPage.toString())
68
+ setSearchParams(searchParams)
69
+ }
70
+
71
+ return (
72
+ <div>
73
+ <p>Page: {page}</p>
74
+ <p>page_size: {pageSize}</p>
75
+ <p>search: {search}</p>
76
+ {/* Button to move to the next page */}
77
+ <button onClick={() => handleChangePage(page + 1)}>Next page</button>
78
+ </div>
79
+ )
80
+ }
81
+ ```
82
+
83
+ </details>
84
+ </details> <details> <summary>After (with autocomplete and safety) βœ…</summary>
85
+
86
+ ```jsx
87
+ // filepath: /example/AfterHook.tsx
88
+ import { useMagicSearchParams } from "@/hooks/useMagicSearchParams";
89
+ import { paramsUsers } from "@/constants/DefaultParamsPage";
90
+
91
+ export const AfterHookExample = () => {
92
+ // context of an external API...
93
+ const { searchParams, getParams, updateParams } = useMagicSearchParams({
94
+ ...paramsUsers,
95
+ forceParams: { page_size: paramsUsers.mandatory.page_size }, // limited to 10
96
+ omitParamsByValues: ["all", "default"],
97
+ });
98
+
99
+ useEffect(() => {
100
+ const paramsUser = getParams();
101
+
102
+ async function loadUsers() {
103
+ toast.loading("Loading...", { id: "loading" });
104
+
105
+ console.log({ paramsUser });
106
+ const { success, message } = await getUsersContext(paramsUser);
107
+ if (success) {
108
+ toast.success(message ?? "Users retrieved", { id: "loading" });
109
+ setLoading(false);
110
+ } else {
111
+ toast.error(message ?? "Unexpected error retrieving the users", {
112
+ id: "loading",
113
+ });
114
+ }
115
+ }
116
+ loadUsers();
117
+ }, [searchParams]);
118
+
119
+ // getParams returns typed and converted data with autocomplete
120
+ const { page, page_size, search } = getParams({ convert: true });
121
+
122
+ const tags = getParam("tags", { convert: false })
123
+
124
+ const handleNextPage = () => {
125
+ const nextPage = { page: (page ?? 1) + 1 };
126
+ updateParams({ newParams: nextPage }); // by default, the rest of the query parameters are preserved
127
+ };
128
+
129
+ return (
130
+ <div>
131
+ {/* Note: typically this input will be β€œuncontrolled,” as you often use a β€œdebounce” approach to delay updates */}
132
+ <input
133
+ defaultValue={search}
134
+ placeholder="Search by..."
135
+ onChange={handleSearchChange}
136
+ />
137
+ <p>Current page: {page}</p>
138
+ <p>Page size: {page_size}</p>
139
+ <p>Search: {search}</p>
140
+ <button onClick={handleNextPage}>Next page</button>
141
+ </div>
142
+ );
143
+ };
144
+ ```
145
+
146
+ </details>
147
+
148
+ #### Additional Information πŸ“‹
149
+
150
+ 1. **Strict Typing_**
151
+
152
+ - By defining β€œmandatory” and β€œoptional” from a constants file, TypeScript infers the available keys in the U
153
+
154
+ 2. **_Control en la URL_**
155
+
156
+ - β€œforceParams” enforces fixed values (preventing unnecessary API overloads).
157
+ β€œomitParamsByValues” removes β€œall” or β€œdefault” parameters that don’t add real information..
158
+
159
+ 3. **_Reuse in Different Views_**
160
+
161
+ - Each view can have its own mandatory and optional. This prevents code duplication for extracting and validating parameters.
162
+
163
+ 4. **_Uniform URL Order_**
164
+
165
+ - ensures a predictable order (first β€œpage”, then β€œpage_size”, etc.)
166
+
167
+ ### Implementation Context
168
+
169
+ 1. **Avoid multiple sources of truth**: By centralizing logic in a single hook, code does not repeat in every file.
170
+ 2. **Guarantee a Common Standard** All parameters (required or optional) are defined in a single place and reused in multiple places.
171
+ 3. **Control the URL**: Prevents unwanted parameter injections and maintains a consistent order(ej. `?page=1&page_size=10` en instead ?`page_size=1000&page=1`).
172
+
173
+ ### Accepted Parameter Typess
174
+
175
+ 1. **Mandatory**:(Required)
176
+
177
+ - Typical example: Pagination (page, page_size)
178
+ - They must always exist in the URL for the view to work.
179
+
180
+ 2. **Optional**:(Opcionales)
181
+
182
+ - Example: Search filters (search, order).
183
+ - They do not affect the **route** if they are not present.
184
+
185
+ 3. **DefaultParams**:
186
+
187
+ - Automatically set when loading a component.
188
+ - Useful for `β€œdefault filters”` or initial settings.
189
+ - Unlike parameters added in links, e.g. `sistema/lista?page=1&page_size=10`, , these load depending on the component (page) being visited, ensuring that the visited page always has default parameters, even if the user removes them. This ensures that **API** calls depending on URL parameters return correct data.
190
+
191
+ 4. **ForceParams**:
192
+
193
+ - Enforce values that cannot be overwritten (e.g. page_size=10).
194
+ - Provides maximum safety while enhancing user experience (avoid page_size=1000).
195
+
196
+ 5. **OmitParamsByValues**:(ParΓ‘metros omitidos por Valores)
197
+
198
+ - A list of values that, if detected, are omitted from the **URL** (e.g. β€˜all’, β€˜default’).
199
+ - Simplifies URLs by removing parameters that do not provide real information.
200
+ - Reserves space for other query parameters given potential URL limitations (depending on the browser in use).
201
+
202
+ 6. **arraySerialization**:
203
+
204
+ - Allows arrays to be serialized in the **URL** through three different methods (csv, repeat, brackets).
205
+ - Enables updating them via two methods: toggle (add or remove) and passing an array of values (e.g. tags: [β€˜new1’, β€˜new2’])
206
+ - Accessible through the **getParams** method to obtain string-type values (e.g. tags=one,two,three) or converted to their original type (e.g. `tags: [β€˜one’, β€˜two’, β€˜three’]`).
207
+
208
+ ## 3 Usage Recommendation with a Constants File πŸ“
209
+
210
+ - Define the required and optional parameters in a single file (e.g. defaultParamsPage.ts).
211
+ - optionally add typing (normally you'll let **typescript** infer)
212
+ - **Beneficios**:
213
+ - **_Greater consistency_**: Everything is centralized, meaning a single source of truth for the parameters of each page.
214
+ - **_Safe typing_**: Guarantees autocomplete and reduces typos.
215
+
216
+ > [!NOTE]
217
+ > This way TypeScript can infer the types of the query parameters and their default values to manag
218
+
219
+ ```typescript
220
+ type UserTagOptions = 'tag1' | 'tag2' | 'react' | 'node' | 'typescript' | 'javascript';
221
+ type OrderUserProps = 'role' | 'date';
222
+ // you can specify the values ​​to help typescript give you more typed
223
+ export const paramsCrimesDashboard = {
224
+ mandatory: {
225
+ days: 7,
226
+ },
227
+ optional: {},
228
+ };
229
+ export const paramsUsers = {
230
+ mandatory: {
231
+ page: 1,
232
+ page_size: 10 as const,
233
+ only_is_active: false,
234
+ },
235
+ optional: {
236
+ order: "" as OrderUserProps;
237
+ search: "",
238
+ tags: ['tag1', 'tag2'] as Array<UserTagOptions>
239
+ },
240
+ };
241
+ ```
242
+
243
+ ## 4 Main Functions βš™οΈ
244
+
245
+ ### 4.1 getParams
246
+
247
+ Retrieves typed parameters from the URL and optionally converts them.
248
+ Useful to pull `β€œpage”, β€œorder”, β€œsearch”`, etc. without dealing with null values or incorrect types.
249
+
250
+ > [!NOTE]
251
+ > By default, the **react-router-dom** `useSearchParams` hook returns parameters as `string`, even if defined with another type (e.g. `number`). The `getParams` method solves this by keeping a reference to their original type.
252
+
253
+ <details>
254
+ <summary>Ejemplo de uso</summary>
255
+
256
+ ```typescript
257
+ // Retrieving converted values
258
+ const { page, search } = getParams({ convert: true });
259
+ const tags = getParam("tags")
260
+ // tags = [tag1, tag2]
261
+
262
+ // Example: displaying parameters in console
263
+ console.log("Current page:", page); // number
264
+ console.log("Search:", search); // string | undefined
265
+ ```
266
+
267
+ </details>
268
+
269
+ ### 4.2 updateParams
270
+
271
+ Safely modifies URL parameters, respecting mandatory values; you may reset one value without losing the rest (e.g. set `page=1` while keeping `search`).
272
+
273
+ <details>
274
+ <summary>Ejemplo de uso</summary>
275
+
276
+ ```typescript
277
+ // Change page and keep the current order
278
+ updateParams({
279
+ newParams: { page: 2 },
280
+ keepParams: { order: true },
281
+ });
282
+
283
+ // Set a new filter and reset the page
284
+ updateParams({ newParams: { page: 1, search: "John" } });
285
+ ```
286
+
287
+ </details>
288
+
289
+ ### 4.3 clearParams
290
+
291
+ Resets the URL parameters, optionally keeping mandatory ones.
292
+ Allows you to β€œclear” the filters and return to the initial state.
293
+ <details> <summary>Ejemplo de uso</summary>
294
+
295
+ ```typescript
296
+ // Clear everything and keep mandatory parameters
297
+ clearParams();
298
+
299
+ // Clear everything, including mandatory parameters
300
+ clearParams({ keepMandatoryParams: false });
301
+ ```
302
+ </details>
303
+
304
+ ### 4.4 onChange
305
+ The `onChange` function allows you to subscribe to changes in specific URL parameters. Each time the parameter changes, the associated callbacks will be executed. This is useful when you need to trigger updates or actions (such as API calls, validations, etc.) after a particular value changes.
306
+
307
+ > [!NOTE]
308
+ > Although you will usually want to call an API or trigger other events as soon as changes are detected in any of the URL parameters (by adding `searchParams` to the dependency array of `useEffect`), there are occasions where you may prefer more granular control and only react to specific parameters.
309
+
310
+
311
+ **Basic use**
312
+ ```jsx
313
+ useEffect(() => {
314
+ function fetchData() {
315
+
316
+ // can be an call to API or any other operation
317
+ return new Promise((resolve) => {
318
+ setTimeout(() => resolve('Information recibed'), 1500)
319
+ })
320
+ }
321
+
322
+ function showData(data: string) {
323
+ alert(`Data recibed: ${data}`)
324
+ }
325
+
326
+ function notifyChange() {
327
+ console.log('Change detected in the parameter search')
328
+ }
329
+
330
+ onChange('search', [
331
+ async () => {
332
+ const data = await fetchData()
333
+ showData(data)
334
+ },
335
+ notifyChange
336
+ ])
337
+ }, [])
338
+ // otr
339
+ ```
340
+
341
+ ### Usage Example & Explanations πŸ–₯οΈπŸ’‘
342
+
343
+ In the following example, we combine:
344
+
345
+ **mandatory**: Needed for pagination.
346
+ **optional**: Search and order parameters.
347
+ **forceParams**: Parameters that must not change
348
+ **omitParamsByValues**: Omits `all` or `default` values.
349
+
350
+ ```jsx
351
+ // filepath: /c:/.../FilterUsers.tsx
352
+ import { useMagicSearchParams } from "@/hooks/UseMagicSearchParams";
353
+ import { paramsUsers } from "@constants/DefaultParamsPage";
354
+
355
+ export const FilterUsers = (props) => {
356
+ const { searchParams, updateParams, clearParams, getParams } =
357
+ useMagicSearchParams({
358
+ ...paramsUsers,
359
+ defaultParams: paramsUsers.mandatory,
360
+ forceParams: { page_size: 1 },
361
+ omitParamsByValues: ["all", "default"],
362
+ });
363
+
364
+ // Retrieve parameters converted to their original types
365
+ const { page, search, order } = getParams({ convert: true });
366
+
367
+
368
+ // Update: set page = 1 and change search
369
+ const handleChangeSearch = (evt) => {
370
+ updateParams({ newParams: { page: 1, search: evt.target.value } });
371
+ };
372
+
373
+ // Clear everything and keep mandatory parameters by default
374
+ const handleReset = () => {
375
+ clearParams();
376
+ };
377
+ const handleChangeOrder = (value) => {
378
+ // if value is equal to 'all' it will be ommited
379
+ updateParams({ newParams: { order: value }, keepParams: { search: false }})
380
+ }
381
+ // ...
382
+ return (
383
+ <>
384
+ {/** rest.. */}
385
+ <select name="order" onChange={e => handleChangeOrder(e)}>
386
+ <option value="all">Select tag</option>
387
+
388
+ {/** map of tags..*/}
389
+ </select>
390
+
391
+ </>
392
+ )
393
+ };
394
+ ```
395
+
396
+ **En este componente:**
397
+
398
+ **_paramsUsers_**: defines the `mandatory` and `optional` objects.
399
+ **_forceParams_**: prevents β€œpage*size” from being changed by the user.
400
+ **_omitParamsByValues**: discards values that do not provide real data (β€œall”, β€œdefault”)
401
+ **_getParams_**: returns typed values (numbers, booleans, strings, etc.).
402
+ **updateParams** and **clearParams** simplify URL update flows.
403
+
404
+ ## 7 SerializaciΓ³n de Arrays en la URL πŸš€
405
+
406
+ The **useMagicSearchParams** hook now allows for advanced and flexible handling of a`array-type parameters`, sending them to the `backend` in the format required. This is done via the **arraySerialization** option, which supports three techniques:
407
+
408
+ ### MΓ©todos de SerializaciΓ³n πŸ”„
409
+
410
+ - **csv**:
411
+ Serializes the array into a single comma-separated string.
412
+ **Ejemplo:**
413
+ `tags=tag1,tag2,tag3`
414
+ Ideal when the backend expects a single string.
415
+
416
+ - **repeat**:
417
+ Sends each array element as a separate parameter.
418
+ **Ejemplo:**
419
+ `tags=tag1&tags=tag2&tags=tag3`
420
+ _Perfect for APIs that handle multiple entries under the same key._
421
+
422
+ - **brackets**:
423
+ Uses bracket notation in the key for each element.
424
+ **Ejemplo:**
425
+ `tags[]=tag1&tags[]=tag2&tags[]=tag3`
426
+ _Useful for frameworks expecting this format (e.g. PHP)._
427
+
428
+ > [!TIP]
429
+ > When extracting `tags` with `getParams({ convert: true })` you get:
430
+ >
431
+ > - **Am String** if not conversion is specified (e.g, csv): `"tags=tag1,tag2,tag3"`
432
+ > - **An Array** if conversion is used: `tags=['tag1', 'tag2', 'tag3']`
433
+ > _This improves consistency and typing in your application._
434
+
435
+ ### dvantages and Benefits 🌟
436
+
437
+ - **Flexible Submission**:
438
+ Choose the method that best suits backend requirements.
439
+ βœ… _Better compatibility with various systems._
440
+
441
+ - **Automatic Normalization**:
442
+ Keys arriving `tags[]` format normalize to `tags` to simplify handling.
443
+ βœ… _Easier iteration and conversion to original types._
444
+
445
+ - **Full URL Control**:
446
+ The hook consistently manages URL rewriting, reducing errors and keeping it readable.
447
+ πŸ”’ _Improves parameter security and control._
448
+
449
+ ### Code Usage Examples πŸ‘¨β€πŸ’»
450
+
451
+ ```jsx
452
+ import { useMagicSearchParams } from "useMagicSearchParams";
453
+ import { paramsUsers } from "../src/constants/defaulParamsPage";
454
+
455
+ export default function App() {
456
+ const { searchParams, getParams, updateParams, clearParams } = useMagicSearchParams({
457
+ ...paramsUsers,
458
+ defaultParams: paramsUsers.mandatory,
459
+ arraySerialization: 'repeat', // You can switch to 'csv' or 'brackets' as needed.
460
+ omitParamsByValues: ["all", "default"],
461
+ });
462
+
463
+ // Get converted parameters (for example, tags is retrieved as an array)
464
+ const { tags, page } = getParams({ convert: true });
465
+
466
+ const availableTags = ['react', 'node', 'typescript', 'javascript'];
467
+
468
+ // Example: Update the tags array with toggle
469
+ const handleTagToggle = (newTag: string) => {
470
+ // if it exists, remove it; otherwise, add it
471
+ updateParams({ newParams: { tags: newTag } });
472
+ };
473
+
474
+ // Pass an array of tags, useful for adding multiple filters at once
475
+ const handleTagToggleArray = (newTags: string[]) => {
476
+ // the hook ensures no duplicates by merging with existing ones
477
+ updateParams({ newParams: { tags: [...tags, ...newTags] } });
478
+ };
479
+
480
+ return (
481
+ <div>
482
+ <div>
483
+ <h3 className='text-lg font-semibold mb-3'>Select Tags:</h3>
484
+ {availableTags.map(tag => {
485
+ const isActive = Array.isArray(tags) && tags.includes(tag);
486
+ return (
487
+ <button
488
+ key={tag}
489
+ onClick={() => handleTagToggle(tag)}
490
+ className={`px-4 py-2 rounded-md border ${
491
+ isActive ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-700'
492
+ }`}
493
+ >
494
+ {tag}
495
+ </button>
496
+ );
497
+ })}
498
+ </div>
499
+ <p>Current tags: {JSON.stringify(tags)}</p>
500
+ {/* Rest of the component */}
501
+ </div>
502
+ );
503
+ }
504
+ ```
505
+
506
+ In this example, when using **repeat** serialization the `URL` result look like this:
507
+
508
+ - **(repeat) Mode**: `?page=1&page_size=10&only_is_active=false&tags=tag1&tags=tag2&tags=tag3`
509
+ - **(csv) Mode**: `?page=1&page_size=10&only_is_active=false&tags=tag1,tag2,tag3`
510
+ - **(brackets) Mode**: `?page=1&page_size=10&only_is_active=false&tags[]=tag1&tags[]=tag2&tags[]=tag3`
511
+
512
+ ### This new functionality allows you to:
513
+
514
+ - Send arrays in a format that matches backend expectations.
515
+ - Centrally manage conversion and serialization, reducing complexity in individual components.
516
+ - Keep the URL clean and consistent, no matter which serialization method you choose.
517
+ - **Provide total control to the developer**: On how to transform or send parameters, allowing custom operations based on the backend.
518
+
519
+ ### Why Is This Functionality Key? 🎯
520
+
521
+ - **Adaptable array submission to the backend:**
522
+ Fits various formats servers may expect.
523
+ - **Reduced complexity in components:**
524
+ Centralizes serialization logic, preventing code duplication.
525
+ - **Better user experience:**
526
+ A clean, consistent URL makes debugging easier and improves usability.
527
+
528
+ ## 8 Best Practices and Considerations βœ…
529
+
530
+ 1. **Validate sensitive parameters in the backend**: Even though the hook protects on the frontend, the server must enforce its own limits.
531
+ 2. **Keep types updated:**: As requirements change, update `mandatory` and `optional` to avoid mismatches.
532
+ 3. **One constants file per view**: Helps organize each screen or section, keeping clarity and consistency.
533
+
534
+ ---
535
+
536
+ ## 9 Unit Tests πŸ”¬
537
+
538
+ This project includes automated tests to ensure its robustness and reliability.
539
+
540
+ ### Run your tests with **Vitest** πŸ§ͺ
541
+
542
+ To validate this hook (and others), go to the test directory and run the following command in your terminal:
543
+
544
+ ```bash
545
+ npm run test ./test/useMagicSearchParams.test.ts
546
+ ```
547
+
548
+ > [!WARNING]
549
+ > Note: Make sure you have Vitest configured in your project so these tests can run correctly; you can check the version with `npm list`
550
+
551
+ ## 10 Conclusion πŸŽ‰
552
+
553
+ The `useMagicSearchParams` hook provides:
554
+
555
+ - **Readability and Maintainability**: By centralizing logic:
556
+ - **Robustess**: in parameter management, limiting insecure values and enabling a coherent flow.
557
+
558
+ It’s recommended to adjust or expand it based on each project’s needs, for example by adding advanced validations or additional type conversions.
559
+
560
+ ---
561
+
562
+ <div align="center">
563
+ <img src="https://github.com/user-attachments/assets/acd13a47-dcd3-488c-b0be-69ce466bb106" alt="Captura de pantalla" width="500px" />
564
+ </div>
@@ -0,0 +1,12 @@
1
+ export declare const paramsUsers: {
2
+ mandatory: {
3
+ page: number;
4
+ page_size: 10;
5
+ only_is_active: boolean;
6
+ tags: unknown[];
7
+ };
8
+ optional: {
9
+ order: string;
10
+ search: string;
11
+ };
12
+ };
@@ -0,0 +1 @@
1
+ export { useMagicSearchParams } from './useMagicSearchParams';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+
2
+ 'use strict'
3
+
4
+ if (process.env.NODE_ENV === 'production') {
5
+ module.exports = require('./react-magic-search-params.cjs.production.min.js')
6
+ } else {
7
+ module.exports = require('./react-magic-search-params.cjs.development.js')
8
+ }