@openway/ui 1.0.0 → 1.0.1

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 (57) hide show
  1. package/README.md +203 -181
  2. package/dist/chunk-CJQNI3QX.js +3 -0
  3. package/dist/chunk-CJQNI3QX.js.map +1 -0
  4. package/dist/index.cjs +5 -1
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +2642 -1103
  7. package/dist/index.d.ts +2642 -1103
  8. package/dist/index.js +5 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/query.cjs +3 -0
  11. package/dist/query.cjs.map +1 -0
  12. package/dist/query.d.cts +309 -0
  13. package/dist/query.d.ts +309 -0
  14. package/dist/query.js +3 -0
  15. package/dist/query.js.map +1 -0
  16. package/dist/useInfiniteScroll-DAlgjUN4.d.cts +325 -0
  17. package/dist/useInfiniteScroll-DAlgjUN4.d.ts +325 -0
  18. package/docs/AGENTS.md +144 -0
  19. package/docs/README.md +150 -0
  20. package/docs/SKILL.md +54 -0
  21. package/docs/components/alert.md +246 -0
  22. package/docs/components/badge.md +238 -0
  23. package/docs/components/button.md +262 -0
  24. package/docs/components/carousel.md +354 -0
  25. package/docs/components/checkbox.md +252 -0
  26. package/docs/components/collapse.md +318 -0
  27. package/docs/components/confirm.md +322 -0
  28. package/docs/components/datepicker.md +259 -0
  29. package/docs/components/daterangepicker.md +260 -0
  30. package/docs/components/datetimepicker.md +226 -0
  31. package/docs/components/datetimerangepicker.md +222 -0
  32. package/docs/components/dropdown.md +275 -0
  33. package/docs/components/empty.md +200 -0
  34. package/docs/components/file-preview.md +180 -0
  35. package/docs/components/input.md +559 -0
  36. package/docs/components/modal.md +293 -0
  37. package/docs/components/popover.md +255 -0
  38. package/docs/components/radio.md +245 -0
  39. package/docs/components/select.md +254 -0
  40. package/docs/components/skeleton.md +150 -0
  41. package/docs/components/slider.md +346 -0
  42. package/docs/components/table.md +316 -0
  43. package/docs/components/tabs.md +432 -0
  44. package/docs/components/textarea.md +193 -0
  45. package/docs/components/timepicker.md +242 -0
  46. package/docs/components/timerangepicker.md +210 -0
  47. package/docs/components/toast.md +282 -0
  48. package/docs/components/toggle.md +211 -0
  49. package/docs/components/tooltip.md +213 -0
  50. package/docs/components/upload-avatar.md +318 -0
  51. package/docs/components/upload-file.md +245 -0
  52. package/docs/components/upload-image.md +126 -0
  53. package/docs/hooks/useDebounce.md +92 -0
  54. package/docs/hooks/useInfiniteScroll.md +95 -0
  55. package/docs/hooks/useSelectInfiniteQuery.md +123 -0
  56. package/docs/hooks/useTableQuery.md +124 -0
  57. package/package.json +31 -12
