@mkt-loitd/react-table-grid-custom 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -0
- package/dist/index.css +57 -0
- package/dist/index.d.mts +71 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +417 -0
- package/dist/index.mjs +390 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# 📦 React Table Grid Custom
|
|
2
|
+
|
|
3
|
+
A powerful, customizable React table component built on top of **react-data-grid**, optimized for **Next.js** and **TypeScript** projects.
|
|
4
|
+
|
|
5
|
+
> Supports pagination, sorting, row selection, i18n, Mantine UI, and flexible column configuration.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
* ✅ Built on **react-data-grid**
|
|
12
|
+
* ✅ Fully written in **TypeScript**
|
|
13
|
+
* ✅ Pagination & sorting
|
|
14
|
+
* ✅ Row selection (checkbox)
|
|
15
|
+
* ✅ Internationalization (`react-i18next`)
|
|
16
|
+
* ✅ Mantine UI integration
|
|
17
|
+
* ✅ Optimized for **Next.js (App Router & Pages Router)**
|
|
18
|
+
* ✅ Tree-shakeable & ESM/CJS support
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 📦 Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @loitd/react-table-grid-custom
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
yarn add @loitd/react-table-grid-custom
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
or
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm add @loitd/react-table-grid-custom
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ⚠️ Peer Dependencies
|
|
43
|
+
|
|
44
|
+
Make sure your project already has:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
react >= 18
|
|
48
|
+
react-dom >= 18
|
|
49
|
+
next >= 13
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
These are required but **not bundled** with the library.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🚀 Basic Usage
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import ReactTableGridCustom from '@loitd/react-table-grid-custom'
|
|
60
|
+
|
|
61
|
+
const columns = [
|
|
62
|
+
{ key: 'id', name: 'ID' },
|
|
63
|
+
{ key: 'name', name: 'Name' },
|
|
64
|
+
{ key: 'email', name: 'Email' }
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
const data = [
|
|
68
|
+
{ id: 1, name: 'John', email: 'john@gmail.com' },
|
|
69
|
+
{ id: 2, name: 'Jane', email: 'jane@gmail.com' }
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
export default function Example() {
|
|
73
|
+
return (
|
|
74
|
+
<div style={{ height: 400 }}>
|
|
75
|
+
<ReactTableGridCustom
|
|
76
|
+
columns={columns}
|
|
77
|
+
data={data}
|
|
78
|
+
page={1}
|
|
79
|
+
pageSize={10}
|
|
80
|
+
total={data.length}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 🧩 Props
|
|
90
|
+
|
|
91
|
+
### `ReactTableGridCustom<T>`
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Description |
|
|
94
|
+
| -------------------------- | ------------------------ | ------------------------ |
|
|
95
|
+
| `columns` | `TColumnsTable<T>` | Column definitions |
|
|
96
|
+
| `data` | `T[]` | Table data |
|
|
97
|
+
| `page` | `number` | Current page |
|
|
98
|
+
| `pageSize` | `number` | Items per page |
|
|
99
|
+
| `total` | `number` | Total records |
|
|
100
|
+
| `onChange` | `(page: number) => void` | Page change callback |
|
|
101
|
+
| `selectedRows` | `ReadonlySet<Key>` | Selected rows |
|
|
102
|
+
| `fetching` | `boolean` | Show loading overlay |
|
|
103
|
+
| `hiddenPagination` | `boolean` | Hide pagination |
|
|
104
|
+
| `hiddenSTT` | `boolean` | Hide index column |
|
|
105
|
+
| `classNameWapperTable` | `string` | Custom wrapper class |
|
|
106
|
+
| `classNamePaginationTable` | `string` | Pagination wrapper class |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 🌍 Internationalization (i18n)
|
|
111
|
+
|
|
112
|
+
This component supports `react-i18next`.
|
|
113
|
+
|
|
114
|
+
Make sure you have:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npm install react-i18next i18next
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Example translation keys:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"display": "Display",
|
|
125
|
+
"to": "to",
|
|
126
|
+
"in": "in",
|
|
127
|
+
"data": "records"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 🎨 Styling
|
|
134
|
+
|
|
135
|
+
* Uses **Mantine** components
|
|
136
|
+
* Fully compatible with **Tailwind CSS**
|
|
137
|
+
* Includes default styles from `react-data-grid`
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import 'react-data-grid/lib/styles.css'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🛠 Development
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm run dev
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Build package:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm run build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Test publish locally:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npm pack
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 📁 Package Output
|
|
166
|
+
|
|
167
|
+
When published, the package includes only:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
dist/
|
|
171
|
+
README.md
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 📄 License
|
|
177
|
+
|
|
178
|
+
ISC © LoiTD
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 💬 Support
|
|
183
|
+
|
|
184
|
+
If you find a bug or want to request a feature, feel free to open an issue or contribute.
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* src/ReactTableGridCustom.css */
|
|
2
|
+
:root {
|
|
3
|
+
--mkt-border-color: #dee2e6a6;
|
|
4
|
+
}
|
|
5
|
+
.rdg::-webkit-scrollbar {
|
|
6
|
+
width: 7px;
|
|
7
|
+
height: 7px;
|
|
8
|
+
}
|
|
9
|
+
:is(.rdg)::-webkit-scrollbar-track {
|
|
10
|
+
border-radius: 4px;
|
|
11
|
+
background-color: transparent;
|
|
12
|
+
}
|
|
13
|
+
:is(.rdg)::-webkit-scrollbar-thumb {
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
background-color: #dadada;
|
|
16
|
+
}
|
|
17
|
+
div[aria-selected=true] {
|
|
18
|
+
outline: none !important;
|
|
19
|
+
}
|
|
20
|
+
.wapper_table {
|
|
21
|
+
border: 1px solid var(--mkt-border-color);
|
|
22
|
+
}
|
|
23
|
+
.wapper_pagination {
|
|
24
|
+
border-top: 1px solid var(--mkt-border-color);
|
|
25
|
+
margin-top: 2px;
|
|
26
|
+
}
|
|
27
|
+
div[role=row]:not(:last-child) > div {
|
|
28
|
+
border-bottom: 1px solid var(--mkt-border-color);
|
|
29
|
+
}
|
|
30
|
+
div[role=row] > div:not(:last-child) {
|
|
31
|
+
border-right: 1px solid var(--mkt-border-color);
|
|
32
|
+
}
|
|
33
|
+
.page_size-table[data-combobox-disabled] {
|
|
34
|
+
cursor: default;
|
|
35
|
+
}
|
|
36
|
+
.custom_input_table.mantine-Input-input:focus {
|
|
37
|
+
outline: none !important;
|
|
38
|
+
--input-bd: inherit;
|
|
39
|
+
}
|
|
40
|
+
.custom_input_table.mantine-Input-input {
|
|
41
|
+
--height: 30px;
|
|
42
|
+
min-height: var(--height);
|
|
43
|
+
height: var(--height);
|
|
44
|
+
line-height: var(--height);
|
|
45
|
+
text-align: center;
|
|
46
|
+
}
|
|
47
|
+
.fill-grid {
|
|
48
|
+
block-size: 100%;
|
|
49
|
+
}
|
|
50
|
+
div[aria-sort] > span {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
}
|
|
54
|
+
.RIGHT_COLUMN_FROZEN_CLASS {
|
|
55
|
+
position: sticky !important;
|
|
56
|
+
right: 0 !important;
|
|
57
|
+
}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Key, Dispatch, SetStateAction, ReactNode, JSX } from 'react';
|
|
2
|
+
import { ColumnOrColumnGroup, DataGridProps } from 'react-data-grid';
|
|
3
|
+
import { PaginationRootProps } from '@mantine/core';
|
|
4
|
+
|
|
5
|
+
type TColumnsTable<T = unknown, SR = unknown> = readonly ColumnOrColumnGroup<NoInfer<T>, NoInfer<SR>>[];
|
|
6
|
+
interface IPaginationParams$1 {
|
|
7
|
+
pageSize?: number;
|
|
8
|
+
page?: number;
|
|
9
|
+
}
|
|
10
|
+
interface IObjectDynamic {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
interface ISetConfigPagination extends IPaginationParams$1, IObjectDynamic {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IPaginationText {
|
|
17
|
+
from?: number;
|
|
18
|
+
to?: number;
|
|
19
|
+
}
|
|
20
|
+
interface IPaginationTextFunc extends IPaginationText, Pick<ICalculatorTotalPage, 'total'> {
|
|
21
|
+
}
|
|
22
|
+
interface IReactTableGridCustom<T = unknown, SR = unknown, K extends Key = Key> extends Omit<DataGridProps<T, SR, K>, 'rows' | 'rowKeyGetter'>, ICalculatorTotalPage {
|
|
23
|
+
classNameWapperTable?: string;
|
|
24
|
+
classNamePaginationTable?: string;
|
|
25
|
+
hiddenPagination?: boolean;
|
|
26
|
+
hiddenSTT?: boolean;
|
|
27
|
+
data?: T[];
|
|
28
|
+
/** Nếu hàm onChange nên dùng useCallback */
|
|
29
|
+
onChange?: Pick<PaginationRootProps, 'onChange'>['onChange'];
|
|
30
|
+
setConfigPagination?: Dispatch<SetStateAction<ISetConfigPagination>>;
|
|
31
|
+
/** Nếu hàm rowKeyGetter nên dùng useCallback*/
|
|
32
|
+
rowKeyGetter?: string | Maybe<(row: NoInfer<T>) => K>;
|
|
33
|
+
hiddenPaginationText?: boolean;
|
|
34
|
+
/** dùng hàm paginationText nên dùng useCallback*/
|
|
35
|
+
paginationText?: (obj: IPaginationTextFunc) => ReactNode;
|
|
36
|
+
listPageSize?: string[];
|
|
37
|
+
fetching?: boolean;
|
|
38
|
+
TableLogo?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare const ReactTableGridCustomInner: <T, SR = unknown, K extends Key = Key>({ classNamePaginationTable, classNameWapperTable, hiddenPagination, hiddenSTT, data, page, pageSize, total, onChange, setConfigPagination, columns, rowKeyGetter, selectedRows, hiddenPaginationText, paginationText, listPageSize, fetching, TableLogo, ...spread }: IReactTableGridCustom<T, SR, K>) => JSX.Element;
|
|
42
|
+
declare const ReactTableGridCustom: typeof ReactTableGridCustomInner;
|
|
43
|
+
|
|
44
|
+
interface IPaginationParams {
|
|
45
|
+
pageSize?: number;
|
|
46
|
+
page?: number;
|
|
47
|
+
}
|
|
48
|
+
type Maybe<T> = T | undefined | null;
|
|
49
|
+
interface ICalculatorTotalPage extends IPaginationParams {
|
|
50
|
+
total?: number;
|
|
51
|
+
}
|
|
52
|
+
interface ISTTParams extends IPaginationParams {
|
|
53
|
+
}
|
|
54
|
+
interface useShowHideColumnParameter<T, SR = unknown> {
|
|
55
|
+
nameLocal?: string;
|
|
56
|
+
/** nếu đầu vào là columns: Functions() thì nên dùng useMemo thì sẽ tối ưu hơn */
|
|
57
|
+
columns: TColumnsTable<T, SR>;
|
|
58
|
+
ignoreColumns?: string[];
|
|
59
|
+
}
|
|
60
|
+
interface useShowHideColumnReturn<T, SR> {
|
|
61
|
+
hiddenColumns: string[];
|
|
62
|
+
setHiddenColumns: Dispatch<SetStateAction<string[]>>;
|
|
63
|
+
columnsTable: TColumnsTable<T, SR>;
|
|
64
|
+
changeHiddenColumn: (key: string | string[]) => void;
|
|
65
|
+
newShowhideColumns: TColumnsTable<T, SR>;
|
|
66
|
+
locationColumns: string[];
|
|
67
|
+
handleFindLocation: (filterColumns: TColumnsTable<T, SR>, locationColumns?: string[]) => TColumnsTable<T, SR>;
|
|
68
|
+
handleChangeLocation?: (arr: string[]) => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { type ICalculatorTotalPage, type IPaginationParams, type IReactTableGridCustom, type ISTTParams, type Maybe, ReactTableGridCustom, ReactTableGridCustom as ReactTableGridCustomDefault, type TColumnsTable, type useShowHideColumnParameter, type useShowHideColumnReturn };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Key, Dispatch, SetStateAction, ReactNode, JSX } from 'react';
|
|
2
|
+
import { ColumnOrColumnGroup, DataGridProps } from 'react-data-grid';
|
|
3
|
+
import { PaginationRootProps } from '@mantine/core';
|
|
4
|
+
|
|
5
|
+
type TColumnsTable<T = unknown, SR = unknown> = readonly ColumnOrColumnGroup<NoInfer<T>, NoInfer<SR>>[];
|
|
6
|
+
interface IPaginationParams$1 {
|
|
7
|
+
pageSize?: number;
|
|
8
|
+
page?: number;
|
|
9
|
+
}
|
|
10
|
+
interface IObjectDynamic {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
interface ISetConfigPagination extends IPaginationParams$1, IObjectDynamic {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IPaginationText {
|
|
17
|
+
from?: number;
|
|
18
|
+
to?: number;
|
|
19
|
+
}
|
|
20
|
+
interface IPaginationTextFunc extends IPaginationText, Pick<ICalculatorTotalPage, 'total'> {
|
|
21
|
+
}
|
|
22
|
+
interface IReactTableGridCustom<T = unknown, SR = unknown, K extends Key = Key> extends Omit<DataGridProps<T, SR, K>, 'rows' | 'rowKeyGetter'>, ICalculatorTotalPage {
|
|
23
|
+
classNameWapperTable?: string;
|
|
24
|
+
classNamePaginationTable?: string;
|
|
25
|
+
hiddenPagination?: boolean;
|
|
26
|
+
hiddenSTT?: boolean;
|
|
27
|
+
data?: T[];
|
|
28
|
+
/** Nếu hàm onChange nên dùng useCallback */
|
|
29
|
+
onChange?: Pick<PaginationRootProps, 'onChange'>['onChange'];
|
|
30
|
+
setConfigPagination?: Dispatch<SetStateAction<ISetConfigPagination>>;
|
|
31
|
+
/** Nếu hàm rowKeyGetter nên dùng useCallback*/
|
|
32
|
+
rowKeyGetter?: string | Maybe<(row: NoInfer<T>) => K>;
|
|
33
|
+
hiddenPaginationText?: boolean;
|
|
34
|
+
/** dùng hàm paginationText nên dùng useCallback*/
|
|
35
|
+
paginationText?: (obj: IPaginationTextFunc) => ReactNode;
|
|
36
|
+
listPageSize?: string[];
|
|
37
|
+
fetching?: boolean;
|
|
38
|
+
TableLogo?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare const ReactTableGridCustomInner: <T, SR = unknown, K extends Key = Key>({ classNamePaginationTable, classNameWapperTable, hiddenPagination, hiddenSTT, data, page, pageSize, total, onChange, setConfigPagination, columns, rowKeyGetter, selectedRows, hiddenPaginationText, paginationText, listPageSize, fetching, TableLogo, ...spread }: IReactTableGridCustom<T, SR, K>) => JSX.Element;
|
|
42
|
+
declare const ReactTableGridCustom: typeof ReactTableGridCustomInner;
|
|
43
|
+
|
|
44
|
+
interface IPaginationParams {
|
|
45
|
+
pageSize?: number;
|
|
46
|
+
page?: number;
|
|
47
|
+
}
|
|
48
|
+
type Maybe<T> = T | undefined | null;
|
|
49
|
+
interface ICalculatorTotalPage extends IPaginationParams {
|
|
50
|
+
total?: number;
|
|
51
|
+
}
|
|
52
|
+
interface ISTTParams extends IPaginationParams {
|
|
53
|
+
}
|
|
54
|
+
interface useShowHideColumnParameter<T, SR = unknown> {
|
|
55
|
+
nameLocal?: string;
|
|
56
|
+
/** nếu đầu vào là columns: Functions() thì nên dùng useMemo thì sẽ tối ưu hơn */
|
|
57
|
+
columns: TColumnsTable<T, SR>;
|
|
58
|
+
ignoreColumns?: string[];
|
|
59
|
+
}
|
|
60
|
+
interface useShowHideColumnReturn<T, SR> {
|
|
61
|
+
hiddenColumns: string[];
|
|
62
|
+
setHiddenColumns: Dispatch<SetStateAction<string[]>>;
|
|
63
|
+
columnsTable: TColumnsTable<T, SR>;
|
|
64
|
+
changeHiddenColumn: (key: string | string[]) => void;
|
|
65
|
+
newShowhideColumns: TColumnsTable<T, SR>;
|
|
66
|
+
locationColumns: string[];
|
|
67
|
+
handleFindLocation: (filterColumns: TColumnsTable<T, SR>, locationColumns?: string[]) => TColumnsTable<T, SR>;
|
|
68
|
+
handleChangeLocation?: (arr: string[]) => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { type ICalculatorTotalPage, type IPaginationParams, type IReactTableGridCustom, type ISTTParams, type Maybe, ReactTableGridCustom, ReactTableGridCustom as ReactTableGridCustomDefault, type TColumnsTable, type useShowHideColumnParameter, type useShowHideColumnReturn };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
ReactTableGridCustom: () => ReactTableGridCustom,
|
|
25
|
+
ReactTableGridCustomDefault: () => ReactTableGridCustom_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/ReactTableGridCustom.tsx
|
|
30
|
+
var import_core2 = require("@mantine/core");
|
|
31
|
+
|
|
32
|
+
// src/helpers/table.ts
|
|
33
|
+
var calculatorTotalPage = ({ total = 0, pageSize = 0 }) => {
|
|
34
|
+
if (!pageSize || pageSize && pageSize <= 0) return 0;
|
|
35
|
+
return Math.ceil(total / pageSize);
|
|
36
|
+
};
|
|
37
|
+
var STT = (data, index) => {
|
|
38
|
+
let stt = 1;
|
|
39
|
+
let current_page = 0;
|
|
40
|
+
let per_page = 0;
|
|
41
|
+
if ((data == null ? void 0 : data.page) !== void 0 && (data == null ? void 0 : data.pageSize) !== void 0) {
|
|
42
|
+
current_page = data.page;
|
|
43
|
+
per_page = data.pageSize;
|
|
44
|
+
}
|
|
45
|
+
let i = (current_page - 1) * per_page;
|
|
46
|
+
i = isNaN(i) ? 0 : i;
|
|
47
|
+
stt = i + (index != null ? index : 0) + 1;
|
|
48
|
+
return stt;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/utils.ts
|
|
52
|
+
var import_clsx = require("clsx");
|
|
53
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
54
|
+
function cn(...inputs) {
|
|
55
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/ReactTableGridCustom.tsx
|
|
59
|
+
var import_lodash = require("lodash");
|
|
60
|
+
var import_react3 = require("react");
|
|
61
|
+
var import_react_data_grid = require("react-data-grid");
|
|
62
|
+
var import_styles = require("react-data-grid/lib/styles.css");
|
|
63
|
+
var import_react_i18next2 = require("react-i18next");
|
|
64
|
+
|
|
65
|
+
// src/component/ComboboxCustom.tsx
|
|
66
|
+
var import_core = require("@mantine/core");
|
|
67
|
+
var import_react = require("react");
|
|
68
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
69
|
+
var ComboboxCustom = ({ options, onChange, value }) => {
|
|
70
|
+
const combobox = (0, import_core.useCombobox)({
|
|
71
|
+
onDropdownClose: () => combobox.resetSelectedOption()
|
|
72
|
+
});
|
|
73
|
+
const newOptions = (0, import_react.useMemo)(() => {
|
|
74
|
+
return (options != null ? options : []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
75
|
+
import_core.Combobox.Option,
|
|
76
|
+
{
|
|
77
|
+
className: "page_size-table",
|
|
78
|
+
value: item,
|
|
79
|
+
disabled: item === value,
|
|
80
|
+
children: item
|
|
81
|
+
},
|
|
82
|
+
item
|
|
83
|
+
));
|
|
84
|
+
}, [options, value]);
|
|
85
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
86
|
+
import_core.Combobox,
|
|
87
|
+
{
|
|
88
|
+
size: "sm",
|
|
89
|
+
store: combobox,
|
|
90
|
+
onOptionSubmit: (val) => {
|
|
91
|
+
onChange && onChange(val);
|
|
92
|
+
combobox.closeDropdown();
|
|
93
|
+
},
|
|
94
|
+
children: [
|
|
95
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Combobox.Target, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
96
|
+
import_core.InputBase,
|
|
97
|
+
{
|
|
98
|
+
component: "button",
|
|
99
|
+
type: "button",
|
|
100
|
+
pointer: true,
|
|
101
|
+
rightSectionPointerEvents: "none",
|
|
102
|
+
onClick: () => combobox.toggleDropdown(),
|
|
103
|
+
className: "w-[70px]",
|
|
104
|
+
classNames: { input: "custom_input_table" },
|
|
105
|
+
children: value || /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Input.Placeholder, { children: "Pick value" })
|
|
106
|
+
}
|
|
107
|
+
) }),
|
|
108
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Combobox.Dropdown, { className: "w-[70px]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Combobox.Options, { children: newOptions }) })
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
var ComboboxCustom_default = ComboboxCustom;
|
|
114
|
+
|
|
115
|
+
// src/component/Icons.tsx
|
|
116
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
117
|
+
var LoadingIcon = ({
|
|
118
|
+
isSpin = false,
|
|
119
|
+
h = 30,
|
|
120
|
+
w = 30,
|
|
121
|
+
size = 30,
|
|
122
|
+
className
|
|
123
|
+
}) => {
|
|
124
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
125
|
+
"svg",
|
|
126
|
+
{
|
|
127
|
+
className: `${isSpin ? "animate-spin" : ""} ${className != null ? className : ""}`,
|
|
128
|
+
viewBox: "0 0 1024 1024",
|
|
129
|
+
focusable: "false",
|
|
130
|
+
"data-icon": "loading",
|
|
131
|
+
width: size || w,
|
|
132
|
+
height: size || h,
|
|
133
|
+
fill: "currentColor",
|
|
134
|
+
"aria-hidden": "true",
|
|
135
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z" })
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
var ArrowIcon = ({
|
|
140
|
+
h,
|
|
141
|
+
w,
|
|
142
|
+
size,
|
|
143
|
+
className
|
|
144
|
+
}) => {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
146
|
+
"svg",
|
|
147
|
+
{
|
|
148
|
+
className,
|
|
149
|
+
stroke: "currentColor",
|
|
150
|
+
fill: "currentColor",
|
|
151
|
+
strokeWidth: "0",
|
|
152
|
+
viewBox: "0 0 16 16",
|
|
153
|
+
height: size != null ? size : h,
|
|
154
|
+
width: size != null ? size : w,
|
|
155
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
157
|
+
"path",
|
|
158
|
+
{
|
|
159
|
+
fillRule: "evenodd",
|
|
160
|
+
d: "M8 4a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5A.5.5 0 0 1 8 4"
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/component/RenderSortStatus.tsx
|
|
168
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
169
|
+
var RenderSortStatus = ({ sortDirection, priority }) => {
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
171
|
+
sortDirection !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
172
|
+
ArrowIcon,
|
|
173
|
+
{
|
|
174
|
+
className: cn(sortDirection === "DESC" && "-rotate-180", "transition-transform"),
|
|
175
|
+
size: 20
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: priority })
|
|
179
|
+
] });
|
|
180
|
+
};
|
|
181
|
+
var RenderSortStatus_default = RenderSortStatus;
|
|
182
|
+
|
|
183
|
+
// src/hooks/useTranslationTable.ts
|
|
184
|
+
var import_react2 = require("react");
|
|
185
|
+
var import_react_i18next = require("react-i18next");
|
|
186
|
+
var useTranslationTable = (column) => {
|
|
187
|
+
const { i18n, t } = (0, import_react_i18next.useTranslation)();
|
|
188
|
+
const columnTranslation = (0, import_react2.useMemo)(() => {
|
|
189
|
+
return column.map((item) => ({ ...item, name: t(`${item == null ? void 0 : item.name}`) }));
|
|
190
|
+
}, [i18n == null ? void 0 : i18n.language, column]);
|
|
191
|
+
return columnTranslation;
|
|
192
|
+
};
|
|
193
|
+
var useTranslationTable_default = useTranslationTable;
|
|
194
|
+
|
|
195
|
+
// src/ReactTableGridCustom.tsx
|
|
196
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
197
|
+
var ReactTableGridCustomInner = ({
|
|
198
|
+
classNamePaginationTable,
|
|
199
|
+
classNameWapperTable,
|
|
200
|
+
hiddenPagination,
|
|
201
|
+
hiddenSTT,
|
|
202
|
+
data = [],
|
|
203
|
+
page,
|
|
204
|
+
pageSize,
|
|
205
|
+
total,
|
|
206
|
+
onChange,
|
|
207
|
+
setConfigPagination,
|
|
208
|
+
columns,
|
|
209
|
+
rowKeyGetter = "uid",
|
|
210
|
+
selectedRows,
|
|
211
|
+
hiddenPaginationText,
|
|
212
|
+
paginationText,
|
|
213
|
+
listPageSize = ["10", "100", "200", "500", "1000", "5000"],
|
|
214
|
+
fetching,
|
|
215
|
+
TableLogo,
|
|
216
|
+
...spread
|
|
217
|
+
}) => {
|
|
218
|
+
const { t } = (0, import_react_i18next2.useTranslation)();
|
|
219
|
+
const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
|
|
220
|
+
const tableRef = (0, import_react3.useRef)(null);
|
|
221
|
+
const [containerWidth, setContainerWidth] = (0, import_react3.useState)(0);
|
|
222
|
+
const [sortColumns, setSortColumns] = (0, import_react3.useState)([]);
|
|
223
|
+
const isSelectRow = selectedRows !== void 0;
|
|
224
|
+
const maxPage = (0, import_react3.useMemo)(
|
|
225
|
+
() => !hiddenPagination ? calculatorTotalPage({
|
|
226
|
+
total,
|
|
227
|
+
pageSize
|
|
228
|
+
}) : 0,
|
|
229
|
+
[pageSize, total, hiddenPagination]
|
|
230
|
+
);
|
|
231
|
+
const toInPagination = (0, import_react3.useMemo)(() => {
|
|
232
|
+
const initPage = {
|
|
233
|
+
from: 0,
|
|
234
|
+
to: 0
|
|
235
|
+
};
|
|
236
|
+
if (!hiddenPaginationText && pageSize && page) {
|
|
237
|
+
const from = STT(
|
|
238
|
+
{
|
|
239
|
+
page,
|
|
240
|
+
pageSize
|
|
241
|
+
},
|
|
242
|
+
0
|
|
243
|
+
);
|
|
244
|
+
return {
|
|
245
|
+
from,
|
|
246
|
+
to: maxPage === page ? total : page * pageSize
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return initPage;
|
|
250
|
+
}, [pageSize, page, hiddenPaginationText, maxPage, total]);
|
|
251
|
+
const columnTranslation = useTranslationTable_default(columns);
|
|
252
|
+
(0, import_react3.useEffect)(() => {
|
|
253
|
+
var _a;
|
|
254
|
+
setIsLoading(false);
|
|
255
|
+
if ((_a = tableRef.current) == null ? void 0 : _a.element) {
|
|
256
|
+
const width = tableRef.current.element.offsetWidth;
|
|
257
|
+
if (width) setContainerWidth(width);
|
|
258
|
+
}
|
|
259
|
+
}, []);
|
|
260
|
+
const newColumns = (0, import_react3.useMemo)(() => {
|
|
261
|
+
let columnsCustom = [...columnTranslation];
|
|
262
|
+
const adjustedContainerWidth = containerWidth - 80 + 35;
|
|
263
|
+
columnsCustom = columnsCustom.map((col) => {
|
|
264
|
+
const newCol = { ...col };
|
|
265
|
+
delete newCol.maxWidth;
|
|
266
|
+
newCol.width = 200;
|
|
267
|
+
return newCol;
|
|
268
|
+
});
|
|
269
|
+
const totalMaxWidth = columnsCustom.reduce((sum, col) => {
|
|
270
|
+
var _a;
|
|
271
|
+
return sum + ("width" in col ? Number((_a = col == null ? void 0 : col.width) != null ? _a : 200) : 0);
|
|
272
|
+
}, 0);
|
|
273
|
+
if (totalMaxWidth < adjustedContainerWidth && columnsCustom.length > 0) {
|
|
274
|
+
const evenWidth = Math.floor(adjustedContainerWidth / columnsCustom.length);
|
|
275
|
+
columnsCustom = columnsCustom.map((col) => {
|
|
276
|
+
const newCol = { ...col };
|
|
277
|
+
delete newCol.maxWidth;
|
|
278
|
+
newCol.width = evenWidth;
|
|
279
|
+
return newCol;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
if (isSelectRow) {
|
|
283
|
+
columnsCustom.unshift(import_react_data_grid.SelectColumn);
|
|
284
|
+
}
|
|
285
|
+
if (!hiddenSTT || !hiddenSTT && page && pageSize) {
|
|
286
|
+
columnsCustom.unshift({
|
|
287
|
+
key: "index",
|
|
288
|
+
name: "STT",
|
|
289
|
+
width: 80,
|
|
290
|
+
renderCell: ({ rowIdx }) => STT({ page, pageSize }, rowIdx)
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return columnsCustom;
|
|
294
|
+
}, [hiddenSTT, isSelectRow, page, pageSize, columnTranslation, containerWidth]);
|
|
295
|
+
const customRowKeyGetter = (0, import_react3.useMemo)(() => {
|
|
296
|
+
return (row) => {
|
|
297
|
+
if (typeof rowKeyGetter === "function") {
|
|
298
|
+
return rowKeyGetter(row);
|
|
299
|
+
}
|
|
300
|
+
return (0, import_lodash.get)(row, rowKeyGetter);
|
|
301
|
+
};
|
|
302
|
+
}, [rowKeyGetter]);
|
|
303
|
+
const handlePageChange = (0, import_react3.useCallback)(
|
|
304
|
+
(page2) => {
|
|
305
|
+
if (onChange) {
|
|
306
|
+
onChange(page2);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (setConfigPagination) {
|
|
310
|
+
setConfigPagination((prev) => ({ ...prev, page: page2 }));
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
[setConfigPagination, onChange]
|
|
314
|
+
);
|
|
315
|
+
const sortedRows = (0, import_react3.useMemo)(() => {
|
|
316
|
+
var _a, _b, _c;
|
|
317
|
+
if (sortColumns.length === 0) return data;
|
|
318
|
+
const direction = (_b = (_a = sortColumns[0]) == null ? void 0 : _a.direction) == null ? void 0 : _b.toLocaleLowerCase();
|
|
319
|
+
const columnKey = (_c = sortColumns[0]) == null ? void 0 : _c.columnKey;
|
|
320
|
+
return (0, import_lodash.orderBy)(data, columnKey, direction);
|
|
321
|
+
}, [data, sortColumns]);
|
|
322
|
+
(0, import_react3.useEffect)(() => {
|
|
323
|
+
if (page && page > maxPage && maxPage > 0) {
|
|
324
|
+
handlePageChange(1);
|
|
325
|
+
}
|
|
326
|
+
}, [page, maxPage, handlePageChange]);
|
|
327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
className: cn(
|
|
331
|
+
"wapper_table flex-1 rounded-md overflow-hidden relative h-full flex flex-col min-h-0",
|
|
332
|
+
classNameWapperTable
|
|
333
|
+
),
|
|
334
|
+
children: [
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative wapper_table_empty wrapperDatagrid flex flex-col flex-1", children: [
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
337
|
+
import_react_data_grid.DataGrid,
|
|
338
|
+
{
|
|
339
|
+
ref: tableRef,
|
|
340
|
+
"aria-rowcount": sortedRows == null ? void 0 : sortedRows.length,
|
|
341
|
+
selectedRows,
|
|
342
|
+
rows: sortedRows,
|
|
343
|
+
rowKeyGetter: rowKeyGetter && isSelectRow ? customRowKeyGetter : void 0,
|
|
344
|
+
columns: newColumns,
|
|
345
|
+
renderers: {
|
|
346
|
+
renderSortStatus: RenderSortStatus_default,
|
|
347
|
+
renderCheckbox({ onChange: onChange2, checked, ...spread2 }) {
|
|
348
|
+
const handleChange = (e) => {
|
|
349
|
+
onChange2(e.target.checked, e.nativeEvent.shiftKey);
|
|
350
|
+
};
|
|
351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core2.Checkbox, { color: "indigo", checked: !!checked, onChange: handleChange, ...spread2 });
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
className: "fill-grid flex-1 h-full min-h-0",
|
|
355
|
+
defaultColumnOptions: {
|
|
356
|
+
// minWidth: 200,
|
|
357
|
+
// maxWidth: 200,
|
|
358
|
+
renderCell: ({ column, row }) => {
|
|
359
|
+
const value = (0, import_lodash.get)(row, column.key);
|
|
360
|
+
return [null, void 0, ""].includes(value) ? "-" : value;
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
sortColumns,
|
|
364
|
+
onSortColumnsChange: setSortColumns,
|
|
365
|
+
...spread
|
|
366
|
+
}
|
|
367
|
+
),
|
|
368
|
+
total === 0 && TableLogo && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "no_result absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 select-none", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-col justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: TableLogo, alt: "", className: "size-32" }) }) })
|
|
369
|
+
] }),
|
|
370
|
+
!hiddenPagination && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
371
|
+
"div",
|
|
372
|
+
{
|
|
373
|
+
className: cn(
|
|
374
|
+
"flex justify-between items-center flex-wrap wapper_pagination p-[10px] pl-2 mt-auto",
|
|
375
|
+
classNamePaginationTable
|
|
376
|
+
),
|
|
377
|
+
children: [
|
|
378
|
+
!hiddenPaginationText && page && pageSize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-sm", children: paginationText ? paginationText({ ...toInPagination, total }) : total ? `${t("display")} ${toInPagination == null ? void 0 : toInPagination.from} ${t("to")} ${toInPagination == null ? void 0 : toInPagination.to} ${t("in")} ${total} ${t("data")}` : "..." }),
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
380
|
+
ComboboxCustom_default,
|
|
381
|
+
{
|
|
382
|
+
options: listPageSize,
|
|
383
|
+
value: pageSize == null ? void 0 : pageSize.toString(),
|
|
384
|
+
onChange: (value) => {
|
|
385
|
+
if (setConfigPagination) {
|
|
386
|
+
setConfigPagination((prev) => ({ ...prev, pageSize: Number(value), page: 1 }));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
!!maxPage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
392
|
+
import_core2.Pagination,
|
|
393
|
+
{
|
|
394
|
+
color: "indigo",
|
|
395
|
+
total: maxPage,
|
|
396
|
+
size: "sm",
|
|
397
|
+
value: page,
|
|
398
|
+
onChange: handlePageChange
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
),
|
|
404
|
+
(fetching || isLoading) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute inset-0 bg-gray-50/45 flex justify-center items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-[2px] rounded-full border-gray-200 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoadingIcon, { isSpin: true }) }) })
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
};
|
|
409
|
+
var ReactTableGridCustom = (0, import_react3.memo)(
|
|
410
|
+
ReactTableGridCustomInner
|
|
411
|
+
);
|
|
412
|
+
var ReactTableGridCustom_default = ReactTableGridCustom;
|
|
413
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
414
|
+
0 && (module.exports = {
|
|
415
|
+
ReactTableGridCustom,
|
|
416
|
+
ReactTableGridCustomDefault
|
|
417
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/ReactTableGridCustom.tsx
|
|
4
|
+
import { Checkbox, Pagination } from "@mantine/core";
|
|
5
|
+
|
|
6
|
+
// src/helpers/table.ts
|
|
7
|
+
var calculatorTotalPage = ({ total = 0, pageSize = 0 }) => {
|
|
8
|
+
if (!pageSize || pageSize && pageSize <= 0) return 0;
|
|
9
|
+
return Math.ceil(total / pageSize);
|
|
10
|
+
};
|
|
11
|
+
var STT = (data, index) => {
|
|
12
|
+
let stt = 1;
|
|
13
|
+
let current_page = 0;
|
|
14
|
+
let per_page = 0;
|
|
15
|
+
if ((data == null ? void 0 : data.page) !== void 0 && (data == null ? void 0 : data.pageSize) !== void 0) {
|
|
16
|
+
current_page = data.page;
|
|
17
|
+
per_page = data.pageSize;
|
|
18
|
+
}
|
|
19
|
+
let i = (current_page - 1) * per_page;
|
|
20
|
+
i = isNaN(i) ? 0 : i;
|
|
21
|
+
stt = i + (index != null ? index : 0) + 1;
|
|
22
|
+
return stt;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/utils.ts
|
|
26
|
+
import { clsx } from "clsx";
|
|
27
|
+
import { twMerge } from "tailwind-merge";
|
|
28
|
+
function cn(...inputs) {
|
|
29
|
+
return twMerge(clsx(inputs));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/ReactTableGridCustom.tsx
|
|
33
|
+
import { get, orderBy } from "lodash";
|
|
34
|
+
import { memo, useCallback, useEffect, useMemo as useMemo3, useRef, useState } from "react";
|
|
35
|
+
import { DataGrid, SelectColumn } from "react-data-grid";
|
|
36
|
+
import "react-data-grid/lib/styles.css";
|
|
37
|
+
import { useTranslation as useTranslation2 } from "react-i18next";
|
|
38
|
+
|
|
39
|
+
// src/component/ComboboxCustom.tsx
|
|
40
|
+
import { Combobox, Input, InputBase, useCombobox } from "@mantine/core";
|
|
41
|
+
import { useMemo } from "react";
|
|
42
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
43
|
+
var ComboboxCustom = ({ options, onChange, value }) => {
|
|
44
|
+
const combobox = useCombobox({
|
|
45
|
+
onDropdownClose: () => combobox.resetSelectedOption()
|
|
46
|
+
});
|
|
47
|
+
const newOptions = useMemo(() => {
|
|
48
|
+
return (options != null ? options : []).map((item) => /* @__PURE__ */ jsx(
|
|
49
|
+
Combobox.Option,
|
|
50
|
+
{
|
|
51
|
+
className: "page_size-table",
|
|
52
|
+
value: item,
|
|
53
|
+
disabled: item === value,
|
|
54
|
+
children: item
|
|
55
|
+
},
|
|
56
|
+
item
|
|
57
|
+
));
|
|
58
|
+
}, [options, value]);
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
Combobox,
|
|
61
|
+
{
|
|
62
|
+
size: "sm",
|
|
63
|
+
store: combobox,
|
|
64
|
+
onOptionSubmit: (val) => {
|
|
65
|
+
onChange && onChange(val);
|
|
66
|
+
combobox.closeDropdown();
|
|
67
|
+
},
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsx(Combobox.Target, { children: /* @__PURE__ */ jsx(
|
|
70
|
+
InputBase,
|
|
71
|
+
{
|
|
72
|
+
component: "button",
|
|
73
|
+
type: "button",
|
|
74
|
+
pointer: true,
|
|
75
|
+
rightSectionPointerEvents: "none",
|
|
76
|
+
onClick: () => combobox.toggleDropdown(),
|
|
77
|
+
className: "w-[70px]",
|
|
78
|
+
classNames: { input: "custom_input_table" },
|
|
79
|
+
children: value || /* @__PURE__ */ jsx(Input.Placeholder, { children: "Pick value" })
|
|
80
|
+
}
|
|
81
|
+
) }),
|
|
82
|
+
/* @__PURE__ */ jsx(Combobox.Dropdown, { className: "w-[70px]", children: /* @__PURE__ */ jsx(Combobox.Options, { children: newOptions }) })
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
var ComboboxCustom_default = ComboboxCustom;
|
|
88
|
+
|
|
89
|
+
// src/component/Icons.tsx
|
|
90
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
91
|
+
var LoadingIcon = ({
|
|
92
|
+
isSpin = false,
|
|
93
|
+
h = 30,
|
|
94
|
+
w = 30,
|
|
95
|
+
size = 30,
|
|
96
|
+
className
|
|
97
|
+
}) => {
|
|
98
|
+
return /* @__PURE__ */ jsx2(
|
|
99
|
+
"svg",
|
|
100
|
+
{
|
|
101
|
+
className: `${isSpin ? "animate-spin" : ""} ${className != null ? className : ""}`,
|
|
102
|
+
viewBox: "0 0 1024 1024",
|
|
103
|
+
focusable: "false",
|
|
104
|
+
"data-icon": "loading",
|
|
105
|
+
width: size || w,
|
|
106
|
+
height: size || h,
|
|
107
|
+
fill: "currentColor",
|
|
108
|
+
"aria-hidden": "true",
|
|
109
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z" })
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
var ArrowIcon = ({
|
|
114
|
+
h,
|
|
115
|
+
w,
|
|
116
|
+
size,
|
|
117
|
+
className
|
|
118
|
+
}) => {
|
|
119
|
+
return /* @__PURE__ */ jsx2(
|
|
120
|
+
"svg",
|
|
121
|
+
{
|
|
122
|
+
className,
|
|
123
|
+
stroke: "currentColor",
|
|
124
|
+
fill: "currentColor",
|
|
125
|
+
strokeWidth: "0",
|
|
126
|
+
viewBox: "0 0 16 16",
|
|
127
|
+
height: size != null ? size : h,
|
|
128
|
+
width: size != null ? size : w,
|
|
129
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
130
|
+
children: /* @__PURE__ */ jsx2(
|
|
131
|
+
"path",
|
|
132
|
+
{
|
|
133
|
+
fillRule: "evenodd",
|
|
134
|
+
d: "M8 4a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5A.5.5 0 0 1 8 4"
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/component/RenderSortStatus.tsx
|
|
142
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
143
|
+
var RenderSortStatus = ({ sortDirection, priority }) => {
|
|
144
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
145
|
+
sortDirection !== void 0 && /* @__PURE__ */ jsx3(
|
|
146
|
+
ArrowIcon,
|
|
147
|
+
{
|
|
148
|
+
className: cn(sortDirection === "DESC" && "-rotate-180", "transition-transform"),
|
|
149
|
+
size: 20
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
/* @__PURE__ */ jsx3("span", { children: priority })
|
|
153
|
+
] });
|
|
154
|
+
};
|
|
155
|
+
var RenderSortStatus_default = RenderSortStatus;
|
|
156
|
+
|
|
157
|
+
// src/hooks/useTranslationTable.ts
|
|
158
|
+
import { useMemo as useMemo2 } from "react";
|
|
159
|
+
import { useTranslation } from "react-i18next";
|
|
160
|
+
var useTranslationTable = (column) => {
|
|
161
|
+
const { i18n, t } = useTranslation();
|
|
162
|
+
const columnTranslation = useMemo2(() => {
|
|
163
|
+
return column.map((item) => ({ ...item, name: t(`${item == null ? void 0 : item.name}`) }));
|
|
164
|
+
}, [i18n == null ? void 0 : i18n.language, column]);
|
|
165
|
+
return columnTranslation;
|
|
166
|
+
};
|
|
167
|
+
var useTranslationTable_default = useTranslationTable;
|
|
168
|
+
|
|
169
|
+
// src/ReactTableGridCustom.tsx
|
|
170
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
171
|
+
var ReactTableGridCustomInner = ({
|
|
172
|
+
classNamePaginationTable,
|
|
173
|
+
classNameWapperTable,
|
|
174
|
+
hiddenPagination,
|
|
175
|
+
hiddenSTT,
|
|
176
|
+
data = [],
|
|
177
|
+
page,
|
|
178
|
+
pageSize,
|
|
179
|
+
total,
|
|
180
|
+
onChange,
|
|
181
|
+
setConfigPagination,
|
|
182
|
+
columns,
|
|
183
|
+
rowKeyGetter = "uid",
|
|
184
|
+
selectedRows,
|
|
185
|
+
hiddenPaginationText,
|
|
186
|
+
paginationText,
|
|
187
|
+
listPageSize = ["10", "100", "200", "500", "1000", "5000"],
|
|
188
|
+
fetching,
|
|
189
|
+
TableLogo,
|
|
190
|
+
...spread
|
|
191
|
+
}) => {
|
|
192
|
+
const { t } = useTranslation2();
|
|
193
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
194
|
+
const tableRef = useRef(null);
|
|
195
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
196
|
+
const [sortColumns, setSortColumns] = useState([]);
|
|
197
|
+
const isSelectRow = selectedRows !== void 0;
|
|
198
|
+
const maxPage = useMemo3(
|
|
199
|
+
() => !hiddenPagination ? calculatorTotalPage({
|
|
200
|
+
total,
|
|
201
|
+
pageSize
|
|
202
|
+
}) : 0,
|
|
203
|
+
[pageSize, total, hiddenPagination]
|
|
204
|
+
);
|
|
205
|
+
const toInPagination = useMemo3(() => {
|
|
206
|
+
const initPage = {
|
|
207
|
+
from: 0,
|
|
208
|
+
to: 0
|
|
209
|
+
};
|
|
210
|
+
if (!hiddenPaginationText && pageSize && page) {
|
|
211
|
+
const from = STT(
|
|
212
|
+
{
|
|
213
|
+
page,
|
|
214
|
+
pageSize
|
|
215
|
+
},
|
|
216
|
+
0
|
|
217
|
+
);
|
|
218
|
+
return {
|
|
219
|
+
from,
|
|
220
|
+
to: maxPage === page ? total : page * pageSize
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return initPage;
|
|
224
|
+
}, [pageSize, page, hiddenPaginationText, maxPage, total]);
|
|
225
|
+
const columnTranslation = useTranslationTable_default(columns);
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
var _a;
|
|
228
|
+
setIsLoading(false);
|
|
229
|
+
if ((_a = tableRef.current) == null ? void 0 : _a.element) {
|
|
230
|
+
const width = tableRef.current.element.offsetWidth;
|
|
231
|
+
if (width) setContainerWidth(width);
|
|
232
|
+
}
|
|
233
|
+
}, []);
|
|
234
|
+
const newColumns = useMemo3(() => {
|
|
235
|
+
let columnsCustom = [...columnTranslation];
|
|
236
|
+
const adjustedContainerWidth = containerWidth - 80 + 35;
|
|
237
|
+
columnsCustom = columnsCustom.map((col) => {
|
|
238
|
+
const newCol = { ...col };
|
|
239
|
+
delete newCol.maxWidth;
|
|
240
|
+
newCol.width = 200;
|
|
241
|
+
return newCol;
|
|
242
|
+
});
|
|
243
|
+
const totalMaxWidth = columnsCustom.reduce((sum, col) => {
|
|
244
|
+
var _a;
|
|
245
|
+
return sum + ("width" in col ? Number((_a = col == null ? void 0 : col.width) != null ? _a : 200) : 0);
|
|
246
|
+
}, 0);
|
|
247
|
+
if (totalMaxWidth < adjustedContainerWidth && columnsCustom.length > 0) {
|
|
248
|
+
const evenWidth = Math.floor(adjustedContainerWidth / columnsCustom.length);
|
|
249
|
+
columnsCustom = columnsCustom.map((col) => {
|
|
250
|
+
const newCol = { ...col };
|
|
251
|
+
delete newCol.maxWidth;
|
|
252
|
+
newCol.width = evenWidth;
|
|
253
|
+
return newCol;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (isSelectRow) {
|
|
257
|
+
columnsCustom.unshift(SelectColumn);
|
|
258
|
+
}
|
|
259
|
+
if (!hiddenSTT || !hiddenSTT && page && pageSize) {
|
|
260
|
+
columnsCustom.unshift({
|
|
261
|
+
key: "index",
|
|
262
|
+
name: "STT",
|
|
263
|
+
width: 80,
|
|
264
|
+
renderCell: ({ rowIdx }) => STT({ page, pageSize }, rowIdx)
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return columnsCustom;
|
|
268
|
+
}, [hiddenSTT, isSelectRow, page, pageSize, columnTranslation, containerWidth]);
|
|
269
|
+
const customRowKeyGetter = useMemo3(() => {
|
|
270
|
+
return (row) => {
|
|
271
|
+
if (typeof rowKeyGetter === "function") {
|
|
272
|
+
return rowKeyGetter(row);
|
|
273
|
+
}
|
|
274
|
+
return get(row, rowKeyGetter);
|
|
275
|
+
};
|
|
276
|
+
}, [rowKeyGetter]);
|
|
277
|
+
const handlePageChange = useCallback(
|
|
278
|
+
(page2) => {
|
|
279
|
+
if (onChange) {
|
|
280
|
+
onChange(page2);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (setConfigPagination) {
|
|
284
|
+
setConfigPagination((prev) => ({ ...prev, page: page2 }));
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
[setConfigPagination, onChange]
|
|
288
|
+
);
|
|
289
|
+
const sortedRows = useMemo3(() => {
|
|
290
|
+
var _a, _b, _c;
|
|
291
|
+
if (sortColumns.length === 0) return data;
|
|
292
|
+
const direction = (_b = (_a = sortColumns[0]) == null ? void 0 : _a.direction) == null ? void 0 : _b.toLocaleLowerCase();
|
|
293
|
+
const columnKey = (_c = sortColumns[0]) == null ? void 0 : _c.columnKey;
|
|
294
|
+
return orderBy(data, columnKey, direction);
|
|
295
|
+
}, [data, sortColumns]);
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (page && page > maxPage && maxPage > 0) {
|
|
298
|
+
handlePageChange(1);
|
|
299
|
+
}
|
|
300
|
+
}, [page, maxPage, handlePageChange]);
|
|
301
|
+
return /* @__PURE__ */ jsxs3(
|
|
302
|
+
"div",
|
|
303
|
+
{
|
|
304
|
+
className: cn(
|
|
305
|
+
"wapper_table flex-1 rounded-md overflow-hidden relative h-full flex flex-col min-h-0",
|
|
306
|
+
classNameWapperTable
|
|
307
|
+
),
|
|
308
|
+
children: [
|
|
309
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative wapper_table_empty wrapperDatagrid flex flex-col flex-1", children: [
|
|
310
|
+
/* @__PURE__ */ jsx4(
|
|
311
|
+
DataGrid,
|
|
312
|
+
{
|
|
313
|
+
ref: tableRef,
|
|
314
|
+
"aria-rowcount": sortedRows == null ? void 0 : sortedRows.length,
|
|
315
|
+
selectedRows,
|
|
316
|
+
rows: sortedRows,
|
|
317
|
+
rowKeyGetter: rowKeyGetter && isSelectRow ? customRowKeyGetter : void 0,
|
|
318
|
+
columns: newColumns,
|
|
319
|
+
renderers: {
|
|
320
|
+
renderSortStatus: RenderSortStatus_default,
|
|
321
|
+
renderCheckbox({ onChange: onChange2, checked, ...spread2 }) {
|
|
322
|
+
const handleChange = (e) => {
|
|
323
|
+
onChange2(e.target.checked, e.nativeEvent.shiftKey);
|
|
324
|
+
};
|
|
325
|
+
return /* @__PURE__ */ jsx4(Checkbox, { color: "indigo", checked: !!checked, onChange: handleChange, ...spread2 });
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
className: "fill-grid flex-1 h-full min-h-0",
|
|
329
|
+
defaultColumnOptions: {
|
|
330
|
+
// minWidth: 200,
|
|
331
|
+
// maxWidth: 200,
|
|
332
|
+
renderCell: ({ column, row }) => {
|
|
333
|
+
const value = get(row, column.key);
|
|
334
|
+
return [null, void 0, ""].includes(value) ? "-" : value;
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
sortColumns,
|
|
338
|
+
onSortColumnsChange: setSortColumns,
|
|
339
|
+
...spread
|
|
340
|
+
}
|
|
341
|
+
),
|
|
342
|
+
total === 0 && TableLogo && /* @__PURE__ */ jsx4("div", { className: "no_result absolute left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 select-none", children: /* @__PURE__ */ jsx4("div", { className: "flex flex-col justify-center", children: /* @__PURE__ */ jsx4("img", { src: TableLogo, alt: "", className: "size-32" }) }) })
|
|
343
|
+
] }),
|
|
344
|
+
!hiddenPagination && /* @__PURE__ */ jsxs3(
|
|
345
|
+
"div",
|
|
346
|
+
{
|
|
347
|
+
className: cn(
|
|
348
|
+
"flex justify-between items-center flex-wrap wapper_pagination p-[10px] pl-2 mt-auto",
|
|
349
|
+
classNamePaginationTable
|
|
350
|
+
),
|
|
351
|
+
children: [
|
|
352
|
+
!hiddenPaginationText && page && pageSize && /* @__PURE__ */ jsx4("div", { className: "text-sm", children: paginationText ? paginationText({ ...toInPagination, total }) : total ? `${t("display")} ${toInPagination == null ? void 0 : toInPagination.from} ${t("to")} ${toInPagination == null ? void 0 : toInPagination.to} ${t("in")} ${total} ${t("data")}` : "..." }),
|
|
353
|
+
/* @__PURE__ */ jsx4(
|
|
354
|
+
ComboboxCustom_default,
|
|
355
|
+
{
|
|
356
|
+
options: listPageSize,
|
|
357
|
+
value: pageSize == null ? void 0 : pageSize.toString(),
|
|
358
|
+
onChange: (value) => {
|
|
359
|
+
if (setConfigPagination) {
|
|
360
|
+
setConfigPagination((prev) => ({ ...prev, pageSize: Number(value), page: 1 }));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
),
|
|
365
|
+
!!maxPage && /* @__PURE__ */ jsx4(
|
|
366
|
+
Pagination,
|
|
367
|
+
{
|
|
368
|
+
color: "indigo",
|
|
369
|
+
total: maxPage,
|
|
370
|
+
size: "sm",
|
|
371
|
+
value: page,
|
|
372
|
+
onChange: handlePageChange
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
(fetching || isLoading) && /* @__PURE__ */ jsx4("div", { className: "absolute inset-0 bg-gray-50/45 flex justify-center items-center", children: /* @__PURE__ */ jsx4("div", { className: "border-[2px] rounded-full border-gray-200 shadow-sm", children: /* @__PURE__ */ jsx4(LoadingIcon, { isSpin: true }) }) })
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
};
|
|
383
|
+
var ReactTableGridCustom = memo(
|
|
384
|
+
ReactTableGridCustomInner
|
|
385
|
+
);
|
|
386
|
+
var ReactTableGridCustom_default = ReactTableGridCustom;
|
|
387
|
+
export {
|
|
388
|
+
ReactTableGridCustom,
|
|
389
|
+
ReactTableGridCustom_default as ReactTableGridCustomDefault
|
|
390
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mkt-loitd/react-table-grid-custom",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"private": false,
|
|
8
|
+
"description": "React Table Grid Custom component",
|
|
9
|
+
"main": "dist/index.cjs",
|
|
10
|
+
"module": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "tsup src/index.ts --watch --format esm,cjs --dts",
|
|
26
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
27
|
+
"prepublishOnly": "npm run build",
|
|
28
|
+
"release:patch": "npm version patch --no-git-tag-version"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": ">=18",
|
|
32
|
+
"react-dom": ">=18",
|
|
33
|
+
"next": ">=13"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@mantine/core": "^8.3.10",
|
|
37
|
+
"@tanstack/react-query": "^5.90.12",
|
|
38
|
+
"clsx": "^2.1.1",
|
|
39
|
+
"formik": "^2.4.9",
|
|
40
|
+
"i18next": "^25.7.3",
|
|
41
|
+
"idb": "^8.0.3",
|
|
42
|
+
"lodash": "^4.17.21",
|
|
43
|
+
"moment": "^2.30.1",
|
|
44
|
+
"react-data-grid": "^7.0.0-beta.59",
|
|
45
|
+
"react-i18next": "^16.5.0",
|
|
46
|
+
"react-select": "^5.10.2",
|
|
47
|
+
"tailwind-merge": "^3.4.0",
|
|
48
|
+
"typeorm": "^0.3.28"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/lodash": "^4.17.21",
|
|
52
|
+
"@types/react": "^18.2.66",
|
|
53
|
+
"tslib": "^2.8.1",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
55
|
+
"typescript": "^5.9.3"
|
|
56
|
+
},
|
|
57
|
+
"license": "ISC",
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+ssh://git@github.com/loitd140201/react-table.git"
|
|
61
|
+
},
|
|
62
|
+
"author": "",
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/loitd140201/react-table/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/loitd140201/react-table#readme"
|
|
67
|
+
}
|