@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,124 @@
1
+ # 📊 Hook `useTableQuery` (`@openway/ui/query`)
2
+
3
+ Hook adapter chuyên dụng kết nối **TanStack Query v5** (`useQuery`) với component `<Table />`, tự động hóa toàn bộ quy trình phân trang máy chủ (Server-side pagination), sắp xếp nhiều cột (Sorting), lọc dữ liệu (Filtering), và tối ưu UX qua `keepPreviousData`.
4
+
5
+ ---
6
+
7
+ ## 🌟 Điểm nổi bật
8
+
9
+ - **Tự động đồng bộ với Table**: Trả về trọn gói `tableProps` sẵn sàng spread thẳng vào `<Table {...tableProps} />`.
10
+ - **Server Pagination**: Quản lý `page` (1-indexed), `pageSize`, tự động chuyển trang và tính toán tổng số trang (`pageCount`).
11
+ - **Server Sorting**: Đồng bộ `sortBy` và `sortOrder` ("asc" | "desc") từ trạng thái click header của Table gửi lên server.
12
+ - **Server Filtering & Auto-Reset**: Tự động chuyển đổi mảng filter của TanStack Table thành dictionary phẳng `Record<string, unknown>`, tự động đưa trang về trang 1 khi người dùng thay đổi bộ lọc (`autoResetPageIndex`).
13
+ - **Giữ dữ liệu mượt mà (`keepPreviousData`)**: Dữ liệu trang cũ vẫn hiển thị trong lúc trang mới đang tải ngầm, loại bỏ hiện tượng nhấp nháy trắng bảng.
14
+ - **Zero `any`**: Type-safe 100% với Generic type `TData` và `TResponse`.
15
+
16
+ ---
17
+
18
+ ## 🚀 Import
19
+
20
+ ```tsx
21
+ import { useTableQuery } from "@openway/ui/query";
22
+ import type {
23
+ TableQueryParams,
24
+ UseTableQueryOptions,
25
+ UseTableQueryReturn,
26
+ } from "@openway/ui/query";
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 📖 Hướng dẫn sử dụng
32
+
33
+ ### Phân trang, Sắp xếp & Lọc phía Máy chủ
34
+
35
+ ```tsx
36
+ import { Table, type ColumnDef } from "@openway/ui";
37
+ import { useTableQuery } from "@openway/ui/query";
38
+
39
+ interface User {
40
+ id: string;
41
+ name: string;
42
+ email: string;
43
+ role: string;
44
+ }
45
+
46
+ interface UserApiResponse {
47
+ data: User[];
48
+ total: number;
49
+ }
50
+
51
+ const columns: ColumnDef<User>[] = [
52
+ { accessorKey: "name", header: "Họ và tên", enableSorting: true },
53
+ { accessorKey: "email", header: "Email" },
54
+ { accessorKey: "role", header: "Vai trò" },
55
+ ];
56
+
57
+ export function UserManagementTable() {
58
+ const { tableProps, query, page, setPage } = useTableQuery<User, UserApiResponse>({
59
+ queryKey: ["users-table"],
60
+ queryFn: async (params) => {
61
+ const searchParams = new URLSearchParams({
62
+ page: String(params.page),
63
+ pageSize: String(params.pageSize),
64
+ ...(params.sortBy && { sortBy: params.sortBy, sortOrder: params.sortOrder ?? "asc" }),
65
+ });
66
+ const res = await fetch(`/api/users?${searchParams}`);
67
+ return res.json();
68
+ },
69
+ // Tự động bóc tách mảng dữ liệu và tổng số dòng từ response
70
+ selectData: (res) => res.data,
71
+ selectTotal: (res) => res.total,
72
+ initialPageSize: 10,
73
+ });
74
+
75
+ return (
76
+ <div className="space-y-4">
77
+ <Table
78
+ {...tableProps}
79
+ columns={columns}
80
+ border
81
+ striped
82
+ hoverable
83
+ />
84
+ </div>
85
+ );
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 🎛️ Bảng Options (`UseTableQueryOptions`)
92
+
93
+ | Tên Option | Kiểu dữ liệu | Mặc định | Mô tả |
94
+ | :--- | :--- | :--- | :--- |
95
+ | `queryKey` | `readonly unknown[]` | **Bắt buộc** | Query key gốc của TanStack Query. |
96
+ | `queryFn` | `(params, context) => Promise<TResponse>` | **Bắt buộc** | Hàm fetch dữ liệu từ API nhận `TableQueryParams`. |
97
+ | `selectData` | `(res) => TData[]` | Tự trích xuất `data/items/results/rows` | Hàm lấy mảng dữ liệu từ API response. |
98
+ | `selectTotal` | `(res) => number` | Tự trích xuất `total/totalCount/count` | Hàm lấy tổng số bản ghi từ API response. |
99
+ | `initialPage` | `number` | `1` | Trang bắt đầu (1-indexed). |
100
+ | `initialPageSize` | `number` | `10` | Số dòng hiển thị mỗi trang. |
101
+ | `autoResetPageIndex` | `boolean` | `true` | Tự động quay về trang 1 khi đổi bộ lọc hoặc sắp xếp. |
102
+ | `queryOptions` | `Omit<UseQueryOptions, ...>` | `undefined` | Các cấu hình nâng cao của TanStack Query (`staleTime`, `refetchInterval`...). |
103
+
104
+ ---
105
+
106
+ ## 📦 Giá trị trả về (`UseTableQueryReturn`)
107
+
108
+ - `tableProps`: Gói props truyền thẳng vào `<Table />`:
109
+ - `data: TData[]`
110
+ - `pageCount: number`
111
+ - `pagination: { pageIndex, pageSize }`
112
+ - `onPaginationChange: OnChangeFn<PaginationState>`
113
+ - `sorting: SortingState`
114
+ - `onSortingChange: OnChangeFn<SortingState>`
115
+ - `columnFilters: ColumnFiltersState`
116
+ - `onColumnFiltersChange: OnChangeFn<ColumnFiltersState>`
117
+ - `isLoading: boolean`
118
+ - `manualPagination: true`
119
+ - `manualSorting: true`
120
+ - `manualFiltering: true`
121
+ - `query`: Query result từ `useQuery`.
122
+ - `page`, `setPage`: Xem và thay đổi số trang hiện tại.
123
+ - `pageSize`, `setPageSize`: Xem và thay đổi số dòng/trang.
124
+ - `resetFilters`: Đặt lại toàn bộ bộ lọc.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openway/ui",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -15,49 +15,68 @@
15
15
  "types": "./dist/index.d.ts",
16
16
  "import": "./dist/index.js",
17
17
  "require": "./dist/index.cjs"
18
+ },
19
+ "./query": {
20
+ "types": "./dist/query.d.ts",
21
+ "import": "./dist/query.js",
22
+ "require": "./dist/query.cjs"
18
23
  }
