@toniel/laravel-tanstack-pagination 0.1.0 → 0.1.2

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 Toniel
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 CHANGED
@@ -1,23 +1,51 @@
1
1
  # Laravel TanStack Pagination
2
2
 
3
- Vue 3 composables untuk Laravel pagination dengan TanStack Query.
3
+ [![npm version](https://img.shields.io/npm/v/@toniel/laravel-tanstack-pagination)](https://www.npmjs.com/package/@toniel/laravel-tanstack-pagination)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@toniel/laravel-tanstack-pagination)](https://www.npmjs.com/package/@toniel/laravel-tanstack-pagination)
5
+ [![GitHub](https://img.shields.io/github/license/toniel/laravel-tanstack-pagination)](https://github.com/toniel/laravel-tanstack-pagination/blob/main/LICENSE)
6
+ [![GitHub stars](https://img.shields.io/github/stars/toniel/laravel-tanstack-pagination)](https://github.com/toniel/laravel-tanstack-pagination)
4
7
 
5
- ## Installation
8
+ Vue 3 composables untuk Laravel pagination dengan TanStack Query - **Headless & Framework Agnostic**.
9
+
10
+ > 💡 **Looking for ready-to-use UI components?** Check out [`@toniel/laravel-tanstack-datatable`](https://github.com/toniel/laravel-tanstack-datatable) - Pre-built DataTable components with this library.
11
+
12
+ ## 📦 Installation
6
13
 
7
14
  ```bash
8
15
  npm install @toniel/laravel-tanstack-pagination
16
+ # or
17
+ yarn add @toniel/laravel-tanstack-pagination
18
+ # or
19
+ pnpm add @toniel/laravel-tanstack-pagination
20
+ # or
21
+ bun add @toniel/laravel-tanstack-pagination
9
22
  ```
10
23
 
11
- ## Usage
24
+ ### Peer Dependencies
25
+
26
+ ```bash
27
+ npm install vue @tanstack/vue-query
28
+ ```
29
+
30
+ ## 🚀 Quick Start
12
31
 
13
32
  ```typescript
14
33
  import { usePagination } from '@toniel/laravel-tanstack-pagination'
34
+ import axios from 'axios'
15
35
 
16
36
  const {
17
37
  tableData,
18
38
  pagination,
39
+ search,
40
+ currentPerPage,
41
+ sortBy,
42
+ sortDirection,
43
+ isLoading,
44
+ error,
19
45
  handlePageChange,
20
- handleSearchChange
46
+ handlePerPageChange,
47
+ handleSearchChange,
48
+ handleSortChange,
21
49
  } = usePagination(
22
50
  (filters) => axios.get('/api/users', { params: filters }),
23
51
  {
@@ -27,47 +55,456 @@ const {
27
55
  )
28
56
  ```
29
57
 
30
- ## Features
58
+ ## Features
31
59
 
32
- - ✅ Laravel pagination support
33
- - ✅ TanStack Query integration
34
- - ✅ Search with debounce
35
- - ✅ Sorting
36
- - ✅ Table numbering helper
37
- - ✅ TypeScript support
60
+ - ✅ **Headless** - Bring your own UI components
61
+ - ✅ **Laravel pagination** support out of the box
62
+ - ✅ **TanStack Query** integration for caching & refetching
63
+ - ✅ **Search** with automatic debounce
64
+ - ✅ **Sorting** (server-side)
65
+ - ✅ **Filtering** with flexible API
66
+ - ✅ **Table numbering** helper for sequential row numbers
67
+ - ✅ **TypeScript** fully typed
68
+ - ✅ **Framework agnostic** - Works with any UI library
38
69
 
39
- ## API
70
+ ## 📖 API Reference
40
71
 
41
72
  ### `usePagination(fetchFn, options)`
42
73
 
43
74
  Main composable for handling Laravel pagination.
44
75
 
45
76
  **Parameters:**
46
- - `fetchFn`: Function that fetches data from Laravel API
47
- - `options`: Configuration options
48
- - `queryKey`: Unique key for the query
49
- - `defaultPerPage`: Items per page (default: 10)
77
+ - `fetchFn`: `(filters: PaginationFilters) => Promise<LaravelPaginationResponse<T>>`
78
+ - Function that fetches data from Laravel API
79
+ - `options`: `UsePaginationOptions<T>`
80
+ - `queryKey`: `string` - Unique key for the query (required)
81
+ - `defaultPerPage`: `number` - Items per page (default: `10`)
82
+ - `defaultSearch`: `string` - Default search query (default: `''`)
83
+ - `defaultSort`: `SortState` - Default sort state (default: `null`)
84
+ - ...all other TanStack Query options
50
85
 
51
86
  **Returns:**
52
- - `tableData`: Computed array of data items
53
- - `pagination`: Reactive pagination state
54
- - `handlePageChange`: Function to change page
55
- - `handleSearchChange`: Function to handle search input
56
- - `handleSortChange`: Function to handle sorting
57
- - `isLoading`: Loading state
58
- - `error`: Error state
59
87
 
60
- ### `useTableNumbering(currentPage, perPage)`
88
+ | Property | Type | Description |
89
+ |----------|------|-------------|
90
+ | `tableData` | `Ref<T[]>` | Computed array of data items |
91
+ | `pagination` | `Ref<LaravelPaginationResponse \| null>` | Full Laravel pagination response |
92
+ | `currentPage` | `Ref<number>` | Current page number |
93
+ | `perPage` | `Ref<number>` | Items per page |
94
+ | `search` | `Ref<string>` | Current search query |
95
+ | `sortBy` | `Ref<string \| null>` | Current sort column |
96
+ | `sortDirection` | `Ref<'asc' \| 'desc'>` | Sort direction |
97
+ | `filters` | `ComputedRef<PaginationFilters>` | All active filters (including custom filters) |
98
+ | `customFilters` | `Ref<Record<string, any>>` | Custom filter state (for external use) |
99
+ | `isLoading` | `Ref<boolean>` | Loading state from TanStack Query |
100
+ | `error` | `Ref<Error \| null>` | Error state from TanStack Query |
101
+ | `handlePageChange` | `(page: number) => void` | Change page handler |
102
+ | `handlePerPageChange` | `(perPage: number) => void` | Change per page handler |
103
+ | `handleSearchChange` | `(search: string) => void` | Search change handler (debounced) |
104
+ | `handleSortChange` | `(column: string) => void` | Toggle sort on column |
105
+ | `handleFilterChange` | `(filters: Record<string, any>) => void` | Bulk update custom filters |
106
+ | `setFilter` | `(key: string, value: any) => void` | Add custom filter |
107
+ | `removeFilter` | `(key: string) => void` | Remove custom filter |
108
+ | `resetFilters` | `() => void` | Reset all filters to defaults |
109
+ | `getNumberingColumn` | `(options?) => ColumnDef` | Get numbering column for TanStack Table |
110
+ | `refetch` | TanStack Query refetch function |
111
+ | `...queryResult` | All other TanStack Query return values |
61
112
 
62
- Helper composable for table row numbering.
113
+ ### `useTableNumbering()`
63
114
 
64
- **Parameters:**
65
- - `currentPage`: Current page number
66
- - `perPage`: Items per page
115
+ Helper composable for creating table row numbering columns.
67
116
 
68
117
  **Returns:**
69
- - `getRowNumber(index)`: Function to get row number for index
118
+ - `createNumberingColumn(pagination, perPage, options?)`: Function to create a numbering column definition for TanStack Table
119
+
120
+ **Example:**
121
+ ```ts
122
+ const { createNumberingColumn } = useTableNumbering()
123
+
124
+ const numberingColumn = createNumberingColumn(
125
+ pagination, // ref from usePagination
126
+ perPage, // ref from usePagination
127
+ {
128
+ header: '#',
129
+ enableSorting: false
130
+ }
131
+ )
132
+ ```
133
+
134
+ ## 🔗 TypeScript Types
135
+
136
+ ```typescript
137
+ // Laravel Pagination Response
138
+ type LaravelPaginationResponse<T = any> = {
139
+ data: T[]
140
+ links: {
141
+ first: string | null
142
+ last: string | null
143
+ next: string | null
144
+ prev: string | null
145
+ }[]
146
+ meta: {
147
+ current_page: number
148
+ from: number
149
+ last_page: number
150
+ links: Array<{
151
+ url: string | null
152
+ label: string
153
+ active: boolean
154
+ }>
155
+ path: string
156
+ per_page: number
157
+ to: number
158
+ total: number
159
+ }
160
+ }
161
+
162
+ // Pagination Filters
163
+ interface PaginationFilters {
164
+ page?: number
165
+ per_page?: number
166
+ search?: string
167
+ [key: string]: any // Custom filters
168
+ }
169
+
170
+ // Sort State
171
+ interface SortState {
172
+ column: string | null
173
+ direction: 'asc' | 'desc'
174
+ }
175
+ ```
176
+
177
+ ## 🎯 Usage with UI Libraries
178
+
179
+ ### With Custom Table Component
180
+
181
+ ```vue
182
+ <template>
183
+ <div>
184
+ <!-- Search -->
185
+ <input v-model="search" @input="handleSearchChange" />
186
+
187
+ <!-- Table -->
188
+ <table>
189
+ <thead>
190
+ <tr>
191
+ <th @click="handleSortChange('name')">Name</th>
192
+ <th @click="handleSortChange('email')">Email</th>
193
+ </tr>
194
+ </thead>
195
+ <tbody>
196
+ <tr v-for="user in tableData" :key="user.id">
197
+ <td>{{ user.name }}</td>
198
+ <td>{{ user.email }}</td>
199
+ </tr>
200
+ </tbody>
201
+ </table>
202
+
203
+ <!-- Pagination -->
204
+ <button
205
+ :disabled="pagination?.meta.current_page === 1"
206
+ @click="handlePageChange(pagination.meta.current_page - 1)"
207
+ >
208
+ Previous
209
+ </button>
210
+ <span>Page {{ pagination?.meta.current_page }} of {{ pagination?.meta.last_page }}</span>
211
+ <button
212
+ :disabled="pagination?.meta.current_page === pagination?.meta.last_page"
213
+ @click="handlePageChange(pagination.meta.current_page + 1)"
214
+ >
215
+ Next
216
+ </button>
217
+ </div>
218
+ </template>
219
+ ```
220
+
221
+ ### With TanStack Table
222
+
223
+ ```vue
224
+ <script setup lang="ts">
225
+ import { usePagination } from '@toniel/laravel-tanstack-pagination'
226
+ import { createColumnHelper, FlexRender, getCoreRowModel, useVueTable } from '@tanstack/vue-table'
227
+
228
+ const columnHelper = createColumnHelper<User>()
229
+
230
+ const {
231
+ tableData,
232
+ pagination,
233
+ perPage,
234
+ getNumberingColumn,
235
+ // ... other returns
236
+ } = usePagination(fetchUsers, { queryKey: 'users' })
237
+
238
+ const columns = [
239
+ getNumberingColumn({ header: '#' }),
240
+ columnHelper.accessor('name', { header: 'Name' }),
241
+ columnHelper.accessor('email', { header: 'Email' }),
242
+ ]
243
+
244
+ const table = useVueTable({
245
+ get data() { return tableData.value },
246
+ columns,
247
+ getCoreRowModel: getCoreRowModel(),
248
+ })
249
+ </script>
250
+ ```
251
+
252
+ ### With Shadcn-vue or Radix-vue
253
+
254
+ For ready-to-use DataTable component with shadcn-vue styling, use:
255
+
256
+ ```bash
257
+ npm install @toniel/laravel-tanstack-datatable
258
+ ```
259
+
260
+ See: https://www.npmjs.com/package/@toniel/laravel-tanstack-datatable
261
+
262
+ ## 🔍 Filtering
263
+
264
+ The `usePagination` composable provides comprehensive filter management with proper state persistence across page changes.
265
+
266
+ ### Single Filter Operations
267
+
268
+ ```typescript
269
+ const {
270
+ setFilter,
271
+ removeFilter,
272
+ customFilters,
273
+ refetch,
274
+ } = usePagination(fetchFn, { queryKey: 'users' })
275
+
276
+ // Set a single filter
277
+ setFilter('status', 'active')
278
+ setFilter('category', 'A')
279
+
280
+ // Remove a filter
281
+ removeFilter('status')
282
+
283
+ // The query will automatically refetch when filters change
284
+ ```
285
+
286
+ ### Bulk Filter Operations
287
+
288
+ ```typescript
289
+ const {
290
+ handleFilterChange,
291
+ customFilters,
292
+ refetch,
293
+ } = usePagination(fetchFn, { queryKey: 'users' })
294
+
295
+ // Bulk update multiple filters at once
296
+ handleFilterChange({
297
+ status: 'active',
298
+ category: 'A',
299
+ year: '2024'
300
+ })
301
+
302
+ // Or pass partial updates (will merge with existing)
303
+ handleFilterChange({
304
+ ...customFilters.value,
305
+ status: 'inactive'
306
+ })
307
+ ```
308
+
309
+ ### Filter State Persistence
310
+
311
+ Custom filters are properly included in the TanStack Query cache key, ensuring:
312
+ - Filters persist when changing pages
313
+ - Filters persist when changing per page
314
+ - Correct cache invalidation on filter changes
315
+ - Back/forward navigation works correctly
316
+
317
+ ```typescript
318
+ // Filters are automatically included in queryKey
319
+ const { filters } = usePagination(fetchFn, { queryKey: 'users' })
320
+
321
+ // filters.value = { page: 1, per_page: 10, search: '', status: 'active', category: 'A' }
322
+ ```
323
+
324
+ ### Reset Filters
325
+
326
+ ```typescript
327
+ const {
328
+ resetFilters,
329
+ customFilters,
330
+ search,
331
+ perPage,
332
+ } = usePagination(fetchFn, { queryKey: 'users', defaultPerPage: 20 })
333
+
334
+ // Reset all filters to defaults
335
+ resetFilters()
336
+
337
+ // After reset:
338
+ // - customFilters = {}
339
+ // - search = ''
340
+ // - perPage = 20
341
+ // - page = 1
342
+ ```
343
+
344
+ ### Example: Complex Filter Form
345
+
346
+ ```typescript
347
+ <script setup lang="ts">
348
+ import { ref, computed } from 'vue'
349
+ import { usePagination } from '@toniel/laravel-tanstack-pagination'
350
+
351
+ // Filter form state (separate from composable)
352
+ const filterForm = ref({
353
+ status: '',
354
+ category: '',
355
+ year: new Date().getFullYear().toString(),
356
+ month: '',
357
+ })
358
+
359
+ const {
360
+ tableData,
361
+ pagination,
362
+ customFilters,
363
+ setFilter,
364
+ removeFilter,
365
+ handlePageChange,
366
+ refetch,
367
+ } = usePagination(
368
+ (filters) => axios.get('/api/transactions', { params: filters }),
369
+ { queryKey: 'transactions', defaultPerPage: 20 }
370
+ )
371
+
372
+ // Apply filters
373
+ const applyFilters = () => {
374
+ // Clear existing custom filters first
375
+ if (filterForm.value.status) {
376
+ setFilter('status', filterForm.value.status)
377
+ } else {
378
+ removeFilter('status')
379
+ }
380
+
381
+ if (filterForm.value.category) {
382
+ setFilter('category', filterForm.value.category)
383
+ } else {
384
+ removeFilter('category')
385
+ }
386
+
387
+ if (filterForm.value.year) {
388
+ setFilter('year', filterForm.value.year)
389
+ } else {
390
+ removeFilter('year')
391
+ }
392
+
393
+ if (filterForm.value.month) {
394
+ setFilter('month', filterForm.value.month)
395
+ } else {
396
+ removeFilter('month')
397
+ }
398
+
399
+ refetch()
400
+ }
401
+
402
+ // Clear all filters
403
+ const clearFilters = () => {
404
+ filterForm.value = { status: '', category: '', year: new Date().getFullYear().toString(), month: '' }
405
+ removeFilter('status')
406
+ removeFilter('category')
407
+ removeFilter('year')
408
+ removeFilter('month')
409
+ refetch()
410
+ }
411
+ </script>
412
+ ```
413
+
414
+ ## 🔧 Laravel Backend Setup
415
+
416
+ Your Laravel API should return paginated responses in this format:
417
+
418
+ ```php
419
+ // UserController.php
420
+ public function index(Request $request)
421
+ {
422
+ $query = User::query();
423
+
424
+ // Search
425
+ if ($request->has('search')) {
426
+ $query->where('name', 'like', "%{$request->search}%")
427
+ ->orWhere('email', 'like', "%{$request->search}%");
428
+ }
429
+
430
+ // Sorting (format: sort[column]=direction)
431
+ foreach ($request->all() as $key => $value) {
432
+ if (str_starts_with($key, 'sort[')) {
433
+ preg_match('/sort\[(.*?)\]/', $key, $matches);
434
+ $column = $matches[1] ?? null;
435
+ if ($column) {
436
+ $query->orderBy($column, $value);
437
+ }
438
+ }
439
+ }
440
+
441
+ // Paginate
442
+ $perPage = $request->input('per_page', 10);
443
+ return $query->paginate($perPage);
444
+ }
445
+ ```
446
+
447
+ The response will automatically be in the correct format:
448
+ ```json
449
+ {
450
+ "data": [...],
451
+ "links": {...},
452
+ "meta": {
453
+ "current_page": 1,
454
+ "from": 1,
455
+ "to": 10,
456
+ "total": 100,
457
+ "per_page": 10,
458
+ "last_page": 10
459
+ }
460
+ }
461
+ ```
462
+
463
+ ## 🔗 Related Packages
464
+
465
+ - [`@toniel/laravel-tanstack-datatable`](https://github.com/toniel/laravel-tanstack-datatable) - Pre-built DataTable components
466
+ - [`@tanstack/vue-query`](https://tanstack.com/query/latest/docs/vue/overview) - Data fetching & caching library
467
+ - [`@tanstack/vue-table`](https://tanstack.com/table/latest/docs/framework/vue/vue-table) - Headless table library
468
+
469
+ ## 🌟 Show Your Support
470
+
471
+ If this package helped you, please consider:
472
+ - ⭐ Starring the [GitHub repository](https://github.com/toniel/laravel-tanstack-pagination)
473
+ - 🐛 [Reporting bugs](https://github.com/toniel/laravel-tanstack-pagination/issues)
474
+ - 💡 [Suggesting new features](https://github.com/toniel/laravel-tanstack-pagination/issues)
475
+ - 🔧 [Contributing code](https://github.com/toniel/laravel-tanstack-pagination/pulls)
476
+
477
+ ## 📄 License
478
+
479
+ [MIT](https://github.com/toniel/laravel-tanstack-pagination/blob/main/LICENSE) © [Toniel](https://github.com/toniel)
480
+
481
+ ## 🤝 Contributing
482
+
483
+ Contributions, issues and feature requests are welcome!
484
+
485
+ 1. Fork the repository
486
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
487
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
488
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
489
+ 5. Open a Pull Request
490
+
491
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
492
+
493
+ ## 📮 Contact
494
+
495
+ - GitHub: [@toniel](https://github.com/toniel)
496
+ - NPM: [@toniel](https://www.npmjs.com/~toniel)
497
+
498
+ ## 🙏 Acknowledgments
499
+
500
+ Built with these amazing libraries:
501
+ - [Vue 3](https://vuejs.org/)
502
+ - [TanStack Query](https://tanstack.com/query/latest)
503
+ - [Laravel](https://laravel.com/)
504
+
505
+ ---
70
506
 
71
- ## License
507
+ <div align="center">
508
+ Made with ❤️ by <a href="https://github.com/toniel">Toniel</a>
509
+ </div>
72
510
 
73
- MIT
package/dist/index.d.mts CHANGED
@@ -52,6 +52,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
52
52
  handlePerPageChange: (newPerPage: number) => void;
53
53
  handleSearchChange: (newSearch: string) => void;
54
54
  handleSortChange: (column: string) => void;
55
+ handleFilterChange: (newFilters: Record<string, any>) => void;
55
56
  resetFilters: () => void;
56
57
  setFilter: (key: string, value: any) => void;
57
58
  removeFilter: (key: string) => void;
@@ -101,6 +102,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
101
102
  sortBy: vue.Ref<string | null, string | null>;
102
103
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
103
104
  filters: vue.ComputedRef<PaginationFilters>;
105
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
104
106
  } | {
105
107
  tableData: vue.ComputedRef<T[]>;
106
108
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -108,6 +110,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
108
110
  handlePerPageChange: (newPerPage: number) => void;
109
111
  handleSearchChange: (newSearch: string) => void;
110
112
  handleSortChange: (column: string) => void;
113
+ handleFilterChange: (newFilters: Record<string, any>) => void;
111
114
  resetFilters: () => void;
112
115
  setFilter: (key: string, value: any) => void;
113
116
  removeFilter: (key: string) => void;
@@ -157,6 +160,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
157
160
  sortBy: vue.Ref<string | null, string | null>;
158
161
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
159
162
  filters: vue.ComputedRef<PaginationFilters>;
163
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
160
164
  } | {
161
165
  tableData: vue.ComputedRef<T[]>;
162
166
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -164,6 +168,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
164
168
  handlePerPageChange: (newPerPage: number) => void;
165
169
  handleSearchChange: (newSearch: string) => void;
166
170
  handleSortChange: (column: string) => void;
171
+ handleFilterChange: (newFilters: Record<string, any>) => void;
167
172
  resetFilters: () => void;
168
173
  setFilter: (key: string, value: any) => void;
169
174
  removeFilter: (key: string) => void;
@@ -213,6 +218,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
213
218
  sortBy: vue.Ref<string | null, string | null>;
214
219
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
215
220
  filters: vue.ComputedRef<PaginationFilters>;
221
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
216
222
  } | {
217
223
  tableData: vue.ComputedRef<T[]>;
218
224
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -220,6 +226,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
220
226
  handlePerPageChange: (newPerPage: number) => void;
221
227
  handleSearchChange: (newSearch: string) => void;
222
228
  handleSortChange: (column: string) => void;
229
+ handleFilterChange: (newFilters: Record<string, any>) => void;
223
230
  resetFilters: () => void;
224
231
  setFilter: (key: string, value: any) => void;
225
232
  removeFilter: (key: string) => void;
@@ -269,6 +276,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
269
276
  sortBy: vue.Ref<string | null, string | null>;
270
277
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
271
278
  filters: vue.ComputedRef<PaginationFilters>;
279
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
272
280
  } | {
273
281
  tableData: vue.ComputedRef<T[]>;
274
282
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -276,6 +284,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
276
284
  handlePerPageChange: (newPerPage: number) => void;
277
285
  handleSearchChange: (newSearch: string) => void;
278
286
  handleSortChange: (column: string) => void;
287
+ handleFilterChange: (newFilters: Record<string, any>) => void;
279
288
  resetFilters: () => void;
280
289
  setFilter: (key: string, value: any) => void;
281
290
  removeFilter: (key: string) => void;
@@ -325,6 +334,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
325
334
  sortBy: vue.Ref<string | null, string | null>;
326
335
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
327
336
  filters: vue.ComputedRef<PaginationFilters>;
337
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
328
338
  } | {
329
339
  tableData: vue.ComputedRef<T[]>;
330
340
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -332,6 +342,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
332
342
  handlePerPageChange: (newPerPage: number) => void;
333
343
  handleSearchChange: (newSearch: string) => void;
334
344
  handleSortChange: (column: string) => void;
345
+ handleFilterChange: (newFilters: Record<string, any>) => void;
335
346
  resetFilters: () => void;
336
347
  setFilter: (key: string, value: any) => void;
337
348
  removeFilter: (key: string) => void;
@@ -381,6 +392,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
381
392
  sortBy: vue.Ref<string | null, string | null>;
382
393
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
383
394
  filters: vue.ComputedRef<PaginationFilters>;
395
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
384
396
  };
385
397
 
386
398
  interface NumberingOptions {
package/dist/index.d.ts CHANGED
@@ -52,6 +52,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
52
52
  handlePerPageChange: (newPerPage: number) => void;
53
53
  handleSearchChange: (newSearch: string) => void;
54
54
  handleSortChange: (column: string) => void;
55
+ handleFilterChange: (newFilters: Record<string, any>) => void;
55
56
  resetFilters: () => void;
56
57
  setFilter: (key: string, value: any) => void;
57
58
  removeFilter: (key: string) => void;
@@ -101,6 +102,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
101
102
  sortBy: vue.Ref<string | null, string | null>;
102
103
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
103
104
  filters: vue.ComputedRef<PaginationFilters>;
105
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
104
106
  } | {
105
107
  tableData: vue.ComputedRef<T[]>;
106
108
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -108,6 +110,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
108
110
  handlePerPageChange: (newPerPage: number) => void;
109
111
  handleSearchChange: (newSearch: string) => void;
110
112
  handleSortChange: (column: string) => void;
113
+ handleFilterChange: (newFilters: Record<string, any>) => void;
111
114
  resetFilters: () => void;
112
115
  setFilter: (key: string, value: any) => void;
113
116
  removeFilter: (key: string) => void;
@@ -157,6 +160,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
157
160
  sortBy: vue.Ref<string | null, string | null>;
158
161
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
159
162
  filters: vue.ComputedRef<PaginationFilters>;
163
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
160
164
  } | {
161
165
  tableData: vue.ComputedRef<T[]>;
162
166
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -164,6 +168,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
164
168
  handlePerPageChange: (newPerPage: number) => void;
165
169
  handleSearchChange: (newSearch: string) => void;
166
170
  handleSortChange: (column: string) => void;
171
+ handleFilterChange: (newFilters: Record<string, any>) => void;
167
172
  resetFilters: () => void;
168
173
  setFilter: (key: string, value: any) => void;
169
174
  removeFilter: (key: string) => void;
@@ -213,6 +218,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
213
218
  sortBy: vue.Ref<string | null, string | null>;
214
219
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
215
220
  filters: vue.ComputedRef<PaginationFilters>;
221
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
216
222
  } | {
217
223
  tableData: vue.ComputedRef<T[]>;
218
224
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -220,6 +226,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
220
226
  handlePerPageChange: (newPerPage: number) => void;
221
227
  handleSearchChange: (newSearch: string) => void;
222
228
  handleSortChange: (column: string) => void;
229
+ handleFilterChange: (newFilters: Record<string, any>) => void;
223
230
  resetFilters: () => void;
224
231
  setFilter: (key: string, value: any) => void;
225
232
  removeFilter: (key: string) => void;
@@ -269,6 +276,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
269
276
  sortBy: vue.Ref<string | null, string | null>;
270
277
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
271
278
  filters: vue.ComputedRef<PaginationFilters>;
279
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
272
280
  } | {
273
281
  tableData: vue.ComputedRef<T[]>;
274
282
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -276,6 +284,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
276
284
  handlePerPageChange: (newPerPage: number) => void;
277
285
  handleSearchChange: (newSearch: string) => void;
278
286
  handleSortChange: (column: string) => void;
287
+ handleFilterChange: (newFilters: Record<string, any>) => void;
279
288
  resetFilters: () => void;
280
289
  setFilter: (key: string, value: any) => void;
281
290
  removeFilter: (key: string) => void;
@@ -325,6 +334,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
325
334
  sortBy: vue.Ref<string | null, string | null>;
326
335
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
327
336
  filters: vue.ComputedRef<PaginationFilters>;
337
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
328
338
  } | {
329
339
  tableData: vue.ComputedRef<T[]>;
330
340
  pagination: vue.ComputedRef<LaravelPaginationResponse<T> | null>;
@@ -332,6 +342,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
332
342
  handlePerPageChange: (newPerPage: number) => void;
333
343
  handleSearchChange: (newSearch: string) => void;
334
344
  handleSortChange: (column: string) => void;
345
+ handleFilterChange: (newFilters: Record<string, any>) => void;
335
346
  resetFilters: () => void;
336
347
  setFilter: (key: string, value: any) => void;
337
348
  removeFilter: (key: string) => void;
@@ -381,6 +392,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
381
392
  sortBy: vue.Ref<string | null, string | null>;
382
393
  sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
383
394
  filters: vue.ComputedRef<PaginationFilters>;
395
+ customFilters: vue.Ref<Record<string, any>, Record<string, any>>;
384
396
  };
385
397
 
386
398
  interface NumberingOptions {
package/dist/index.js CHANGED
@@ -103,11 +103,13 @@ function usePagination(fetchFn, options) {
103
103
  const search = (0, import_vue2.ref)(options.defaultSearch || "");
104
104
  const sortBy = (0, import_vue2.ref)(options.defaultSort?.column || null);
105
105
  const sortDirection = (0, import_vue2.ref)(options.defaultSort?.direction || "asc");
106
+ const customFilters = (0, import_vue2.ref)({});
106
107
  const filters = (0, import_vue2.computed)(() => {
107
108
  const baseFilters = {
108
109
  page: currentPage.value,
109
110
  per_page: perPage.value,
110
- search: search.value
111
+ search: search.value,
112
+ ...customFilters.value
111
113
  };
112
114
  if (sortBy.value) {
113
115
  baseFilters[`sort[${sortBy.value}]`] = sortDirection.value;
@@ -143,11 +145,15 @@ function usePagination(fetchFn, options) {
143
145
  currentPage.value = 1;
144
146
  };
145
147
  const setFilter = (key, value) => {
146
- filters.value[key] = value;
148
+ customFilters.value[key] = value;
147
149
  currentPage.value = 1;
148
150
  };
149
151
  const removeFilter = (key) => {
150
- delete filters.value[key];
152
+ delete customFilters.value[key];
153
+ currentPage.value = 1;
154
+ };
155
+ const handleFilterChange = (newFilters) => {
156
+ customFilters.value = { ...newFilters };
151
157
  currentPage.value = 1;
152
158
  };
153
159
  const resetFilters = () => {
@@ -156,6 +162,7 @@ function usePagination(fetchFn, options) {
156
162
  search.value = options.defaultSearch || "";
157
163
  sortBy.value = options.defaultSort?.column || null;
158
164
  sortDirection.value = options.defaultSort?.direction || "asc";
165
+ customFilters.value = {};
159
166
  };
160
167
  let searchTimeout;
161
168
  (0, import_vue2.watch)(search, () => {
@@ -176,6 +183,7 @@ function usePagination(fetchFn, options) {
176
183
  sortBy,
177
184
  sortDirection,
178
185
  filters,
186
+ customFilters,
179
187
  // Query result
180
188
  ...queryResult,
181
189
  // Computed
@@ -186,6 +194,7 @@ function usePagination(fetchFn, options) {
186
194
  handlePerPageChange,
187
195
  handleSearchChange,
188
196
  handleSortChange,
197
+ handleFilterChange,
189
198
  resetFilters,
190
199
  setFilter,
191
200
  removeFilter,
package/dist/index.mjs CHANGED
@@ -76,11 +76,13 @@ function usePagination(fetchFn, options) {
76
76
  const search = ref(options.defaultSearch || "");
77
77
  const sortBy = ref(options.defaultSort?.column || null);
78
78
  const sortDirection = ref(options.defaultSort?.direction || "asc");
79
+ const customFilters = ref({});
79
80
  const filters = computed(() => {
80
81
  const baseFilters = {
81
82
  page: currentPage.value,
82
83
  per_page: perPage.value,
83
- search: search.value
84
+ search: search.value,
85
+ ...customFilters.value
84
86
  };
85
87
  if (sortBy.value) {
86
88
  baseFilters[`sort[${sortBy.value}]`] = sortDirection.value;
@@ -116,11 +118,15 @@ function usePagination(fetchFn, options) {
116
118
  currentPage.value = 1;
117
119
  };
118
120
  const setFilter = (key, value) => {
119
- filters.value[key] = value;
121
+ customFilters.value[key] = value;
120
122
  currentPage.value = 1;
121
123
  };
122
124
  const removeFilter = (key) => {
123
- delete filters.value[key];
125
+ delete customFilters.value[key];
126
+ currentPage.value = 1;
127
+ };
128
+ const handleFilterChange = (newFilters) => {
129
+ customFilters.value = { ...newFilters };
124
130
  currentPage.value = 1;
125
131
  };
126
132
  const resetFilters = () => {
@@ -129,6 +135,7 @@ function usePagination(fetchFn, options) {
129
135
  search.value = options.defaultSearch || "";
130
136
  sortBy.value = options.defaultSort?.column || null;
131
137
  sortDirection.value = options.defaultSort?.direction || "asc";
138
+ customFilters.value = {};
132
139
  };
133
140
  let searchTimeout;
134
141
  watch(search, () => {
@@ -149,6 +156,7 @@ function usePagination(fetchFn, options) {
149
156
  sortBy,
150
157
  sortDirection,
151
158
  filters,
159
+ customFilters,
152
160
  // Query result
153
161
  ...queryResult,
154
162
  // Computed
@@ -159,6 +167,7 @@ function usePagination(fetchFn, options) {
159
167
  handlePerPageChange,
160
168
  handleSearchChange,
161
169
  handleSortChange,
170
+ handleFilterChange,
162
171
  resetFilters,
163
172
  setFilter,
164
173
  removeFilter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toniel/laravel-tanstack-pagination",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Vue 3 composables for Laravel pagination with TanStack Query",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -26,10 +26,22 @@
26
26
  "laravel",
27
27
  "pagination",
28
28
  "composable",
29
- "tanstack-query"
29
+ "tanstack-query",
30
+ "headless",
31
+ "typescript",
32
+ "vue-composables",
33
+ "laravel-api"
30
34
  ],
31
- "author": "Your Name",
35
+ "author": "Toniel <toniel@example.com>",
32
36
  "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/toniel/laravel-tanstack-pagination.git"
40
+ },
41
+ "homepage": "https://github.com/toniel/laravel-tanstack-pagination#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/toniel/laravel-tanstack-pagination/issues"
44
+ },
33
45
  "peerDependencies": {
34
46
  "vue": "^3.0.0",
35
47
  "@tanstack/vue-query": "^5.0.0"