@toniel/laravel-tanstack-pagination 0.1.2 → 0.1.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.
- package/dist/index.d.mts +15 -8
- package/dist/index.d.ts +15 -8
- package/dist/index.js +26 -17
- package/dist/index.mjs +28 -19
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5,12 +5,12 @@ import { Ref, ComputedRef } from 'vue';
|
|
|
5
5
|
|
|
6
6
|
type LaravelPaginationResponse<T = any> = {
|
|
7
7
|
data: T[];
|
|
8
|
-
links:
|
|
8
|
+
links: {
|
|
9
9
|
first: string | null;
|
|
10
10
|
last: string | null;
|
|
11
11
|
next: string | null;
|
|
12
12
|
prev: string | null;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
meta: {
|
|
15
15
|
current_page: number;
|
|
16
16
|
from: number;
|
|
@@ -44,6 +44,7 @@ interface UsePaginationOptions<T> extends Omit<UseQueryOptions<LaravelPagination
|
|
|
44
44
|
defaultPerPage?: number;
|
|
45
45
|
defaultSearch?: string;
|
|
46
46
|
defaultSort?: SortState;
|
|
47
|
+
debounceMs?: number;
|
|
47
48
|
}
|
|
48
49
|
declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) => Promise<LaravelPaginationResponse<T>>, options: UsePaginationOptions<T>): {
|
|
49
50
|
tableData: vue.ComputedRef<T[]>;
|
|
@@ -56,7 +57,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
56
57
|
resetFilters: () => void;
|
|
57
58
|
setFilter: (key: string, value: any) => void;
|
|
58
59
|
removeFilter: (key: string) => void;
|
|
59
|
-
getNumberingColumn: (
|
|
60
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
60
61
|
accessorKey: string;
|
|
61
62
|
header: string;
|
|
62
63
|
enableSorting: boolean;
|
|
@@ -98,6 +99,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
98
99
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
99
100
|
currentPage: vue.Ref<number, number>;
|
|
100
101
|
perPage: vue.Ref<number, number>;
|
|
102
|
+
currentPerPage: vue.Ref<number, number>;
|
|
101
103
|
search: vue.Ref<string, string>;
|
|
102
104
|
sortBy: vue.Ref<string | null, string | null>;
|
|
103
105
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -114,7 +116,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
114
116
|
resetFilters: () => void;
|
|
115
117
|
setFilter: (key: string, value: any) => void;
|
|
116
118
|
removeFilter: (key: string) => void;
|
|
117
|
-
getNumberingColumn: (
|
|
119
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
118
120
|
accessorKey: string;
|
|
119
121
|
header: string;
|
|
120
122
|
enableSorting: boolean;
|
|
@@ -156,6 +158,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
156
158
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
157
159
|
currentPage: vue.Ref<number, number>;
|
|
158
160
|
perPage: vue.Ref<number, number>;
|
|
161
|
+
currentPerPage: vue.Ref<number, number>;
|
|
159
162
|
search: vue.Ref<string, string>;
|
|
160
163
|
sortBy: vue.Ref<string | null, string | null>;
|
|
161
164
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -172,7 +175,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
172
175
|
resetFilters: () => void;
|
|
173
176
|
setFilter: (key: string, value: any) => void;
|
|
174
177
|
removeFilter: (key: string) => void;
|
|
175
|
-
getNumberingColumn: (
|
|
178
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
176
179
|
accessorKey: string;
|
|
177
180
|
header: string;
|
|
178
181
|
enableSorting: boolean;
|
|
@@ -214,6 +217,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
214
217
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
215
218
|
currentPage: vue.Ref<number, number>;
|
|
216
219
|
perPage: vue.Ref<number, number>;
|
|
220
|
+
currentPerPage: vue.Ref<number, number>;
|
|
217
221
|
search: vue.Ref<string, string>;
|
|
218
222
|
sortBy: vue.Ref<string | null, string | null>;
|
|
219
223
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -230,7 +234,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
230
234
|
resetFilters: () => void;
|
|
231
235
|
setFilter: (key: string, value: any) => void;
|
|
232
236
|
removeFilter: (key: string) => void;
|
|
233
|
-
getNumberingColumn: (
|
|
237
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
234
238
|
accessorKey: string;
|
|
235
239
|
header: string;
|
|
236
240
|
enableSorting: boolean;
|
|
@@ -272,6 +276,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
272
276
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
273
277
|
currentPage: vue.Ref<number, number>;
|
|
274
278
|
perPage: vue.Ref<number, number>;
|
|
279
|
+
currentPerPage: vue.Ref<number, number>;
|
|
275
280
|
search: vue.Ref<string, string>;
|
|
276
281
|
sortBy: vue.Ref<string | null, string | null>;
|
|
277
282
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -288,7 +293,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
288
293
|
resetFilters: () => void;
|
|
289
294
|
setFilter: (key: string, value: any) => void;
|
|
290
295
|
removeFilter: (key: string) => void;
|
|
291
|
-
getNumberingColumn: (
|
|
296
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
292
297
|
accessorKey: string;
|
|
293
298
|
header: string;
|
|
294
299
|
enableSorting: boolean;
|
|
@@ -330,6 +335,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
330
335
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
331
336
|
currentPage: vue.Ref<number, number>;
|
|
332
337
|
perPage: vue.Ref<number, number>;
|
|
338
|
+
currentPerPage: vue.Ref<number, number>;
|
|
333
339
|
search: vue.Ref<string, string>;
|
|
334
340
|
sortBy: vue.Ref<string | null, string | null>;
|
|
335
341
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -346,7 +352,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
346
352
|
resetFilters: () => void;
|
|
347
353
|
setFilter: (key: string, value: any) => void;
|
|
348
354
|
removeFilter: (key: string) => void;
|
|
349
|
-
getNumberingColumn: (
|
|
355
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
350
356
|
accessorKey: string;
|
|
351
357
|
header: string;
|
|
352
358
|
enableSorting: boolean;
|
|
@@ -388,6 +394,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
388
394
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
389
395
|
currentPage: vue.Ref<number, number>;
|
|
390
396
|
perPage: vue.Ref<number, number>;
|
|
397
|
+
currentPerPage: vue.Ref<number, number>;
|
|
391
398
|
search: vue.Ref<string, string>;
|
|
392
399
|
sortBy: vue.Ref<string | null, string | null>;
|
|
393
400
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,12 +5,12 @@ import { Ref, ComputedRef } from 'vue';
|
|
|
5
5
|
|
|
6
6
|
type LaravelPaginationResponse<T = any> = {
|
|
7
7
|
data: T[];
|
|
8
|
-
links:
|
|
8
|
+
links: {
|
|
9
9
|
first: string | null;
|
|
10
10
|
last: string | null;
|
|
11
11
|
next: string | null;
|
|
12
12
|
prev: string | null;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
meta: {
|
|
15
15
|
current_page: number;
|
|
16
16
|
from: number;
|
|
@@ -44,6 +44,7 @@ interface UsePaginationOptions<T> extends Omit<UseQueryOptions<LaravelPagination
|
|
|
44
44
|
defaultPerPage?: number;
|
|
45
45
|
defaultSearch?: string;
|
|
46
46
|
defaultSort?: SortState;
|
|
47
|
+
debounceMs?: number;
|
|
47
48
|
}
|
|
48
49
|
declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) => Promise<LaravelPaginationResponse<T>>, options: UsePaginationOptions<T>): {
|
|
49
50
|
tableData: vue.ComputedRef<T[]>;
|
|
@@ -56,7 +57,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
56
57
|
resetFilters: () => void;
|
|
57
58
|
setFilter: (key: string, value: any) => void;
|
|
58
59
|
removeFilter: (key: string) => void;
|
|
59
|
-
getNumberingColumn: (
|
|
60
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
60
61
|
accessorKey: string;
|
|
61
62
|
header: string;
|
|
62
63
|
enableSorting: boolean;
|
|
@@ -98,6 +99,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
98
99
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
99
100
|
currentPage: vue.Ref<number, number>;
|
|
100
101
|
perPage: vue.Ref<number, number>;
|
|
102
|
+
currentPerPage: vue.Ref<number, number>;
|
|
101
103
|
search: vue.Ref<string, string>;
|
|
102
104
|
sortBy: vue.Ref<string | null, string | null>;
|
|
103
105
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -114,7 +116,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
114
116
|
resetFilters: () => void;
|
|
115
117
|
setFilter: (key: string, value: any) => void;
|
|
116
118
|
removeFilter: (key: string) => void;
|
|
117
|
-
getNumberingColumn: (
|
|
119
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
118
120
|
accessorKey: string;
|
|
119
121
|
header: string;
|
|
120
122
|
enableSorting: boolean;
|
|
@@ -156,6 +158,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
156
158
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
157
159
|
currentPage: vue.Ref<number, number>;
|
|
158
160
|
perPage: vue.Ref<number, number>;
|
|
161
|
+
currentPerPage: vue.Ref<number, number>;
|
|
159
162
|
search: vue.Ref<string, string>;
|
|
160
163
|
sortBy: vue.Ref<string | null, string | null>;
|
|
161
164
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -172,7 +175,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
172
175
|
resetFilters: () => void;
|
|
173
176
|
setFilter: (key: string, value: any) => void;
|
|
174
177
|
removeFilter: (key: string) => void;
|
|
175
|
-
getNumberingColumn: (
|
|
178
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
176
179
|
accessorKey: string;
|
|
177
180
|
header: string;
|
|
178
181
|
enableSorting: boolean;
|
|
@@ -214,6 +217,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
214
217
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
215
218
|
currentPage: vue.Ref<number, number>;
|
|
216
219
|
perPage: vue.Ref<number, number>;
|
|
220
|
+
currentPerPage: vue.Ref<number, number>;
|
|
217
221
|
search: vue.Ref<string, string>;
|
|
218
222
|
sortBy: vue.Ref<string | null, string | null>;
|
|
219
223
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -230,7 +234,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
230
234
|
resetFilters: () => void;
|
|
231
235
|
setFilter: (key: string, value: any) => void;
|
|
232
236
|
removeFilter: (key: string) => void;
|
|
233
|
-
getNumberingColumn: (
|
|
237
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
234
238
|
accessorKey: string;
|
|
235
239
|
header: string;
|
|
236
240
|
enableSorting: boolean;
|
|
@@ -272,6 +276,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
272
276
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
273
277
|
currentPage: vue.Ref<number, number>;
|
|
274
278
|
perPage: vue.Ref<number, number>;
|
|
279
|
+
currentPerPage: vue.Ref<number, number>;
|
|
275
280
|
search: vue.Ref<string, string>;
|
|
276
281
|
sortBy: vue.Ref<string | null, string | null>;
|
|
277
282
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -288,7 +293,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
288
293
|
resetFilters: () => void;
|
|
289
294
|
setFilter: (key: string, value: any) => void;
|
|
290
295
|
removeFilter: (key: string) => void;
|
|
291
|
-
getNumberingColumn: (
|
|
296
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
292
297
|
accessorKey: string;
|
|
293
298
|
header: string;
|
|
294
299
|
enableSorting: boolean;
|
|
@@ -330,6 +335,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
330
335
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
331
336
|
currentPage: vue.Ref<number, number>;
|
|
332
337
|
perPage: vue.Ref<number, number>;
|
|
338
|
+
currentPerPage: vue.Ref<number, number>;
|
|
333
339
|
search: vue.Ref<string, string>;
|
|
334
340
|
sortBy: vue.Ref<string | null, string | null>;
|
|
335
341
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
|
@@ -346,7 +352,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
346
352
|
resetFilters: () => void;
|
|
347
353
|
setFilter: (key: string, value: any) => void;
|
|
348
354
|
removeFilter: (key: string) => void;
|
|
349
|
-
getNumberingColumn: (
|
|
355
|
+
getNumberingColumn: (columnOptions?: any) => {
|
|
350
356
|
accessorKey: string;
|
|
351
357
|
header: string;
|
|
352
358
|
enableSorting: boolean;
|
|
@@ -388,6 +394,7 @@ declare function usePagination<T = any>(fetchFn: (filters: PaginationFilters) =>
|
|
|
388
394
|
suspense: () => Promise<_tanstack_vue_query.QueryObserverResult<LaravelPaginationResponse<T>, Error>>;
|
|
389
395
|
currentPage: vue.Ref<number, number>;
|
|
390
396
|
perPage: vue.Ref<number, number>;
|
|
397
|
+
currentPerPage: vue.Ref<number, number>;
|
|
391
398
|
search: vue.Ref<string, string>;
|
|
392
399
|
sortBy: vue.Ref<string | null, string | null>;
|
|
393
400
|
sortDirection: vue.Ref<"asc" | "desc", "asc" | "desc">;
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ function useTableNumbering() {
|
|
|
31
31
|
const createNumberingColumn = (pagination, perPage, options = {}) => {
|
|
32
32
|
const {
|
|
33
33
|
header = "No.",
|
|
34
|
-
className = "
|
|
34
|
+
className = "",
|
|
35
35
|
width = "60px",
|
|
36
36
|
enableSorting = false
|
|
37
37
|
} = options;
|
|
@@ -97,21 +97,32 @@ function useTableNumbering() {
|
|
|
97
97
|
// src/composables/usePagination.ts
|
|
98
98
|
var import_vue_query = require("@tanstack/vue-query");
|
|
99
99
|
var import_vue2 = require("vue");
|
|
100
|
+
var VALID_SORT_COLUMN = /^[a-zA-Z0-9_.]+$/;
|
|
100
101
|
function usePagination(fetchFn, options) {
|
|
101
102
|
const currentPage = (0, import_vue2.ref)(1);
|
|
102
103
|
const perPage = (0, import_vue2.ref)(options.defaultPerPage || 10);
|
|
103
104
|
const search = (0, import_vue2.ref)(options.defaultSearch || "");
|
|
105
|
+
const debouncedSearch = (0, import_vue2.ref)(options.defaultSearch || "");
|
|
104
106
|
const sortBy = (0, import_vue2.ref)(options.defaultSort?.column || null);
|
|
105
107
|
const sortDirection = (0, import_vue2.ref)(options.defaultSort?.direction || "asc");
|
|
106
108
|
const customFilters = (0, import_vue2.ref)({});
|
|
109
|
+
let searchTimeout;
|
|
110
|
+
(0, import_vue2.watch)(search, (newValue) => {
|
|
111
|
+
clearTimeout(searchTimeout);
|
|
112
|
+
searchTimeout = setTimeout(() => {
|
|
113
|
+
debouncedSearch.value = newValue;
|
|
114
|
+
currentPage.value = 1;
|
|
115
|
+
}, options.debounceMs ?? 300);
|
|
116
|
+
});
|
|
117
|
+
(0, import_vue2.onScopeDispose)(() => clearTimeout(searchTimeout));
|
|
107
118
|
const filters = (0, import_vue2.computed)(() => {
|
|
108
119
|
const baseFilters = {
|
|
109
120
|
page: currentPage.value,
|
|
110
121
|
per_page: perPage.value,
|
|
111
|
-
search:
|
|
122
|
+
search: debouncedSearch.value,
|
|
112
123
|
...customFilters.value
|
|
113
124
|
};
|
|
114
|
-
if (sortBy.value) {
|
|
125
|
+
if (sortBy.value && VALID_SORT_COLUMN.test(sortBy.value)) {
|
|
115
126
|
baseFilters[`sort[${sortBy.value}]`] = sortDirection.value;
|
|
116
127
|
}
|
|
117
128
|
return baseFilters;
|
|
@@ -120,22 +131,24 @@ function usePagination(fetchFn, options) {
|
|
|
120
131
|
...options,
|
|
121
132
|
queryKey: [options.queryKey, filters],
|
|
122
133
|
queryFn: () => fetchFn(filters.value),
|
|
134
|
+
placeholderData: import_vue_query.keepPreviousData,
|
|
123
135
|
refetchOnWindowFocus: false
|
|
124
136
|
});
|
|
125
137
|
const tableData = (0, import_vue2.computed)(() => queryResult.data.value?.data || []);
|
|
126
138
|
const pagination = (0, import_vue2.computed)(() => queryResult.data.value || null);
|
|
127
139
|
const handlePageChange = (page) => {
|
|
128
|
-
|
|
140
|
+
const lastPage = pagination.value?.meta?.last_page ?? Infinity;
|
|
141
|
+
currentPage.value = Math.min(Math.max(1, Math.floor(page)), lastPage);
|
|
129
142
|
};
|
|
130
143
|
const handlePerPageChange = (newPerPage) => {
|
|
131
|
-
perPage.value = newPerPage;
|
|
144
|
+
perPage.value = Math.max(1, Math.floor(newPerPage));
|
|
132
145
|
currentPage.value = 1;
|
|
133
146
|
};
|
|
134
147
|
const handleSearchChange = (newSearch) => {
|
|
135
148
|
search.value = newSearch;
|
|
136
|
-
currentPage.value = 1;
|
|
137
149
|
};
|
|
138
150
|
const handleSortChange = (column) => {
|
|
151
|
+
if (!VALID_SORT_COLUMN.test(column)) return;
|
|
139
152
|
if (sortBy.value === column) {
|
|
140
153
|
sortDirection.value = sortDirection.value === "asc" ? "desc" : "asc";
|
|
141
154
|
} else {
|
|
@@ -145,11 +158,12 @@ function usePagination(fetchFn, options) {
|
|
|
145
158
|
currentPage.value = 1;
|
|
146
159
|
};
|
|
147
160
|
const setFilter = (key, value) => {
|
|
148
|
-
customFilters.value[key]
|
|
161
|
+
customFilters.value = { ...customFilters.value, [key]: value };
|
|
149
162
|
currentPage.value = 1;
|
|
150
163
|
};
|
|
151
164
|
const removeFilter = (key) => {
|
|
152
|
-
|
|
165
|
+
const { [key]: _, ...rest } = customFilters.value;
|
|
166
|
+
customFilters.value = rest;
|
|
153
167
|
currentPage.value = 1;
|
|
154
168
|
};
|
|
155
169
|
const handleFilterChange = (newFilters) => {
|
|
@@ -160,25 +174,20 @@ function usePagination(fetchFn, options) {
|
|
|
160
174
|
currentPage.value = 1;
|
|
161
175
|
perPage.value = options.defaultPerPage || 10;
|
|
162
176
|
search.value = options.defaultSearch || "";
|
|
177
|
+
debouncedSearch.value = options.defaultSearch || "";
|
|
163
178
|
sortBy.value = options.defaultSort?.column || null;
|
|
164
179
|
sortDirection.value = options.defaultSort?.direction || "asc";
|
|
165
180
|
customFilters.value = {};
|
|
166
181
|
};
|
|
167
|
-
let searchTimeout;
|
|
168
|
-
(0, import_vue2.watch)(search, () => {
|
|
169
|
-
clearTimeout(searchTimeout);
|
|
170
|
-
searchTimeout = window.setTimeout(() => {
|
|
171
|
-
currentPage.value = 1;
|
|
172
|
-
}, 300);
|
|
173
|
-
});
|
|
174
182
|
const { createNumberingColumn } = useTableNumbering();
|
|
175
|
-
const getNumberingColumn = (
|
|
176
|
-
return createNumberingColumn(pagination, perPage,
|
|
183
|
+
const getNumberingColumn = (columnOptions = {}) => {
|
|
184
|
+
return createNumberingColumn(pagination, perPage, columnOptions);
|
|
177
185
|
};
|
|
178
186
|
return {
|
|
179
187
|
// State
|
|
180
188
|
currentPage,
|
|
181
189
|
perPage,
|
|
190
|
+
currentPerPage: perPage,
|
|
182
191
|
search,
|
|
183
192
|
sortBy,
|
|
184
193
|
sortDirection,
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ function useTableNumbering() {
|
|
|
4
4
|
const createNumberingColumn = (pagination, perPage, options = {}) => {
|
|
5
5
|
const {
|
|
6
6
|
header = "No.",
|
|
7
|
-
className = "
|
|
7
|
+
className = "",
|
|
8
8
|
width = "60px",
|
|
9
9
|
enableSorting = false
|
|
10
10
|
} = options;
|
|
@@ -68,23 +68,34 @@ function useTableNumbering() {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// src/composables/usePagination.ts
|
|
71
|
-
import { useQuery } from "@tanstack/vue-query";
|
|
72
|
-
import { computed, ref, watch } from "vue";
|
|
71
|
+
import { useQuery, keepPreviousData } from "@tanstack/vue-query";
|
|
72
|
+
import { computed, onScopeDispose, ref, watch } from "vue";
|
|
73
|
+
var VALID_SORT_COLUMN = /^[a-zA-Z0-9_.]+$/;
|
|
73
74
|
function usePagination(fetchFn, options) {
|
|
74
75
|
const currentPage = ref(1);
|
|
75
76
|
const perPage = ref(options.defaultPerPage || 10);
|
|
76
77
|
const search = ref(options.defaultSearch || "");
|
|
78
|
+
const debouncedSearch = ref(options.defaultSearch || "");
|
|
77
79
|
const sortBy = ref(options.defaultSort?.column || null);
|
|
78
80
|
const sortDirection = ref(options.defaultSort?.direction || "asc");
|
|
79
81
|
const customFilters = ref({});
|
|
82
|
+
let searchTimeout;
|
|
83
|
+
watch(search, (newValue) => {
|
|
84
|
+
clearTimeout(searchTimeout);
|
|
85
|
+
searchTimeout = setTimeout(() => {
|
|
86
|
+
debouncedSearch.value = newValue;
|
|
87
|
+
currentPage.value = 1;
|
|
88
|
+
}, options.debounceMs ?? 300);
|
|
89
|
+
});
|
|
90
|
+
onScopeDispose(() => clearTimeout(searchTimeout));
|
|
80
91
|
const filters = computed(() => {
|
|
81
92
|
const baseFilters = {
|
|
82
93
|
page: currentPage.value,
|
|
83
94
|
per_page: perPage.value,
|
|
84
|
-
search:
|
|
95
|
+
search: debouncedSearch.value,
|
|
85
96
|
...customFilters.value
|
|
86
97
|
};
|
|
87
|
-
if (sortBy.value) {
|
|
98
|
+
if (sortBy.value && VALID_SORT_COLUMN.test(sortBy.value)) {
|
|
88
99
|
baseFilters[`sort[${sortBy.value}]`] = sortDirection.value;
|
|
89
100
|
}
|
|
90
101
|
return baseFilters;
|
|
@@ -93,22 +104,24 @@ function usePagination(fetchFn, options) {
|
|
|
93
104
|
...options,
|
|
94
105
|
queryKey: [options.queryKey, filters],
|
|
95
106
|
queryFn: () => fetchFn(filters.value),
|
|
107
|
+
placeholderData: keepPreviousData,
|
|
96
108
|
refetchOnWindowFocus: false
|
|
97
109
|
});
|
|
98
110
|
const tableData = computed(() => queryResult.data.value?.data || []);
|
|
99
111
|
const pagination = computed(() => queryResult.data.value || null);
|
|
100
112
|
const handlePageChange = (page) => {
|
|
101
|
-
|
|
113
|
+
const lastPage = pagination.value?.meta?.last_page ?? Infinity;
|
|
114
|
+
currentPage.value = Math.min(Math.max(1, Math.floor(page)), lastPage);
|
|
102
115
|
};
|
|
103
116
|
const handlePerPageChange = (newPerPage) => {
|
|
104
|
-
perPage.value = newPerPage;
|
|
117
|
+
perPage.value = Math.max(1, Math.floor(newPerPage));
|
|
105
118
|
currentPage.value = 1;
|
|
106
119
|
};
|
|
107
120
|
const handleSearchChange = (newSearch) => {
|
|
108
121
|
search.value = newSearch;
|
|
109
|
-
currentPage.value = 1;
|
|
110
122
|
};
|
|
111
123
|
const handleSortChange = (column) => {
|
|
124
|
+
if (!VALID_SORT_COLUMN.test(column)) return;
|
|
112
125
|
if (sortBy.value === column) {
|
|
113
126
|
sortDirection.value = sortDirection.value === "asc" ? "desc" : "asc";
|
|
114
127
|
} else {
|
|
@@ -118,11 +131,12 @@ function usePagination(fetchFn, options) {
|
|
|
118
131
|
currentPage.value = 1;
|
|
119
132
|
};
|
|
120
133
|
const setFilter = (key, value) => {
|
|
121
|
-
customFilters.value[key]
|
|
134
|
+
customFilters.value = { ...customFilters.value, [key]: value };
|
|
122
135
|
currentPage.value = 1;
|
|
123
136
|
};
|
|
124
137
|
const removeFilter = (key) => {
|
|
125
|
-
|
|
138
|
+
const { [key]: _, ...rest } = customFilters.value;
|
|
139
|
+
customFilters.value = rest;
|
|
126
140
|
currentPage.value = 1;
|
|
127
141
|
};
|
|
128
142
|
const handleFilterChange = (newFilters) => {
|
|
@@ -133,25 +147,20 @@ function usePagination(fetchFn, options) {
|
|
|
133
147
|
currentPage.value = 1;
|
|
134
148
|
perPage.value = options.defaultPerPage || 10;
|
|
135
149
|
search.value = options.defaultSearch || "";
|
|
150
|
+
debouncedSearch.value = options.defaultSearch || "";
|
|
136
151
|
sortBy.value = options.defaultSort?.column || null;
|
|
137
152
|
sortDirection.value = options.defaultSort?.direction || "asc";
|
|
138
153
|
customFilters.value = {};
|
|
139
154
|
};
|
|
140
|
-
let searchTimeout;
|
|
141
|
-
watch(search, () => {
|
|
142
|
-
clearTimeout(searchTimeout);
|
|
143
|
-
searchTimeout = window.setTimeout(() => {
|
|
144
|
-
currentPage.value = 1;
|
|
145
|
-
}, 300);
|
|
146
|
-
});
|
|
147
155
|
const { createNumberingColumn } = useTableNumbering();
|
|
148
|
-
const getNumberingColumn = (
|
|
149
|
-
return createNumberingColumn(pagination, perPage,
|
|
156
|
+
const getNumberingColumn = (columnOptions = {}) => {
|
|
157
|
+
return createNumberingColumn(pagination, perPage, columnOptions);
|
|
150
158
|
};
|
|
151
159
|
return {
|
|
152
160
|
// State
|
|
153
161
|
currentPage,
|
|
154
162
|
perPage,
|
|
163
|
+
currentPerPage: perPage,
|
|
155
164
|
search,
|
|
156
165
|
sortBy,
|
|
157
166
|
sortDirection,
|