19
24
  },
20
25
  "files": [
21
26
  "dist",
27
+ "docs",
22
28
  "README.md",
23
29
  "LICENSE"
24
30
  ],
25
- "scripts": {
26
- "build": "tsup",
27
- "prepublishOnly": "pnpm build",
28
- "lint": "eslint",
29
- "check-types": "tsc --noEmit",
30
- "doctor": "pnpm dlx react-doctor@latest",
31
- "cypress:open": "cypress open --component",
32
- "cypress:run": "cypress run --component"
33
- },
34
31
  "peerDependencies": {
32
+ "@tanstack/react-query": ">=5.0.0",
35
33
  "next": ">=16.0.0",
36
34
  "react": ">=19.0.0",
37
35
  "react-dom": ">=19.0.0",
38
36
  "tailwindcss": ">=4.0.0"
39
37
  },
38
+ "peerDependenciesMeta": {
39
+ "@tanstack/react-query": {
40
+ "optional": true
41
+ }
42
+ },
40
43
  "dependencies": {
44
+ "@dnd-kit/core": "^6.3.1",
45
+ "@dnd-kit/modifiers": "^9.0.0",
46
+ "@dnd-kit/sortable": "^10.0.0",
47
+ "@dnd-kit/utilities": "^3.2.2",
41
48
  "@floating-ui/react": "^0.27.20",
42
49
  "@radix-ui/react-slider": "^1.4.7",
43
50
  "@tanstack/match-sorter-utils": "^9.1.2",
51
+ "@tanstack/react-table": "^9.2.4",
52
+ "react-dropzone": "^20.1.1",
44
53
  "react-easy-crop": "^6.2.3",
45
54
  "react-textarea-autosize": "^8.5.9",
46
55
  "sonner": "^2.0.8"
47
56
  },
48
57
  "devDependencies": {
49
- "eslint-config-next": "16.3.4",
50
58
  "@tailwindcss/postcss": "^4.3.3",
59
+ "@tanstack/react-query": "^5.102.8",
51
60
  "@types/node": "^22.15.3",
52
61
  "@types/react": "19.2.2",
53
62
  "@types/react-dom": "19.2.2",
54
63
  "cypress": "^15.21.0",
55
64
  "eslint": "^9.39.1",
65
+ "eslint-config-next": "16.3.4",
66
+ "eslint-config-prettier": "^10.1.8",
56
67
  "next": "16.3.0",
57
68
  "react": "^19.2.0",
58
69
  "react-dom": "^19.2.0",
59
70
  "tailwindcss": "^4.3.3",
60
71
  "tsup": "^8.5.1",
61
72
  "typescript": "^5.9.2"
73
+ },
74
+ "scripts": {
75
+ "build": "tsup",
76
+ "lint": "eslint",
77
+ "check-types": "tsc --noEmit",
78
+ "doctor": "pnpm dlx react-doctor@latest",
79
+ "cypress:open": "cypress open --component",
80
+ "cypress:run": "cypress run --component"
62
81
  }
63
- }
82
+ }