@@ -0,0 +1,309 @@
1
+ import { QueryFunctionContext, UseQueryOptions, UseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query';
2
+ import { RowData, SortingState, ColumnFiltersState, PaginationState, OnChangeFn } from '@tanstack/react-table';
3
+ import { ReactNode } from 'react';
4
+ import { b as SelectOptionItem, U as UseInfiniteScrollOptions } from './useInfiniteScroll-DAlgjUN4.js';
5
+ import '@floating-ui/react';
6
+
7
+ /**
8
+ * Các tham số truy vấn chuẩn hóa gửi lên API máy chủ.
9
+ */
10
+ interface TableQueryParams {
11
+ /**
12
+ * Số thứ tự trang (1-indexed: 1, 2, 3...)
13
+ */
14
+ page: number;
15
+ /**
16
+ * Kích thước trang (số dòng trên 1 trang)
17
+ */
18
+ pageSize: number;
19
+ /**
20
+ * ID cột được sắp xếp
21
+ */
22
+ sortBy?: string;
23
+ /**
24
+ * Chiều sắp xếp: "asc" (tăng dần) hoặc "desc" (giảm dần)
25
+ */
26
+ sortOrder?: "asc" | "desc";
27
+ /**
28
+ * Danh sách bộ lọc cột dạng từ điển phẳng Record<cột, giá trị>
29
+ */
30
+ filters?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * Các tùy chọn cấu hình cho hook `useTableQuery`.
34
+ */
35
+ interface UseTableQueryOptions<TData extends RowData = RowData, TResponse = unknown, TError = Error> {
36
+ /**
37
+ * Base query key cho TanStack Query.
38
+ * `queryParams` sẽ tự động được thêm vào cuối queryKey: `[...queryKey, queryParams]`.
39
+ */
40
+ queryKey: readonly unknown[];
41
+ /**
42
+ * Hàm gọi API truy vấn dữ liệu từ máy chủ.
43
+ * Nhận vào `queryParams` đã chuẩn hóa và `context` của TanStack Query.
44
+ */
45
+ queryFn: (params: TableQueryParams, context: QueryFunctionContext<readonly unknown[]>) => Promise<TResponse>;
46
+ /**
47
+ * Hàm trích xuất mảng dữ liệu các dòng (`TData[]`) từ kết quả API trả về.
48
+ * Mặc định tự động kiểm tra `response.data`, `response.items`, `response.rows`, `response.results` hoặc bản thân mảng response.
49
+ */
50
+ selectData?: (response: TResponse) => TData[];
51
+ /**
52
+ * Hàm trích xuất tổng số lượng bản ghi (`rowCount` / `total`) từ kết quả API trả về.
53
+ * Mặc định tự động kiểm tra `response.total`, `response.rowCount`, `response.totalCount`, `response.count`.
54
+ */
55
+ selectRowCount?: (response: TResponse) => number;
56
+ /**
57
+ * Cấu hình phân trang ban đầu
58
+ */
59
+ initialPagination?: {
60
+ pageIndex?: number;
61
+ pageSize?: number;
62
+ };
63
+ /**
64
+ * Cấu hình sắp xếp ban đầu
65
+ */
66
+ initialSorting?: SortingState;
67
+ /**
68
+ * Cấu hình bộ lọc cột ban đầu
69
+ */
70
+ initialColumnFilters?: ColumnFiltersState;
71
+ /**
72
+ * Cấu hình từ khóa tìm kiếm ban đầu
73
+ */
74
+ initialGlobalFilter?: string;
75
+ /**
76
+ * Tự động đưa về trang đầu (pageIndex = 0) khi thay đổi tìm kiếm, bộ lọc hoặc sắp xếp.
77
+ * @default true
78
+ */
79
+ autoResetPageIndex?: boolean;
80
+ /**
81
+ * Các tùy chọn nâng cao truyền trực tiếp cho hook `useQuery` của TanStack Query
82
+ * (ví dụ: `staleTime`, `gcTime`, `refetchOnWindowFocus`, `enabled`...).
83
+ */
84
+ queryOptions?: Omit<UseQueryOptions<TResponse, TError, TResponse, readonly unknown[]>, "queryKey" | "queryFn">;
85
+ }
86
+ /**
87
+ * Kết quả trả về từ hook `useTableQuery`.
88
+ */
89
+ interface UseTableQueryReturn<TData extends RowData = RowData, TResponse = unknown, TError = Error> {
90
+ /**
91
+ * Tập props trọn gói sẵn sàng truyền thẳng vào `<DataTable {...tableProps} />`
92
+ */
93
+ tableProps: {
94
+ data: TData[];
95
+ rowCount: number;
96
+ isLoading: boolean;
97
+ isRefresh: boolean;
98
+ onRefresh: () => void;
99
+ manualPagination: true;
100
+ manualSorting: true;
101
+ manualFiltering: true;
102
+ pagination: PaginationState;
103
+ onPaginationChange: OnChangeFn<PaginationState>;
104
+ sorting: SortingState;
105
+ onSortingChange: OnChangeFn<SortingState>;
106
+ columnFilters: ColumnFiltersState;
107
+ onColumnFiltersChange: OnChangeFn<ColumnFiltersState>;
108
+ globalFilter: string;
109
+ onGlobalFilterChange: (filter: string) => void;
110
+ };
111
+ /**
112
+ * Instance query đầy đủ từ TanStack Query
113
+ */
114
+ query: UseQueryResult<TResponse, TError>;
115
+ /**
116
+ * Tham số truy vấn hiện tại (dùng để debug, ghi log, đồng bộ URL query string, hoặc xuất Excel)
117
+ */
118
+ queryParams: TableQueryParams;
119
+ /**
120
+ * Đặt lại toàn bộ phân trang, sắp xếp, tìm kiếm và bộ lọc về giá trị mặc định ban đầu
121
+ */
122
+ resetAll: () => void;
123
+ /**
124
+ * Đổi trang thủ công (1-indexed: 1, 2, 3...)
125
+ */
126
+ setPage: (page: number) => void;
127
+ /**
128
+ * Đổi số dòng trên mỗi trang thủ công
129
+ */
130
+ setPageSize: (pageSize: number) => void;
131
+ /**
132
+ * Đổi từ khóa tìm kiếm toàn bảng (lọc client-side)
133
+ */
134
+ setGlobalFilter: (filter: string) => void;
135
+ /**
136
+ * Cập nhật trạng thái sắp xếp
137
+ */
138
+ setSorting: (sorting: SortingState | ((prev: SortingState) => SortingState)) => void;
139
+ /**
140
+ * Cập nhật trạng thái bộ lọc cột
141
+ */
142
+ setColumnFilters: (filters: ColumnFiltersState | ((prev: ColumnFiltersState) => ColumnFiltersState)) => void;
143
+ }
144
+ /**
145
+ * Hook Adapter `useTableQuery` tích hợp TanStack Table v9 và TanStack Query v5.
146
+ *
147
+ * Tính năng:
148
+ * - Đồng bộ hai chiều trạng thái bảng (Pagination, Sorting, Filtering, Search) với server API.
149
+ * - Tự động định dạng tham số `TableQueryParams`: `page` (1-indexed), `pageSize`, `search`, `sortBy`, `sortOrder`, `filters`.
150
+ * - Tự động gắn `queryParams` vào `queryKey` của TanStack Query để kích hoạt cache/refetch thông minh.
151
+ * - Hỗ trợ phân trang mượt mà bằng `placeholderData: keepPreviousData` (không bị nhấp nháy Skeleton khi chuyển trang).
152
+ * - Cung cấp `tableProps` dựng sẵn truyền trực tiếp vào `<DataTable {...tableProps} />`.
153
+ */
154
+ declare function useTableQuery<TData extends RowData = RowData, TResponse = unknown, TError = Error>(options: UseTableQueryOptions<TData, TResponse, TError>): UseTableQueryReturn<TData, TResponse, TError>;
155
+
156
+ /**
157
+ * Các tham số truy vấn chuẩn hóa được chuyển tới hàm `queryFn`.
158
+ */
159
+ interface SelectQueryParams<TPageParam = number, TFilters extends Record<string, unknown> = Record<string, unknown>> {
160
+ /**
161
+ * Tham số phân trang hiện tại (trang hiện tại hoặc cursor).
162
+ */
163
+ pageParam: TPageParam;
164
+ /**
165
+ * Từ khóa tìm kiếm từ ô Select.
166
+ */
167
+ search: string;
168
+ /**
169
+ * Bộ lọc bổ sung từ menu filter của Select.
170
+ */
171
+ filters: TFilters;
172
+ }
173
+ /**
174
+ * Các tùy chọn cấu hình cho hook `useSelectInfiniteQuery`.
175
+ */
176
+ interface UseSelectInfiniteQueryOptions<TData = unknown, TResponse = unknown, TPageParam = number, TFilters extends Record<string, unknown> = Record<string, unknown>, TError = Error> {
177
+ /**
178
+ * Base query key cho TanStack Query.
179
+ * `[{ search, filters }]` sẽ tự động được thêm vào cuối queryKey:
180
+ * `[...queryKey, { search, filters }]`.
181
+ */
182
+ queryKey: readonly unknown[];
183
+ /**
184
+ * Hàm gọi API truy vấn dữ liệu từ máy chủ theo từng trang.
185
+ * Nhận vào `SelectQueryParams` đã chuẩn hóa và `context` của TanStack Query.
186
+ */
187
+ queryFn: (params: SelectQueryParams<TPageParam, TFilters>, context: QueryFunctionContext<readonly unknown[], TPageParam>) => Promise<TResponse>;
188
+ /**
189
+ * Giá trị tham số trang đầu tiên (initialPageParam).
190
+ * @default 1
191
+ */
192
+ initialPageParam?: TPageParam;
193
+ /**
194
+ * Hàm xác định `pageParam` cho trang tiếp theo.
195
+ * Trả về `undefined` hoặc `null` khi không còn dữ liệu tiếp theo.
196
+ */
197
+ getNextPageParam?: (lastPage: TResponse, allPages: TResponse[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null;
198
+ /**
199
+ * Hàm xác định `pageParam` cho trang trước đó (nếu có).
200
+ */
201
+ getPreviousPageParam?: (firstPage: TResponse, allPages: TResponse[], firstPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null;
202
+ /**
203
+ * Hàm trích xuất danh sách options (`SelectOptionItem<TData>[]`) từ mỗi `response` trang.
204
+ * Nếu không truyền, mặc định sẽ kiểm tra `data`, `items`, `options`, `results`, `rows` hoặc chính `response`.
205
+ */
206
+ selectOptions?: (response: TResponse) => SelectOptionItem<TData>[];
207
+ /**
208
+ * Hàm biến đổi từng phần tử thô (raw entity) thành `SelectOptionItem<TData>`.
209
+ */
210
+ mapOption?: (item: unknown, index: number) => SelectOptionItem<TData>;
211
+ /**
212
+ * Thời gian debounce từ khóa tìm kiếm (tính theo ms).
213
+ * @default 300
214
+ */
215
+ debounceMs?: number;
216
+ /**
217
+ * Từ khóa tìm kiếm ban đầu.
218
+ */
219
+ initialSearch?: string;
220
+ /**
221
+ * Giá trị bộ lọc menu ban đầu.
222
+ */
223
+ initialFilters?: TFilters;
224
+ /**
225
+ * Danh sách options ban đầu ghim sẵn (ví dụ các options đã chọn trước đó cần bảo lưu).
226
+ */
227
+ initialOptions?: SelectOptionItem<TData>[];
228
+ /**
229
+ * Số dòng Skeleton hiển thị khi đang tải thêm trang tiếp theo.
230
+ * @default 2
231
+ */
232
+ skeletonLines?: number;
233
+ /**
234
+ * Chiều cao của mỗi dòng Skeleton khi đang tải thêm trang.
235
+ * @default "1.75rem"
236
+ */
237
+ skeletonHeight?: number | string;
238
+ /**
239
+ * Tùy biến render khi đang tải thêm trang tiếp theo (thay thế Skeleton mặc định).
240
+ */
241
+ renderLoadingMore?: () => ReactNode;
242
+ /**
243
+ * Thông báo hiển thị khi đã tải hết toàn bộ dữ liệu ở đáy danh sách (tùy chọn).
244
+ */
245
+ endMessage?: ReactNode;
246
+ /**
247
+ * Tùy chọn truyền trực tiếp cho hook `useInfiniteScroll`.
248
+ */
249
+ scrollOptions?: Partial<Omit<UseInfiniteScrollOptions, "onLoadMore" | "hasMore" | "isLoading">>;
250
+ /**
251
+ * Các tùy chọn nâng cao truyền trực tiếp cho hook `useInfiniteQuery` của TanStack Query.
252
+ */
253
+ queryOptions?: Omit<UseInfiniteQueryOptions<TResponse, TError, InfiniteData<TResponse>, readonly unknown[], TPageParam>, "queryKey" | "queryFn" | "initialPageParam" | "getNextPageParam" | "getPreviousPageParam">;
254
+ }
255
+ /**
256
+ * Kết quả trả về từ hook `useSelectInfiniteQuery`.
257
+ */
258
+ interface UseSelectInfiniteQueryReturn<TData = unknown, TResponse = unknown, TFilters extends Record<string, unknown> = Record<string, unknown>, TError = Error> {
259
+ /**
260
+ * Bộ props trọn gói sẵn sàng truyền thẳng vào `<Select {...selectProps} />` hoặc `<MultiSelect {...selectProps} />`
261
+ */
262
+ selectProps: {
263
+ options: SelectOptionItem<TData>[];
264
+ isLoading: boolean;
265
+ searchMode: "server";
266
+ debounceMs: number;
267
+ onSearch: (query: string, filters: TFilters) => void;
268
+ listFooter: ReactNode;
269
+ };
270
+ /**
271
+ * Instance query đầy đủ từ TanStack Query
272
+ */
273
+ query: UseInfiniteQueryResult<InfiniteData<TResponse>, TError>;
274
+ /**
275
+ * Toàn bộ danh sách options đã gom tụ từ tất cả các trang
276
+ */
277
+ options: SelectOptionItem<TData>[];
278
+ /**
279
+ * Từ khóa tìm kiếm hiện tại (đã được Select debounce qua onSearch)
280
+ */
281
+ search: string;
282
+ /**
283
+ * Phương thức cập nhật từ khóa tìm kiếm
284
+ */
285
+ setSearch: (search: string) => void;
286
+ /**
287
+ * Bộ lọc menu hiện tại
288
+ */
289
+ filters: TFilters;
290
+ /**
291
+ * Phương thức cập nhật bộ lọc menu
292
+ */
293
+ setFilters: (filters: TFilters | ((prev: TFilters) => TFilters)) => void;
294
+ /**
295
+ * Ref gắn vào phần tử sentinel (IntersectionObserver)
296
+ */
297
+ sentinelRef: (node: HTMLElement | null) => void;
298
+ /**
299
+ * Đặt lại toàn bộ tìm kiếm, bộ lọc về giá trị ban đầu
300
+ */
301
+ reset: () => void;
302
+ }
303
+ /**
304
+ * Hook `useSelectInfiniteQuery` kết hợp TanStack Query `useInfiniteQuery` với `useInfiniteScroll`
305
+ * dành riêng cho `<Select />` và `<MultiSelect />` ở chế độ máy chủ (`searchMode="server"`).
306
+ */
307
+ declare function useSelectInfiniteQuery<TData = unknown, TResponse = unknown, TPageParam = number, TFilters extends Record<string, unknown> = Record<string, unknown>, TError = Error>({ queryKey, queryFn, initialPageParam, getNextPageParam, getPreviousPageParam, selectOptions, mapOption, debounceMs, initialSearch, initialFilters, initialOptions, skeletonLines, skeletonHeight, renderLoadingMore, endMessage, scrollOptions, queryOptions, }: UseSelectInfiniteQueryOptions<TData, TResponse, TPageParam, TFilters, TError>): UseSelectInfiniteQueryReturn<TData, TResponse, TFilters, TError>;
308
+
309
+ export { type SelectQueryParams, type TableQueryParams, type UseSelectInfiniteQueryOptions, type UseSelectInfiniteQueryReturn, type UseTableQueryOptions, type UseTableQueryReturn, useSelectInfiniteQuery, useTableQuery };
package/dist/query.js ADDED
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ import{c as J,g as W,l as j}from"./chunk-CJQNI3QX.js";import{useCallback as S,useMemo as N,useState as G}from"react";import{useQuery as $,keepPreviousData as ee}from"@tanstack/react-query";function te(n){if(!n)return[];if(Array.isArray(n))return n;if(typeof n=="object"){let e=n;if(Array.isArray(e.data))return e.data;if(Array.isArray(e.items))return e.items;if(Array.isArray(e.rows))return e.rows;if(Array.isArray(e.results))return e.results}return[]}function ne(n){if(!n)return 0;if(Array.isArray(n))return n.length;if(typeof n=="object"){let e=n,R=e.total??e.rowCount??e.totalCount??e.count;if(typeof R=="number")return R;if(typeof R=="string"){let m=Number(R);if(!isNaN(m))return m}}return 0}function B(n,e){return typeof n=="function"?n(e):n}function re(n){let{queryKey:e,queryFn:R,selectData:m=te,selectRowCount:q=ne,initialPagination:d,initialSorting:b,initialColumnFilters:k,initialGlobalFilter:x,autoResetPageIndex:g=!0,queryOptions:D}=n,[y,c]=G({pageIndex:d?.pageIndex??0,pageSize:d?.pageSize??j}),[h,w]=G(b??[]),[T,E]=G(k??[]),[C,Q]=G(x??""),P=N(()=>{let a={page:y.pageIndex+1,pageSize:y.pageSize},r=h[0];if(r&&(a.sortBy=r.id,a.sortOrder=r.desc?"desc":"asc"),T.length>0){let z={};T.forEach(Z=>{z[Z.id]=Z.value}),a.filters=z}return a},[y.pageIndex,y.pageSize,h,T]),v=N(()=>[...e,P],[e,P]),p=$({queryKey:v,queryFn:a=>R(P,a),placeholderData:ee,...D}),L=N(()=>p.data?m(p.data):[],[p.data,m]),o=N(()=>p.data?q(p.data):0,[p.data,q]),F=S(a=>{c(r=>B(a,r))},[]),I=S(a=>{w(r=>B(a,r)),g&&c(r=>r.pageIndex===0?r:{...r,pageIndex:0})},[g]),A=S(a=>{E(r=>B(a,r)),g&&c(r=>r.pageIndex===0?r:{...r,pageIndex:0})},[g]),O=S(a=>{Q(a),g&&c(r=>r.pageIndex===0?r:{...r,pageIndex:0})},[g]),M=S(()=>{c({pageIndex:d?.pageIndex??0,pageSize:d?.pageSize??j}),w(b??[]),E(k??[]),Q(x??"")},[d,b,k,x]),Y=S(a=>{c(r=>({...r,pageIndex:Math.max(0,a-1)}))},[]),s=S(a=>{c({pageIndex:0,pageSize:a})},[]),f=S(a=>{O(a)},[O]),{isLoading:i,isRefetching:l,refetch:t}=p,u=S(()=>{t()},[t]);return{tableProps:N(()=>({data:L,rowCount:o,isLoading:i,isRefresh:l&&!i,onRefresh:u,manualPagination:!0,manualSorting:!0,manualFiltering:!0,pagination:y,onPaginationChange:F,sorting:h,onSortingChange:I,columnFilters:T,onColumnFiltersChange:A,globalFilter:C,onGlobalFilterChange:O}),[L,o,i,l,u,y,F,h,I,T,A,C,O]),query:p,queryParams:P,resetAll:M,setPage:Y,setPageSize:s,setGlobalFilter:f,setSorting:w,setColumnFilters:E}}import{useCallback as H,useMemo as _,useState as X}from"react";import{useInfiniteQuery as ae}from"@tanstack/react-query";import{jsx as K}from"react/jsx-runtime";function V(n){if(!n)return[];if(Array.isArray(n))return n;if(typeof n!="object")return[];let e=n;return Array.isArray(e.data)?e.data:Array.isArray(e.items)?e.items:Array.isArray(e.options)?e.options:Array.isArray(e.results)?e.results:Array.isArray(e.rows)?e.rows:[]}var oe={};function se({queryKey:n,queryFn:e,initialPageParam:R=1,getNextPageParam:m,getPreviousPageParam:q,selectOptions:d,mapOption:b,debounceMs:k=300,initialSearch:x="",initialFilters:g=oe,initialOptions:D,skeletonLines:y=2,skeletonHeight:c="1.75rem",renderLoadingMore:h,endMessage:w,scrollOptions:T,queryOptions:E}){let[C,Q]=X(x),[P,v]=X(g),p=_(()=>[...n,{search:C,filters:P}],[n,C,P]),L=H((s,f,i,l)=>{if(m)return m(s,f,i,l);if(!s||typeof s!="object")return;let t=s;if(typeof t.nextPage=="number"||typeof t.nextPage=="string")return t.nextPage;if(typeof t.next_page=="number"||typeof t.next_page=="string")return t.next_page;if(typeof t.nextCursor=="string"||typeof t.nextCursor=="number")return t.nextCursor;if(typeof t.next_cursor=="string"||typeof t.next_cursor=="number")return t.next_cursor;if(!(t.hasMore===!1||t.has_more===!1||t.hasNextPage===!1)&&typeof i=="number"){if(V(s).length===0)return;let U=typeof t.total=="number"?t.total:typeof t.totalCount=="number"?t.totalCount:typeof t.count=="number"?t.count:void 0;return U!==void 0&&f.reduce((r,z)=>r+V(z).length,0)>=U?void 0:i+1}},[m]),o=ae({queryKey:p,queryFn:s=>e({pageParam:s.pageParam,search:C,filters:P},s),initialPageParam:R,getNextPageParam:L,getPreviousPageParam:q,...E}),F=_(()=>{let s=o.data?.pages??[],f=[],i=new Set;if(D&&D.length>0)for(let l of D)i.has(l.value)||(i.add(l.value),f.push(l));for(let l of s){let t=[];if(d)t=d(l);else{let u=V(l);b?t=u.map((U,a)=>b(U,a)):t=u}for(let u of t)u&&u.value!==void 0&&!i.has(u.value)&&(i.add(u.value),f.push(u))}return f},[o.data?.pages,d,b,D]),{sentinelRef:I}=J({onLoadMore:()=>{o.hasNextPage&&!o.isFetchingNextPage&&o.fetchNextPage()},hasMore:!!o.hasNextPage,isLoading:o.isFetchingNextPage||o.isLoading,disabled:o.isError,rootMargin:T?.rootMargin??"80px",threshold:T?.threshold??0,root:T?.root}),A=H((s,f)=>{Q(s),v(f)},[]),O=H(()=>{Q(x),v(g)},[x,g]),M=_(()=>F.length===0?null:o.isFetchingNextPage?K("div",{ref:I,className:"p-1 space-y-1 w-full",children:h?h():K(W,{lines:y,height:c,gap:"0.25rem",radius:"sm",className:"p-0.5"})}):o.hasNextPage?K("div",{ref:I,className:"h-1 w-full","aria-hidden":"true"}):w?K("div",{className:"py-2 px-1 text-center text-xs text-neutral-400 dark:text-neutral-500",children:w}):null,[F.length,o.isFetchingNextPage,o.hasNextPage,I,h,y,c,w]);return{selectProps:_(()=>({options:F,isLoading:o.isLoading,searchMode:"server",debounceMs:k,onSearch:A,listFooter:M}),[F,o.isLoading,k,A,M]),query:o,options:F,search:C,setSearch:Q,filters:P,setFilters:v,sentinelRef:I,reset:O}}export{se as useSelectInfiniteQuery,re as useTableQuery};
3
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/table/hooks/useTableQuery.ts","../src/components/select/hooks/useSelectInfiniteQuery.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\r\nimport {\r\n useQuery,\r\n keepPreviousData,\r\n type QueryFunctionContext,\r\n type UseQueryOptions,\r\n type UseQueryResult,\r\n} from \"@tanstack/react-query\";\r\nimport type {\r\n ColumnFiltersState,\r\n OnChangeFn,\r\n PaginationState,\r\n RowData,\r\n SortingState,\r\n Updater,\r\n} from \"@tanstack/react-table\";\r\nimport { DEFAULT_PAGE_SIZE } from \"../constants\";\r\n\r\n/**\r\n * Các tham số truy vấn chuẩn hóa gửi lên API máy chủ.\r\n */\r\nexport interface TableQueryParams {\r\n /**\r\n * Số thứ tự trang (1-indexed: 1, 2, 3...)\r\n */\r\n page: number;\r\n\r\n /**\r\n * Kích thước trang (số dòng trên 1 trang)\r\n */\r\n pageSize: number;\r\n\r\n /**\r\n * ID cột được sắp xếp\r\n */\r\n sortBy?: string;\r\n\r\n /**\r\n * Chiều sắp xếp: \"asc\" (tăng dần) hoặc \"desc\" (giảm dần)\r\n */\r\n sortOrder?: \"asc\" | \"desc\";\r\n\r\n /**\r\n * Danh sách bộ lọc cột dạng từ điển phẳng Record<cột, giá trị>\r\n */\r\n filters?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Các tùy chọn cấu hình cho hook `useTableQuery`.\r\n */\r\nexport interface UseTableQueryOptions<TData extends RowData = RowData, TResponse = unknown, TError = Error> {\r\n /**\r\n * Base query key cho TanStack Query.\r\n * `queryParams` sẽ tự động được thêm vào cuối queryKey: `[...queryKey, queryParams]`.\r\n */\r\n queryKey: readonly unknown[];\r\n\r\n /**\r\n * Hàm gọi API truy vấn dữ liệu từ máy chủ.\r\n * Nhận vào `queryParams` đã chuẩn hóa và `context` của TanStack Query.\r\n */\r\n queryFn: (params: TableQueryParams, context: QueryFunctionContext<readonly unknown[]>) => Promise<TResponse>;\r\n\r\n /**\r\n * Hàm trích xuất mảng dữ liệu các dòng (`TData[]`) từ kết quả API trả về.\r\n * Mặc định tự động kiểm tra `response.data`, `response.items`, `response.rows`, `response.results` hoặc bản thân mảng response.\r\n */\r\n selectData?: (response: TResponse) => TData[];\r\n\r\n /**\r\n * Hàm trích xuất tổng số lượng bản ghi (`rowCount` / `total`) từ kết quả API trả về.\r\n * Mặc định tự động kiểm tra `response.total`, `response.rowCount`, `response.totalCount`, `response.count`.\r\n */\r\n selectRowCount?: (response: TResponse) => number;\r\n\r\n /**\r\n * Cấu hình phân trang ban đầu\r\n */\r\n initialPagination?: {\r\n pageIndex?: number;\r\n pageSize?: number;\r\n };\r\n\r\n /**\r\n * Cấu hình sắp xếp ban đầu\r\n */\r\n initialSorting?: SortingState;\r\n\r\n /**\r\n * Cấu hình bộ lọc cột ban đầu\r\n */\r\n initialColumnFilters?: ColumnFiltersState;\r\n\r\n /**\r\n * Cấu hình từ khóa tìm kiếm ban đầu\r\n */\r\n initialGlobalFilter?: string;\r\n\r\n /**\r\n * Tự động đưa về trang đầu (pageIndex = 0) khi thay đổi tìm kiếm, bộ lọc hoặc sắp xếp.\r\n * @default true\r\n */\r\n autoResetPageIndex?: boolean;\r\n\r\n /**\r\n * Các tùy chọn nâng cao truyền trực tiếp cho hook `useQuery` của TanStack Query\r\n * (ví dụ: `staleTime`, `gcTime`, `refetchOnWindowFocus`, `enabled`...).\r\n */\r\n queryOptions?: Omit<UseQueryOptions<TResponse, TError, TResponse, readonly unknown[]>, \"queryKey\" | \"queryFn\">;\r\n}\r\n\r\n/**\r\n * Kết quả trả về từ hook `useTableQuery`.\r\n */\r\nexport interface UseTableQueryReturn<TData extends RowData = RowData, TResponse = unknown, TError = Error> {\r\n /**\r\n * Tập props trọn gói sẵn sàng truyền thẳng vào `<DataTable {...tableProps} />`\r\n */\r\n tableProps: {\r\n data: TData[];\r\n rowCount: number;\r\n isLoading: boolean;\r\n isRefresh: boolean;\r\n onRefresh: () => void;\r\n manualPagination: true;\r\n manualSorting: true;\r\n manualFiltering: true;\r\n pagination: PaginationState;\r\n onPaginationChange: OnChangeFn<PaginationState>;\r\n sorting: SortingState;\r\n onSortingChange: OnChangeFn<SortingState>;\r\n columnFilters: ColumnFiltersState;\r\n onColumnFiltersChange: OnChangeFn<ColumnFiltersState>;\r\n globalFilter: string;\r\n onGlobalFilterChange: (filter: string) => void;\r\n };\r\n\r\n /**\r\n * Instance query đầy đủ từ TanStack Query\r\n */\r\n query: UseQueryResult<TResponse, TError>;\r\n\r\n /**\r\n * Tham số truy vấn hiện tại (dùng để debug, ghi log, đồng bộ URL query string, hoặc xuất Excel)\r\n */\r\n queryParams: TableQueryParams;\r\n\r\n /**\r\n * Đặt lại toàn bộ phân trang, sắp xếp, tìm kiếm và bộ lọc về giá trị mặc định ban đầu\r\n */\r\n resetAll: () => void;\r\n\r\n /**\r\n * Đổi trang thủ công (1-indexed: 1, 2, 3...)\r\n */\r\n setPage: (page: number) => void;\r\n\r\n /**\r\n * Đổi số dòng trên mỗi trang thủ công\r\n */\r\n setPageSize: (pageSize: number) => void;\r\n\r\n /**\r\n * Đổi từ khóa tìm kiếm toàn bảng (lọc client-side)\r\n */\r\n setGlobalFilter: (filter: string) => void;\r\n\r\n /**\r\n * Cập nhật trạng thái sắp xếp\r\n */\r\n setSorting: (sorting: SortingState | ((prev: SortingState) => SortingState)) => void;\r\n\r\n /**\r\n * Cập nhật trạng thái bộ lọc cột\r\n */\r\n setColumnFilters: (filters: ColumnFiltersState | ((prev: ColumnFiltersState) => ColumnFiltersState)) => void;\r\n}\r\n\r\n/**\r\n * Trích xuất mặc định danh sách dòng dữ liệu từ API response.\r\n */\r\nfunction defaultSelectData<TData>(response: unknown): TData[] {\r\n if (!response) return [];\r\n if (Array.isArray(response)) return response as TData[];\r\n if (typeof response === \"object\") {\r\n const obj = response as Record<string, unknown>;\r\n if (Array.isArray(obj.data)) return obj.data as TData[];\r\n if (Array.isArray(obj.items)) return obj.items as TData[];\r\n if (Array.isArray(obj.rows)) return obj.rows as TData[];\r\n if (Array.isArray(obj.results)) return obj.results as TData[];\r\n }\r\n return [];\r\n}\r\n\r\n/**\r\n * Trích xuất mặc định tổng số lượng bản ghi từ API response.\r\n */\r\nfunction defaultSelectRowCount(response: unknown): number {\r\n if (!response) return 0;\r\n if (Array.isArray(response)) return response.length;\r\n if (typeof response === \"object\") {\r\n const obj = response as Record<string, unknown>;\r\n const total = obj.total ?? obj.rowCount ?? obj.totalCount ?? obj.count;\r\n if (typeof total === \"number\") return total;\r\n if (typeof total === \"string\") {\r\n const parsed = Number(total);\r\n if (!isNaN(parsed)) return parsed;\r\n }\r\n }\r\n return 0;\r\n}\r\n\r\n/**\r\n * Helper giải quyết Updater của TanStack Table\r\n */\r\nfunction resolveUpdater<T>(updater: Updater<T>, prev: T): T {\r\n return typeof updater === \"function\" ? (updater as (old: T) => T)(prev) : updater;\r\n}\r\n\r\n/**\r\n * Hook Adapter `useTableQuery` tích hợp TanStack Table v9 và TanStack Query v5.\r\n *\r\n * Tính năng:\r\n * - Đồng bộ hai chiều trạng thái bảng (Pagination, Sorting, Filtering, Search) với server API.\r\n * - Tự động định dạng tham số `TableQueryParams`: `page` (1-indexed), `pageSize`, `search`, `sortBy`, `sortOrder`, `filters`.\r\n * - Tự động gắn `queryParams` vào `queryKey` của TanStack Query để kích hoạt cache/refetch thông minh.\r\n * - Hỗ trợ phân trang mượt mà bằng `placeholderData: keepPreviousData` (không bị nhấp nháy Skeleton khi chuyển trang).\r\n * - Cung cấp `tableProps` dựng sẵn truyền trực tiếp vào `<DataTable {...tableProps} />`.\r\n */\r\nexport function useTableQuery<TData extends RowData = RowData, TResponse = unknown, TError = Error>(\r\n options: UseTableQueryOptions<TData, TResponse, TError>\r\n): UseTableQueryReturn<TData, TResponse, TError> {\r\n const {\r\n queryKey,\r\n queryFn,\r\n selectData = defaultSelectData,\r\n selectRowCount = defaultSelectRowCount,\r\n initialPagination,\r\n initialSorting,\r\n initialColumnFilters,\r\n initialGlobalFilter,\r\n autoResetPageIndex = true,\r\n queryOptions,\r\n } = options;\r\n\r\n // 1. Quản lý trạng thái bảng (Table states)\r\n const [pagination, setPagination] = useState<PaginationState>({\r\n pageIndex: initialPagination?.pageIndex ?? 0,\r\n pageSize: initialPagination?.pageSize ?? DEFAULT_PAGE_SIZE,\r\n });\r\n\r\n const [sorting, setSorting] = useState<SortingState>(initialSorting ?? []);\r\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(initialColumnFilters ?? []);\r\n const [globalFilter, setGlobalFilter] = useState<string>(initialGlobalFilter ?? \"\");\r\n\r\n // 2. Chuẩn hóa tham số query gửi lên server\r\n const queryParams = useMemo<TableQueryParams>(() => {\r\n const params: TableQueryParams = {\r\n page: pagination.pageIndex + 1,\r\n pageSize: pagination.pageSize,\r\n };\r\n\r\n const firstSort = sorting[0];\r\n if (firstSort) {\r\n params.sortBy = firstSort.id;\r\n params.sortOrder = firstSort.desc ? \"desc\" : \"asc\";\r\n }\r\n\r\n if (columnFilters.length > 0) {\r\n const filtersDict: Record<string, unknown> = {};\r\n columnFilters.forEach((cf) => {\r\n filtersDict[cf.id] = cf.value;\r\n });\r\n params.filters = filtersDict;\r\n }\r\n\r\n return params;\r\n }, [pagination.pageIndex, pagination.pageSize, sorting, columnFilters]);\r\n\r\n // 3. Ghép queryKey với queryParams\r\n const fullQueryKey = useMemo(() => [...queryKey, queryParams] as const, [queryKey, queryParams]);\r\n\r\n // 4. Gọi useQuery của TanStack Query v5\r\n const query = useQuery<TResponse, TError, TResponse, readonly unknown[]>({\r\n queryKey: fullQueryKey,\r\n queryFn: (ctx) => queryFn(queryParams, ctx),\r\n placeholderData: keepPreviousData,\r\n ...queryOptions,\r\n });\r\n\r\n // 5. Trích xuất dữ liệu hàng và tổng số lượng\r\n const data = useMemo<TData[]>(() => {\r\n return query.data ? selectData(query.data) : [];\r\n }, [query.data, selectData]);\r\n\r\n const rowCount = useMemo<number>(() => {\r\n return query.data ? selectRowCount(query.data) : 0;\r\n }, [query.data, selectRowCount]);\r\n\r\n // 6. Xử lý các sự kiện thay đổi trạng thái kèm autoResetPageIndex\r\n const handlePaginationChange: OnChangeFn<PaginationState> = useCallback((updater) => {\r\n setPagination((prev) => resolveUpdater(updater, prev));\r\n }, []);\r\n\r\n const handleSortingChange: OnChangeFn<SortingState> = useCallback(\r\n (updater) => {\r\n setSorting((prev) => resolveUpdater(updater, prev));\r\n if (autoResetPageIndex) {\r\n setPagination((prev) => (prev.pageIndex === 0 ? prev : { ...prev, pageIndex: 0 }));\r\n }\r\n },\r\n [autoResetPageIndex]\r\n );\r\n\r\n const handleColumnFiltersChange: OnChangeFn<ColumnFiltersState> = useCallback(\r\n (updater) => {\r\n setColumnFilters((prev) => resolveUpdater(updater, prev));\r\n if (autoResetPageIndex) {\r\n setPagination((prev) => (prev.pageIndex === 0 ? prev : { ...prev, pageIndex: 0 }));\r\n }\r\n },\r\n [autoResetPageIndex]\r\n );\r\n\r\n const handleGlobalFilterChange = useCallback(\r\n (filter: string) => {\r\n setGlobalFilter(filter);\r\n if (autoResetPageIndex) {\r\n setPagination((prev) => (prev.pageIndex === 0 ? prev : { ...prev, pageIndex: 0 }));\r\n }\r\n },\r\n [autoResetPageIndex]\r\n );\r\n\r\n // 7. Các hàm tiện ích bổ sung\r\n const resetAll = useCallback(() => {\r\n setPagination({\r\n pageIndex: initialPagination?.pageIndex ?? 0,\r\n pageSize: initialPagination?.pageSize ?? DEFAULT_PAGE_SIZE,\r\n });\r\n setSorting(initialSorting ?? []);\r\n setColumnFilters(initialColumnFilters ?? []);\r\n setGlobalFilter(initialGlobalFilter ?? \"\");\r\n }, [initialPagination, initialSorting, initialColumnFilters, initialGlobalFilter]);\r\n\r\n const setPage = useCallback((page: number) => {\r\n setPagination((prev) => ({\r\n ...prev,\r\n pageIndex: Math.max(0, page - 1),\r\n }));\r\n }, []);\r\n\r\n const setPageSize = useCallback((pageSize: number) => {\r\n setPagination({\r\n pageIndex: 0,\r\n pageSize,\r\n });\r\n }, []);\r\n\r\n const setGlobalFilterValue = useCallback(\r\n (filter: string) => {\r\n handleGlobalFilterChange(filter);\r\n },\r\n [handleGlobalFilterChange]\r\n );\r\n\r\n // 8. Đóng gói tableProps truyền cho DataTable\r\n const { isLoading, isRefetching, refetch } = query;\r\n\r\n const handleRefresh = useCallback(() => {\r\n void refetch();\r\n }, [refetch]);\r\n\r\n const tableProps = useMemo(\r\n () => ({\r\n data,\r\n rowCount,\r\n isLoading,\r\n isRefresh: isRefetching && !isLoading,\r\n onRefresh: handleRefresh,\r\n manualPagination: true as const,\r\n manualSorting: true as const,\r\n manualFiltering: true as const,\r\n pagination,\r\n onPaginationChange: handlePaginationChange,\r\n sorting,\r\n onSortingChange: handleSortingChange,\r\n columnFilters,\r\n onColumnFiltersChange: handleColumnFiltersChange,\r\n globalFilter,\r\n onGlobalFilterChange: handleGlobalFilterChange,\r\n }),\r\n [\r\n data,\r\n rowCount,\r\n isLoading,\r\n isRefetching,\r\n handleRefresh,\r\n pagination,\r\n handlePaginationChange,\r\n sorting,\r\n handleSortingChange,\r\n columnFilters,\r\n handleColumnFiltersChange,\r\n globalFilter,\r\n handleGlobalFilterChange,\r\n ]\r\n );\r\n\r\n return {\r\n tableProps,\r\n query,\r\n queryParams,\r\n resetAll,\r\n setPage,\r\n setPageSize,\r\n setGlobalFilter: setGlobalFilterValue,\r\n setSorting,\r\n setColumnFilters,\r\n };\r\n}\r\n","import React, {\r\n useCallback,\r\n useMemo,\r\n useState,\r\n type ReactNode,\r\n} from \"react\";\r\nimport {\r\n useInfiniteQuery,\r\n type InfiniteData,\r\n type QueryFunctionContext,\r\n type UseInfiniteQueryOptions,\r\n type UseInfiniteQueryResult,\r\n} from \"@tanstack/react-query\";\r\nimport type { SelectOptionItem } from \"../types\";\r\nimport { useInfiniteScroll, type UseInfiniteScrollOptions } from \"@/hooks/useInfiniteScroll\";\r\nimport Skeleton from \"@/components/skeleton/Skeleton\";\r\n\r\n/**\r\n * Các tham số truy vấn chuẩn hóa được chuyển tới hàm `queryFn`.\r\n */\r\nexport interface SelectQueryParams<\r\n TPageParam = number,\r\n TFilters extends Record<string, unknown> = Record<string, unknown>,\r\n> {\r\n /**\r\n * Tham số phân trang hiện tại (trang hiện tại hoặc cursor).\r\n */\r\n pageParam: TPageParam;\r\n\r\n /**\r\n * Từ khóa tìm kiếm từ ô Select.\r\n */\r\n search: string;\r\n\r\n /**\r\n * Bộ lọc bổ sung từ menu filter của Select.\r\n */\r\n filters: TFilters;\r\n}\r\n\r\n/**\r\n * Hàm hỗ trợ tự động trích xuất mảng dữ liệu từ các cấu trúc response phổ biến.\r\n */\r\nfunction extractRawOptions(response: unknown): unknown[] {\r\n if (!response) return [];\r\n if (Array.isArray(response)) return response;\r\n if (typeof response !== \"object\") return [];\r\n\r\n const record = response as Record<string, unknown>;\r\n if (Array.isArray(record.data)) return record.data;\r\n if (Array.isArray(record.items)) return record.items;\r\n if (Array.isArray(record.options)) return record.options;\r\n if (Array.isArray(record.results)) return record.results;\r\n if (Array.isArray(record.rows)) return record.rows;\r\n\r\n return [];\r\n}\r\n\r\n/**\r\n * Các tùy chọn cấu hình cho hook `useSelectInfiniteQuery`.\r\n */\r\nexport interface UseSelectInfiniteQueryOptions<\r\n TData = unknown,\r\n TResponse = unknown,\r\n TPageParam = number,\r\n TFilters extends Record<string, unknown> = Record<string, unknown>,\r\n TError = Error,\r\n> {\r\n /**\r\n * Base query key cho TanStack Query.\r\n * `[{ search, filters }]` sẽ tự động được thêm vào cuối queryKey:\r\n * `[...queryKey, { search, filters }]`.\r\n */\r\n queryKey: readonly unknown[];\r\n\r\n /**\r\n * Hàm gọi API truy vấn dữ liệu từ máy chủ theo từng trang.\r\n * Nhận vào `SelectQueryParams` đã chuẩn hóa và `context` của TanStack Query.\r\n */\r\n queryFn: (\r\n params: SelectQueryParams<TPageParam, TFilters>,\r\n context: QueryFunctionContext<readonly unknown[], TPageParam>\r\n ) => Promise<TResponse>;\r\n\r\n /**\r\n * Giá trị tham số trang đầu tiên (initialPageParam).\r\n * @default 1\r\n */\r\n initialPageParam?: TPageParam;\r\n\r\n /**\r\n * Hàm xác định `pageParam` cho trang tiếp theo.\r\n * Trả về `undefined` hoặc `null` khi không còn dữ liệu tiếp theo.\r\n */\r\n getNextPageParam?: (\r\n lastPage: TResponse,\r\n allPages: TResponse[],\r\n lastPageParam: TPageParam,\r\n allPageParams: TPageParam[]\r\n ) => TPageParam | undefined | null;\r\n\r\n /**\r\n * Hàm xác định `pageParam` cho trang trước đó (nếu có).\r\n */\r\n getPreviousPageParam?: (\r\n firstPage: TResponse,\r\n allPages: TResponse[],\r\n firstPageParam: TPageParam,\r\n allPageParams: TPageParam[]\r\n ) => TPageParam | undefined | null;\r\n\r\n /**\r\n * Hàm trích xuất danh sách options (`SelectOptionItem<TData>[]`) từ mỗi `response` trang.\r\n * Nếu không truyền, mặc định sẽ kiểm tra `data`, `items`, `options`, `results`, `rows` hoặc chính `response`.\r\n */\r\n selectOptions?: (response: TResponse) => SelectOptionItem<TData>[];\r\n\r\n /**\r\n * Hàm biến đổi từng phần tử thô (raw entity) thành `SelectOptionItem<TData>`.\r\n */\r\n mapOption?: (item: unknown, index: number) => SelectOptionItem<TData>;\r\n\r\n /**\r\n * Thời gian debounce từ khóa tìm kiếm (tính theo ms).\r\n * @default 300\r\n */\r\n debounceMs?: number;\r\n\r\n /**\r\n * Từ khóa tìm kiếm ban đầu.\r\n */\r\n initialSearch?: string;\r\n\r\n /**\r\n * Giá trị bộ lọc menu ban đầu.\r\n */\r\n initialFilters?: TFilters;\r\n\r\n /**\r\n * Danh sách options ban đầu ghim sẵn (ví dụ các options đã chọn trước đó cần bảo lưu).\r\n */\r\n initialOptions?: SelectOptionItem<TData>[];\r\n\r\n /**\r\n * Số dòng Skeleton hiển thị khi đang tải thêm trang tiếp theo.\r\n * @default 2\r\n */\r\n skeletonLines?: number;\r\n\r\n /**\r\n * Chiều cao của mỗi dòng Skeleton khi đang tải thêm trang.\r\n * @default \"1.75rem\"\r\n */\r\n skeletonHeight?: number | string;\r\n\r\n /**\r\n * Tùy biến render khi đang tải thêm trang tiếp theo (thay thế Skeleton mặc định).\r\n */\r\n renderLoadingMore?: () => ReactNode;\r\n\r\n /**\r\n * Thông báo hiển thị khi đã tải hết toàn bộ dữ liệu ở đáy danh sách (tùy chọn).\r\n */\r\n endMessage?: ReactNode;\r\n\r\n /**\r\n * Tùy chọn truyền trực tiếp cho hook `useInfiniteScroll`.\r\n */\r\n scrollOptions?: Partial<Omit<UseInfiniteScrollOptions, \"onLoadMore\" | \"hasMore\" | \"isLoading\">>;\r\n\r\n /**\r\n * Các tùy chọn nâng cao truyền trực tiếp cho hook `useInfiniteQuery` của TanStack Query.\r\n */\r\n queryOptions?: Omit<\r\n UseInfiniteQueryOptions<TResponse, TError, InfiniteData<TResponse>, readonly unknown[], TPageParam>,\r\n \"queryKey\" | \"queryFn\" | \"initialPageParam\" | \"getNextPageParam\" | \"getPreviousPageParam\"\r\n >;\r\n}\r\n\r\n/**\r\n * Kết quả trả về từ hook `useSelectInfiniteQuery`.\r\n */\r\nexport interface UseSelectInfiniteQueryReturn<\r\n TData = unknown,\r\n TResponse = unknown,\r\n TFilters extends Record<string, unknown> = Record<string, unknown>,\r\n TError = Error,\r\n> {\r\n /**\r\n * Bộ props trọn gói sẵn sàng truyền thẳng vào `<Select {...selectProps} />` hoặc `<MultiSelect {...selectProps} />`\r\n */\r\n selectProps: {\r\n options: SelectOptionItem<TData>[];\r\n isLoading: boolean;\r\n searchMode: \"server\";\r\n debounceMs: number;\r\n onSearch: (query: string, filters: TFilters) => void;\r\n listFooter: ReactNode;\r\n };\r\n\r\n /**\r\n * Instance query đầy đủ từ TanStack Query\r\n */\r\n query: UseInfiniteQueryResult<InfiniteData<TResponse>, TError>;\r\n\r\n /**\r\n * Toàn bộ danh sách options đã gom tụ từ tất cả các trang\r\n */\r\n options: SelectOptionItem<TData>[];\r\n\r\n /**\r\n * Từ khóa tìm kiếm hiện tại (đã được Select debounce qua onSearch)\r\n */\r\n search: string;\r\n\r\n /**\r\n * Phương thức cập nhật từ khóa tìm kiếm\r\n */\r\n setSearch: (search: string) => void;\r\n\r\n /**\r\n * Bộ lọc menu hiện tại\r\n */\r\n filters: TFilters;\r\n\r\n /**\r\n * Phương thức cập nhật bộ lọc menu\r\n */\r\n setFilters: (filters: TFilters | ((prev: TFilters) => TFilters)) => void;\r\n\r\n /**\r\n * Ref gắn vào phần tử sentinel (IntersectionObserver)\r\n */\r\n sentinelRef: (node: HTMLElement | null) => void;\r\n\r\n /**\r\n * Đặt lại toàn bộ tìm kiếm, bộ lọc về giá trị ban đầu\r\n */\r\n reset: () => void;\r\n}\r\n\r\nconst EMPTY_FILTERS: Record<string, unknown> = {};\r\n\r\n/**\r\n * Hook `useSelectInfiniteQuery` kết hợp TanStack Query `useInfiniteQuery` với `useInfiniteScroll`\r\n * dành riêng cho `<Select />` và `<MultiSelect />` ở chế độ máy chủ (`searchMode=\"server\"`).\r\n */\r\nexport function useSelectInfiniteQuery<\r\n TData = unknown,\r\n TResponse = unknown,\r\n TPageParam = number,\r\n TFilters extends Record<string, unknown> = Record<string, unknown>,\r\n TError = Error,\r\n>({\r\n queryKey,\r\n queryFn,\r\n initialPageParam = 1 as unknown as TPageParam,\r\n getNextPageParam,\r\n getPreviousPageParam,\r\n selectOptions,\r\n mapOption,\r\n debounceMs = 300,\r\n initialSearch = \"\",\r\n initialFilters = EMPTY_FILTERS as TFilters,\r\n initialOptions,\r\n skeletonLines = 2,\r\n skeletonHeight = \"1.75rem\",\r\n renderLoadingMore,\r\n endMessage,\r\n scrollOptions,\r\n queryOptions,\r\n}: UseSelectInfiniteQueryOptions<TData, TResponse, TPageParam, TFilters, TError>): UseSelectInfiniteQueryReturn<TData, TResponse, TFilters, TError> {\r\n // 1. Quản lý từ khóa tìm kiếm & bộ lọc menu\r\n const [search, setSearch] = useState(initialSearch);\r\n const [filters, setFilters] = useState<TFilters>(initialFilters);\r\n\r\n // 2. Xây dựng full queryKey kết hợp search & filters\r\n const fullQueryKey = useMemo(\r\n () => [...queryKey, { search, filters }] as const,\r\n [queryKey, search, filters]\r\n );\r\n\r\n // 4. Default getNextPageParam thông minh\r\n const resolvedGetNextPageParam = useCallback(\r\n (\r\n lastPage: TResponse,\r\n allPages: TResponse[],\r\n lastPageParam: TPageParam,\r\n allPageParams: TPageParam[]\r\n ): TPageParam | undefined | null => {\r\n if (getNextPageParam) {\r\n return getNextPageParam(lastPage, allPages, lastPageParam, allPageParams);\r\n }\r\n\r\n if (!lastPage || typeof lastPage !== \"object\") return undefined;\r\n const record = lastPage as Record<string, unknown>;\r\n\r\n if (typeof record.nextPage === \"number\" || typeof record.nextPage === \"string\") {\r\n return record.nextPage as unknown as TPageParam;\r\n }\r\n if (typeof record.next_page === \"number\" || typeof record.next_page === \"string\") {\r\n return record.next_page as unknown as TPageParam;\r\n }\r\n if (typeof record.nextCursor === \"string\" || typeof record.nextCursor === \"number\") {\r\n return record.nextCursor as unknown as TPageParam;\r\n }\r\n if (typeof record.next_cursor === \"string\" || typeof record.next_cursor === \"number\") {\r\n return record.next_cursor as unknown as TPageParam;\r\n }\r\n\r\n if (record.hasMore === false || record.has_more === false || record.hasNextPage === false) {\r\n return undefined;\r\n }\r\n\r\n if (typeof lastPageParam === \"number\") {\r\n const rawItems = extractRawOptions(lastPage);\r\n if (rawItems.length === 0) return undefined;\r\n\r\n const total =\r\n typeof record.total === \"number\"\r\n ? record.total\r\n : typeof record.totalCount === \"number\"\r\n ? record.totalCount\r\n : typeof record.count === \"number\"\r\n ? record.count\r\n : undefined;\r\n\r\n if (total !== undefined) {\r\n const currentCount = allPages.reduce((acc, p) => acc + extractRawOptions(p).length, 0);\r\n if (currentCount >= total) return undefined;\r\n }\r\n\r\n return (lastPageParam + 1) as unknown as TPageParam;\r\n }\r\n\r\n return undefined;\r\n },\r\n [getNextPageParam]\r\n );\r\n\r\n // 5. TanStack Query useInfiniteQuery\r\n const query = useInfiniteQuery<TResponse, TError, InfiniteData<TResponse>, readonly unknown[], TPageParam>({\r\n queryKey: fullQueryKey,\r\n queryFn: (context) => {\r\n return queryFn(\r\n {\r\n pageParam: context.pageParam as TPageParam,\r\n search,\r\n filters,\r\n },\r\n context\r\n );\r\n },\r\n initialPageParam,\r\n getNextPageParam: resolvedGetNextPageParam,\r\n getPreviousPageParam,\r\n ...queryOptions,\r\n });\r\n\r\n // 6. Trích xuất và gom tụ options từ tất cả các trang\r\n const options = useMemo<SelectOptionItem<TData>[]>(() => {\r\n const pages = query.data?.pages ?? [];\r\n const allItems: SelectOptionItem<TData>[] = [];\r\n const seen = new Set<string | number>();\r\n\r\n // Nếu có initialOptions, đưa vào danh sách trước\r\n if (initialOptions && initialOptions.length > 0) {\r\n for (const opt of initialOptions) {\r\n if (!seen.has(opt.value)) {\r\n seen.add(opt.value);\r\n allItems.push(opt);\r\n }\r\n }\r\n }\r\n\r\n for (const page of pages) {\r\n let pageOptions: SelectOptionItem<TData>[] = [];\r\n\r\n if (selectOptions) {\r\n pageOptions = selectOptions(page);\r\n } else {\r\n const raw = extractRawOptions(page);\r\n if (mapOption) {\r\n pageOptions = raw.map((item, index) => mapOption(item, index));\r\n } else {\r\n pageOptions = raw as SelectOptionItem<TData>[];\r\n }\r\n }\r\n\r\n for (const opt of pageOptions) {\r\n if (opt && opt.value !== undefined && !seen.has(opt.value)) {\r\n seen.add(opt.value);\r\n allItems.push(opt);\r\n }\r\n }\r\n }\r\n\r\n return allItems;\r\n }, [query.data?.pages, selectOptions, mapOption, initialOptions]);\r\n\r\n // 7. useInfiniteScroll để tải trang tiếp theo khi người dùng cuộn đến cuối\r\n const { sentinelRef } = useInfiniteScroll({\r\n onLoadMore: () => {\r\n if (query.hasNextPage && !query.isFetchingNextPage) {\r\n query.fetchNextPage();\r\n }\r\n },\r\n hasMore: Boolean(query.hasNextPage),\r\n isLoading: query.isFetchingNextPage || query.isLoading,\r\n disabled: query.isError,\r\n rootMargin: scrollOptions?.rootMargin ?? \"80px\",\r\n threshold: scrollOptions?.threshold ?? 0,\r\n root: scrollOptions?.root,\r\n });\r\n\r\n // 8. Handler nhận search từ Select component\r\n const handleSearch = useCallback((newSearch: string, newFilters: TFilters) => {\r\n setSearch(newSearch);\r\n setFilters(newFilters);\r\n }, []);\r\n\r\n // 9. Reset state\r\n const reset = useCallback(() => {\r\n setSearch(initialSearch);\r\n setFilters(initialFilters);\r\n }, [initialSearch, initialFilters]);\r\n\r\n // 10. Giao diện Skeleton / Sentinel dưới đáy danh sách (listFooter)\r\n const listFooter = useMemo<ReactNode>(() => {\r\n // Nếu chưa có option nào thì để màn hình loading chính của SelectMenu hiển thị\r\n if (options.length === 0) return null;\r\n\r\n if (query.isFetchingNextPage) {\r\n return (\r\n <div ref={sentinelRef} className=\"p-1 space-y-1 w-full\">\r\n {renderLoadingMore ? (\r\n renderLoadingMore()\r\n ) : (\r\n <Skeleton\r\n lines={skeletonLines}\r\n height={skeletonHeight}\r\n gap=\"0.25rem\"\r\n radius=\"sm\"\r\n className=\"p-0.5\"\r\n />\r\n )}\r\n </div>\r\n );\r\n }\r\n\r\n if (query.hasNextPage) {\r\n return <div ref={sentinelRef} className=\"h-1 w-full\" aria-hidden=\"true\" />;\r\n }\r\n\r\n if (endMessage) {\r\n return (\r\n <div className=\"py-2 px-1 text-center text-xs text-neutral-400 dark:text-neutral-500\">\r\n {endMessage}\r\n </div>\r\n );\r\n }\r\n\r\n return null;\r\n }, [\r\n options.length,\r\n query.isFetchingNextPage,\r\n query.hasNextPage,\r\n sentinelRef,\r\n renderLoadingMore,\r\n skeletonLines,\r\n skeletonHeight,\r\n endMessage,\r\n ]);\r\n\r\n // 11. Đóng gói selectProps trọn gói\r\n const selectProps = useMemo(\r\n () => ({\r\n options,\r\n isLoading: query.isLoading,\r\n searchMode: \"server\" as const,\r\n debounceMs,\r\n onSearch: handleSearch,\r\n listFooter,\r\n }),\r\n [options, query.isLoading, debounceMs, handleSearch, listFooter]\r\n );\r\n\r\n return {\r\n selectProps,\r\n query,\r\n options,\r\n search,\r\n setSearch,\r\n filters,\r\n setFilters,\r\n sentinelRef,\r\n reset,\r\n };\r\n}\r\n\r\nexport default useSelectInfiniteQuery;\r\n"],"mappings":"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","names":["useCallback","useMemo","useState","useQuery","keepPreviousData","defaultSelectData","response","obj","defaultSelectRowCount","total","parsed","resolveUpdater","updater","prev","useTableQuery","options","queryKey","queryFn","selectData","selectRowCount","initialPagination","initialSorting","initialColumnFilters","initialGlobalFilter","autoResetPageIndex","queryOptions","pagination","setPagination","useState","DEFAULT_PAGE_SIZE","sorting","setSorting","columnFilters","setColumnFilters","globalFilter","setGlobalFilter","queryParams","useMemo","params","firstSort","filtersDict","cf","fullQueryKey","query","useQuery","ctx","keepPreviousData","data","rowCount","handlePaginationChange","useCallback","handleSortingChange","handleColumnFiltersChange","handleGlobalFilterChange","filter","resetAll","setPage","page","setPageSize","pageSize","setGlobalFilterValue","isLoading","isRefetching","refetch","handleRefresh","useCallback","useMemo","useState","useInfiniteQuery","jsx","extractRawOptions","response","record","EMPTY_FILTERS","useSelectInfiniteQuery","queryKey","queryFn","initialPageParam","getNextPageParam","getPreviousPageParam","selectOptions","mapOption","debounceMs","initialSearch","initialFilters","initialOptions","skeletonLines","skeletonHeight","renderLoadingMore","endMessage","scrollOptions","queryOptions","search","setSearch","useState","filters","setFilters","fullQueryKey","useMemo","resolvedGetNextPageParam","useCallback","lastPage","allPages","lastPageParam","allPageParams","total","acc","p","query","useInfiniteQuery","context","options","pages","allItems","seen","opt","page","pageOptions","raw","item","index","sentinelRef","useInfiniteScroll","handleSearch","newSearch","newFilters","reset","listFooter","Skeleton"]}