kmod-cli 1.1.0 → 1.2.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.
|
@@ -37,61 +37,104 @@ import {
|
|
|
37
37
|
} from './table';
|
|
38
38
|
|
|
39
39
|
export type TableHeaderClassNames = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
header?: string;
|
|
41
|
+
row?: string;
|
|
42
|
+
head?: string;
|
|
43
43
|
};
|
|
44
44
|
export type TableBodyClassNames = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
body?: string;
|
|
46
|
+
row?: string;
|
|
47
|
+
cell?: string;
|
|
48
48
|
};
|
|
49
49
|
export type TableClassNames = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
export type TableHeaderProps<TData> = HTMLAttributes<HTMLTableSectionElement> & {
|
|
57
|
-
handleClick: ({ e, table }: { e: React.MouseEvent<HTMLTableSectionElement>; table: ITable<TData> }) => void;
|
|
58
|
-
|
|
50
|
+
wrapper?: string;
|
|
51
|
+
container?: string;
|
|
52
|
+
table?: string;
|
|
53
|
+
header?: TableHeaderClassNames;
|
|
54
|
+
body?: TableBodyClassNames;
|
|
59
55
|
};
|
|
56
|
+
export type TableHeaderProps<TData> =
|
|
57
|
+
HTMLAttributes<HTMLTableSectionElement> & {
|
|
58
|
+
handleClick: ({
|
|
59
|
+
e,
|
|
60
|
+
table,
|
|
61
|
+
}: {
|
|
62
|
+
e: React.MouseEvent<HTMLTableSectionElement>;
|
|
63
|
+
table: ITable<TData>;
|
|
64
|
+
}) => void;
|
|
65
|
+
};
|
|
60
66
|
export type TableBodyProps<TData> = HTMLAttributes<HTMLTableSectionElement> & {
|
|
61
|
-
|
|
67
|
+
handleClick: ({
|
|
68
|
+
e,
|
|
69
|
+
table,
|
|
70
|
+
}: {
|
|
71
|
+
e: React.MouseEvent<HTMLTableSectionElement>;
|
|
72
|
+
table: ITable<TData>;
|
|
73
|
+
}) => void;
|
|
62
74
|
};
|
|
63
75
|
export type TableHeadProps<TData> = HTMLAttributes<HTMLTableCellElement> & {
|
|
76
|
+
handleClick: ({
|
|
77
|
+
e,
|
|
78
|
+
table,
|
|
79
|
+
cell,
|
|
80
|
+
}: {
|
|
81
|
+
e: React.MouseEvent<HTMLTableCellElement>;
|
|
82
|
+
cell: Header<TData, unknown>;
|
|
83
|
+
table: ITable<TData>;
|
|
84
|
+
}) => void;
|
|
85
|
+
};
|
|
86
|
+
export type TableCellProps<TData, TValue> =
|
|
87
|
+
HTMLAttributes<HTMLTableCellElement> & {
|
|
64
88
|
handleClick: ({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
e,
|
|
90
|
+
table,
|
|
91
|
+
cell,
|
|
92
|
+
}: {
|
|
93
|
+
e: React.MouseEvent<HTMLTableCellElement>;
|
|
94
|
+
cell: Cell<TData, TValue>;
|
|
95
|
+
table: ITable<TData>;
|
|
72
96
|
}) => void;
|
|
73
|
-
};
|
|
74
|
-
export type TableCellProps<TData, TValue> = HTMLAttributes<HTMLTableCellElement> & {
|
|
75
|
-
handleClick: ({ e, table, cell }: { e: React.MouseEvent<HTMLTableCellElement>; cell: Cell<TData, TValue>; table: ITable<TData> }) => void;
|
|
76
|
-
};
|
|
97
|
+
};
|
|
77
98
|
export type TableRowHeadProps<TData> = HTMLAttributes<HTMLTableRowElement> & {
|
|
78
|
-
|
|
99
|
+
handleClick: ({
|
|
100
|
+
e,
|
|
101
|
+
table,
|
|
102
|
+
row,
|
|
103
|
+
}: {
|
|
104
|
+
e: React.MouseEvent<HTMLTableRowElement>;
|
|
105
|
+
row: HeaderGroup<TData>;
|
|
106
|
+
table: ITable<TData>;
|
|
107
|
+
}) => void;
|
|
79
108
|
};
|
|
80
109
|
export type TableRowBodyProps<TData> = HTMLAttributes<HTMLTableRowElement> & {
|
|
81
|
-
|
|
110
|
+
handleClick: ({
|
|
111
|
+
e,
|
|
112
|
+
table,
|
|
113
|
+
row,
|
|
114
|
+
}: {
|
|
115
|
+
e: React.MouseEvent<HTMLTableRowElement>;
|
|
116
|
+
row: Row<TData>;
|
|
117
|
+
table: ITable<TData>;
|
|
118
|
+
}) => void;
|
|
82
119
|
};
|
|
83
120
|
export type TableProps<TData> = HTMLAttributes<HTMLTableElement> & {
|
|
84
|
-
|
|
121
|
+
handleClick: ({
|
|
122
|
+
e,
|
|
123
|
+
table,
|
|
124
|
+
}: {
|
|
125
|
+
e: React.MouseEvent<HTMLTableElement>;
|
|
126
|
+
table: ITable<TData>;
|
|
127
|
+
}) => void;
|
|
85
128
|
};
|
|
86
129
|
|
|
87
130
|
export type UseTableProps<TData, TValue> = {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
131
|
+
tableProps?: TableProps<TData>;
|
|
132
|
+
headerProps?: TableHeaderProps<TData>;
|
|
133
|
+
bodyProps?: TableBodyProps<TData>;
|
|
134
|
+
cellBodyProps?: TableCellProps<TData, TValue>;
|
|
135
|
+
rowHeadProps?: TableRowHeadProps<TData>;
|
|
136
|
+
rowBodyProps?: TableRowBodyProps<TData>;
|
|
137
|
+
cellHeadProps?: TableHeadProps<TData>;
|
|
95
138
|
};
|
|
96
139
|
|
|
97
140
|
// export type Handles = {
|
|
@@ -109,240 +152,345 @@ export type UseTableProps<TData, TValue> = {
|
|
|
109
152
|
// }
|
|
110
153
|
|
|
111
154
|
export type DataTableProps<TData, TValue> = {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
columns: ColumnDef<TData, TValue>[];
|
|
156
|
+
data: TData[];
|
|
157
|
+
toolbarTable?: ({
|
|
158
|
+
table,
|
|
159
|
+
fns,
|
|
160
|
+
}: {
|
|
161
|
+
table: ITable<TData>;
|
|
162
|
+
fns: DataTableToolbarFns<TData>;
|
|
163
|
+
}) => ReactNode | ReactNode[];
|
|
164
|
+
paginationTable?: ({
|
|
165
|
+
table,
|
|
166
|
+
fns,
|
|
167
|
+
}: {
|
|
168
|
+
table: ITable<TData>;
|
|
169
|
+
fns: DataTablePaginationFns<TData>;
|
|
170
|
+
}) => ReactNode | ReactNode[];
|
|
171
|
+
isLoading?: boolean;
|
|
172
|
+
classNames?: TableClassNames;
|
|
173
|
+
emptyLabel?: string;
|
|
174
|
+
showSortIconHeader?: boolean;
|
|
175
|
+
surfix?: ({
|
|
176
|
+
header,
|
|
177
|
+
showSortIconHeader,
|
|
178
|
+
}: {
|
|
179
|
+
header: Header<TData, TValue | unknown>;
|
|
180
|
+
showSortIconHeader: boolean;
|
|
181
|
+
}) => ReactNode | ReactNode[];
|
|
182
|
+
enableSort?: boolean;
|
|
183
|
+
useTableProps?: UseTableProps<TData, TValue>;
|
|
184
|
+
initialState?: InitialTableState;
|
|
185
|
+
// handles?: Handles
|
|
131
186
|
};
|
|
132
187
|
|
|
133
188
|
export type DataTableToolbarFns<TData> = {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
189
|
+
globalFilter: string;
|
|
190
|
+
setGlobalFilter: (value: string) => void;
|
|
191
|
+
sorting: any;
|
|
192
|
+
setSorting: (value: any) => void;
|
|
193
|
+
getColumn: (columnId: string) => ReturnType<ITable<TData>["getColumn"]>;
|
|
139
194
|
};
|
|
140
195
|
|
|
141
196
|
export type DataTablePaginationFns<TData> = {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
197
|
+
previousPage: () => void;
|
|
198
|
+
nextPage: () => void;
|
|
199
|
+
getCanPreviousPage: () => boolean;
|
|
200
|
+
getCanNextPage: () => boolean;
|
|
201
|
+
pageIndex: number;
|
|
202
|
+
pageSize: number;
|
|
148
203
|
};
|
|
149
204
|
|
|
150
205
|
export function DataTable<TData, TValue>({
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
206
|
+
columns,
|
|
207
|
+
data,
|
|
208
|
+
toolbarTable,
|
|
209
|
+
paginationTable,
|
|
210
|
+
classNames,
|
|
211
|
+
isLoading = false,
|
|
212
|
+
emptyLabel = "No data",
|
|
213
|
+
showSortIconHeader = true,
|
|
214
|
+
surfix,
|
|
215
|
+
enableSort = true,
|
|
216
|
+
useTableProps,
|
|
217
|
+
initialState,
|
|
218
|
+
}: // handles
|
|
219
|
+
DataTableProps<TData, TValue>) {
|
|
220
|
+
const table = useReactTable({
|
|
221
|
+
data,
|
|
222
|
+
columns,
|
|
223
|
+
getCoreRowModel: getCoreRowModel(),
|
|
224
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
225
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
226
|
+
getSortedRowModel: enableSort ? getSortedRowModel() : undefined,
|
|
227
|
+
initialState: initialState,
|
|
228
|
+
});
|
|
229
|
+
const toolbarFns: DataTableToolbarFns<TData> = {
|
|
230
|
+
globalFilter: table.getState().globalFilter as string,
|
|
231
|
+
setGlobalFilter: table.setGlobalFilter,
|
|
232
|
+
sorting: table.getState().sorting,
|
|
233
|
+
setSorting: table.setSorting,
|
|
234
|
+
getColumn: table.getColumn,
|
|
235
|
+
};
|
|
236
|
+
const paginationFns: DataTablePaginationFns<TData> = {
|
|
237
|
+
previousPage: table.previousPage,
|
|
238
|
+
nextPage: table.nextPage,
|
|
239
|
+
getCanPreviousPage: table.getCanPreviousPage,
|
|
240
|
+
getCanNextPage: table.getCanNextPage,
|
|
241
|
+
pageIndex: table.getState().pagination.pageIndex,
|
|
242
|
+
pageSize: table.getState().pagination.pageSize,
|
|
243
|
+
};
|
|
189
244
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
245
|
+
return (
|
|
246
|
+
<div className={cn("space-y-4", classNames?.wrapper)}>
|
|
247
|
+
{toolbarTable && toolbarTable({ table, fns: toolbarFns })}
|
|
248
|
+
<div className={cn(classNames?.container)}>
|
|
249
|
+
<Table
|
|
250
|
+
className={cn(classNames?.table)}
|
|
251
|
+
{...useTableProps?.tableProps}
|
|
252
|
+
onClick={(e) => useTableProps?.tableProps?.handleClick({ e, table })}
|
|
253
|
+
>
|
|
254
|
+
<TableHeader
|
|
255
|
+
className={cn(classNames?.header?.header)}
|
|
256
|
+
{...useTableProps?.headerProps}
|
|
257
|
+
onClick={(e) =>
|
|
258
|
+
useTableProps?.headerProps?.handleClick({ e, table })
|
|
259
|
+
}
|
|
260
|
+
>
|
|
261
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
262
|
+
<TableRow
|
|
263
|
+
key={headerGroup.id}
|
|
264
|
+
className={cn(classNames?.header?.row)}
|
|
265
|
+
{...useTableProps?.rowHeadProps}
|
|
266
|
+
onClick={(e) =>
|
|
267
|
+
useTableProps?.rowHeadProps?.handleClick({
|
|
268
|
+
e,
|
|
269
|
+
row: headerGroup,
|
|
270
|
+
table,
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
>
|
|
274
|
+
{headerGroup.headers.map((header) => (
|
|
275
|
+
<TableHead
|
|
276
|
+
key={header.id}
|
|
277
|
+
{...(() => {
|
|
278
|
+
const { handleClick, onClick, ...rest } =
|
|
279
|
+
useTableProps?.cellHeadProps || {};
|
|
280
|
+
return rest;
|
|
281
|
+
})()}
|
|
282
|
+
className={cn(
|
|
283
|
+
"cursor-pointer select-none",
|
|
284
|
+
classNames?.header?.head
|
|
285
|
+
)}
|
|
286
|
+
onClick={(e) => {
|
|
287
|
+
// Just call the parent's onClick if provided
|
|
288
|
+
if (useTableProps?.cellHeadProps?.onClick) {
|
|
289
|
+
useTableProps.cellHeadProps.onClick(e);
|
|
290
|
+
}
|
|
224
291
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
)
|
|
239
|
-
|
|
292
|
+
// Just call the parent's handleClick if provided
|
|
293
|
+
if (useTableProps?.cellHeadProps?.handleClick) {
|
|
294
|
+
useTableProps.cellHeadProps.handleClick({
|
|
295
|
+
e,
|
|
296
|
+
cell: header,
|
|
297
|
+
table,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
<div className="flex items-center gap-1">
|
|
303
|
+
{flexRender(
|
|
304
|
+
header.column.columnDef.header,
|
|
305
|
+
header.getContext()
|
|
306
|
+
)}
|
|
307
|
+
{table.getRowModel().rows.length > 0 &&
|
|
308
|
+
surfix &&
|
|
309
|
+
surfix({ header, showSortIconHeader })}
|
|
310
|
+
</div>
|
|
311
|
+
</TableHead>
|
|
312
|
+
))}
|
|
313
|
+
</TableRow>
|
|
314
|
+
))}
|
|
315
|
+
</TableHeader>
|
|
240
316
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
317
|
+
<TableBody
|
|
318
|
+
className={cn(classNames?.body?.body)}
|
|
319
|
+
{...useTableProps?.bodyProps}
|
|
320
|
+
onClick={(e) => useTableProps?.bodyProps?.handleClick({ e, table })}
|
|
321
|
+
>
|
|
322
|
+
{isLoading && (
|
|
323
|
+
<TableSkeleton
|
|
324
|
+
props={useTableProps}
|
|
325
|
+
isLoading={isLoading}
|
|
326
|
+
classNames={classNames}
|
|
327
|
+
emptyLabel={emptyLabel}
|
|
328
|
+
columns={columns}
|
|
329
|
+
/>
|
|
330
|
+
)}
|
|
331
|
+
{!isLoading &&
|
|
332
|
+
table.getRowModel().rows.length > 0 &&
|
|
333
|
+
table.getRowModel().rows.map((row) => {
|
|
334
|
+
const { handleClick, onClick, ...rest } =
|
|
335
|
+
useTableProps?.rowBodyProps || {};
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<TableRow
|
|
339
|
+
{...(() => {
|
|
340
|
+
const { handleClick, onClick, ...rest } =
|
|
341
|
+
useTableProps?.rowBodyProps || {};
|
|
342
|
+
return rest;
|
|
343
|
+
})()}
|
|
344
|
+
key={row.id}
|
|
345
|
+
className={cn(classNames?.body?.row)}
|
|
346
|
+
data-state={row.getIsSelected() && "selected"}
|
|
347
|
+
// {...useTableProps?.rowBodyProps}
|
|
348
|
+
onClick={(e) => {
|
|
349
|
+
// Just call the parent's onClick if provided
|
|
350
|
+
if (useTableProps?.rowBodyProps?.onClick) {
|
|
351
|
+
useTableProps.rowBodyProps.onClick(e);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Just call the parent's handleClick if provided
|
|
355
|
+
if (useTableProps?.rowBodyProps?.handleClick) {
|
|
356
|
+
useTableProps.rowBodyProps.handleClick({
|
|
357
|
+
e,
|
|
358
|
+
row,
|
|
359
|
+
table,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}}
|
|
363
|
+
>
|
|
364
|
+
{row.getVisibleCells().map((cell) => (
|
|
365
|
+
<TableCell
|
|
366
|
+
{...(() => {
|
|
367
|
+
const { handleClick, onClick, ...rest } =
|
|
368
|
+
useTableProps?.cellBodyProps || {};
|
|
369
|
+
return rest;
|
|
370
|
+
})()}
|
|
371
|
+
key={cell.id}
|
|
372
|
+
className={cn(classNames?.body?.cell)}
|
|
373
|
+
// {...useTableProps?.cellBodyProps}
|
|
374
|
+
onClick={(e) => {
|
|
375
|
+
// Just call the parent's onClick if provided
|
|
376
|
+
if (useTableProps?.cellBodyProps?.onClick) {
|
|
377
|
+
useTableProps.cellBodyProps.onClick(e);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Just call the parent's handleClick if provided
|
|
381
|
+
if (useTableProps?.cellBodyProps?.handleClick) {
|
|
382
|
+
useTableProps.cellBodyProps.handleClick({
|
|
383
|
+
e,
|
|
384
|
+
cell,
|
|
385
|
+
table,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}}
|
|
389
|
+
>
|
|
390
|
+
{flexRender(
|
|
391
|
+
cell.column.columnDef.cell,
|
|
392
|
+
cell.getContext()
|
|
287
393
|
)}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
394
|
+
</TableCell>
|
|
395
|
+
))}
|
|
396
|
+
</TableRow>
|
|
397
|
+
);
|
|
398
|
+
})}
|
|
399
|
+
{!isLoading && table.getRowModel().rows.length === 0 && (
|
|
400
|
+
<TableRow
|
|
401
|
+
key="no-data"
|
|
402
|
+
className={cn(classNames?.body?.row)}
|
|
403
|
+
{...useTableProps?.rowBodyProps}
|
|
404
|
+
>
|
|
405
|
+
<TableCell
|
|
406
|
+
colSpan={columns.length}
|
|
407
|
+
className={cn("h-24 text-center", classNames?.body?.cell)}
|
|
408
|
+
{...useTableProps?.cellBodyProps}
|
|
409
|
+
>
|
|
410
|
+
{emptyLabel}
|
|
411
|
+
</TableCell>
|
|
412
|
+
</TableRow>
|
|
413
|
+
)}
|
|
414
|
+
</TableBody>
|
|
415
|
+
</Table>
|
|
416
|
+
</div>
|
|
417
|
+
{paginationTable && paginationTable({ table, fns: paginationFns })}
|
|
418
|
+
</div>
|
|
419
|
+
);
|
|
294
420
|
}
|
|
295
421
|
|
|
296
422
|
type TableSkeletonProps<TData, TValue> = {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
423
|
+
isLoading: boolean;
|
|
424
|
+
classNames?: TableClassNames;
|
|
425
|
+
emptyLabel?: string;
|
|
426
|
+
columns: ColumnDef<TData, TValue>[];
|
|
427
|
+
props?: UseTableProps<TData, TValue>;
|
|
302
428
|
};
|
|
303
429
|
|
|
304
|
-
export const TableSkeleton = <TData, TValue>({
|
|
305
|
-
|
|
306
|
-
|
|
430
|
+
export const TableSkeleton = <TData, TValue>({
|
|
431
|
+
isLoading,
|
|
432
|
+
classNames,
|
|
433
|
+
emptyLabel,
|
|
434
|
+
props,
|
|
435
|
+
columns,
|
|
436
|
+
}: TableSkeletonProps<TData, TValue>) => {
|
|
437
|
+
const [showNoData, setShowNoData] = useState(false);
|
|
438
|
+
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
307
439
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
return () => {
|
|
319
|
-
if (timerRef.current) {
|
|
320
|
-
clearTimeout(timerRef.current);
|
|
321
|
-
timerRef.current = null;
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
}, [isLoading]);
|
|
325
|
-
|
|
326
|
-
if (showNoData) {
|
|
327
|
-
return (
|
|
328
|
-
<TableRow key="no-data-skeleton" className={cn(classNames?.body?.row)} {...props?.rowBodyProps}>
|
|
329
|
-
<TableCell colSpan={columns.length} className={cn("h-24 text-center", classNames?.body?.cell)} {...props?.cellBodyProps}>
|
|
330
|
-
{emptyLabel}
|
|
331
|
-
</TableCell>
|
|
332
|
-
</TableRow>
|
|
333
|
-
);
|
|
440
|
+
useEffect(() => {
|
|
441
|
+
if (isLoading) {
|
|
442
|
+
timerRef.current = setTimeout(() => setShowNoData(true), 10000);
|
|
443
|
+
} else {
|
|
444
|
+
setShowNoData(false);
|
|
445
|
+
if (timerRef.current) {
|
|
446
|
+
clearTimeout(timerRef.current);
|
|
447
|
+
timerRef.current = null;
|
|
448
|
+
}
|
|
334
449
|
}
|
|
450
|
+
return () => {
|
|
451
|
+
if (timerRef.current) {
|
|
452
|
+
clearTimeout(timerRef.current);
|
|
453
|
+
timerRef.current = null;
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
}, [isLoading]);
|
|
457
|
+
|
|
458
|
+
if (showNoData) {
|
|
335
459
|
return (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
460
|
+
<TableRow
|
|
461
|
+
key="no-data-skeleton"
|
|
462
|
+
className={cn(classNames?.body?.row)}
|
|
463
|
+
{...props?.rowBodyProps}
|
|
464
|
+
>
|
|
465
|
+
<TableCell
|
|
466
|
+
colSpan={columns.length}
|
|
467
|
+
className={cn("h-24 text-center", classNames?.body?.cell)}
|
|
468
|
+
{...props?.cellBodyProps}
|
|
469
|
+
>
|
|
470
|
+
{emptyLabel}
|
|
471
|
+
</TableCell>
|
|
472
|
+
</TableRow>
|
|
347
473
|
);
|
|
348
|
-
}
|
|
474
|
+
}
|
|
475
|
+
return (
|
|
476
|
+
<>
|
|
477
|
+
{[...Array(5)].map((_, rowIndex) => (
|
|
478
|
+
<TableRow
|
|
479
|
+
key={`skeleton-${rowIndex}`}
|
|
480
|
+
className={cn(classNames?.body?.row)}
|
|
481
|
+
{...props?.rowBodyProps}
|
|
482
|
+
>
|
|
483
|
+
{columns.map((_, colIndex) => (
|
|
484
|
+
<TableCell
|
|
485
|
+
key={`skeleton-${rowIndex}-${colIndex}`}
|
|
486
|
+
className={cn(classNames?.body?.cell)}
|
|
487
|
+
{...props?.cellBodyProps}
|
|
488
|
+
>
|
|
489
|
+
<div className="shimmer h-4 w-full" />
|
|
490
|
+
</TableCell>
|
|
491
|
+
))}
|
|
492
|
+
</TableRow>
|
|
493
|
+
))}
|
|
494
|
+
</>
|
|
495
|
+
);
|
|
496
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Cookies from 'js-cookie';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @function set - Sets a cookie with the given name, value, and expiration days.
|
|
5
|
+
* @function get - Gets the value of a cookie with the given name.
|
|
6
|
+
* @function remove - Removes a cookie with the given name.
|
|
7
|
+
* @function exists - Checks if a cookie with the given name exists.
|
|
8
|
+
*/
|
|
9
|
+
export const ck = {
|
|
10
|
+
set: (name: string, value: string, days?: number) => {
|
|
11
|
+
Cookies.set(name, value, {
|
|
12
|
+
expires: days || 365 * 100, // Default to 100 years if not specified
|
|
13
|
+
path: "/",
|
|
14
|
+
secure: process.env.NODE_ENV === "production",
|
|
15
|
+
sameSite: "Lax",
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
get: (name: string): string | undefined => {
|
|
20
|
+
return Cookies.get(name);
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
remove: (name: string) => {
|
|
24
|
+
Cookies.remove(name, {path: "/"});
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
exists: (name: string): boolean => {
|
|
29
|
+
return Cookies.get(name) !== undefined;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export const REGEXS = {
|
|
4
|
+
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
5
|
+
phone: /^[0-9]{10,11}$/,
|
|
6
|
+
url: /^(https?:\/\/)?([\w-]+(\.[\w-]+)+)(\/[\w-]*)*(\?.*)?$/,
|
|
7
|
+
username: /^[a-zA-Z0-9_]{3,20}$/,
|
|
8
|
+
password: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,}$/,
|
|
9
|
+
postalCode: /^[0-9]{5,6}$/,
|
|
10
|
+
number: /^\d+$/,
|
|
11
|
+
decimal: /^\d+(\.\d{1,2})?$/,
|
|
12
|
+
name: /^[a-zA-ZÀ-ỹ\s]{1,50}$/,
|
|
13
|
+
date: /^\d{4}-\d{2}-\d{2}$/,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
interface ValidationRule {
|
|
17
|
+
required?: boolean;
|
|
18
|
+
pattern?: RegExp;
|
|
19
|
+
custom?: (value: string) => boolean;
|
|
20
|
+
minLength?: number;
|
|
21
|
+
maxLength?: number;
|
|
22
|
+
errorMessage?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type ValidationRules<T> = {
|
|
26
|
+
[K in keyof T]: ValidationRule;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type ValidationErrors<T> = {
|
|
30
|
+
[K in keyof T]?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const useFormValidator = <T extends Record<string, any>>(
|
|
34
|
+
initialValues: T,
|
|
35
|
+
validationRules: ValidationRules<T>
|
|
36
|
+
) => {
|
|
37
|
+
const [values, setValues] = useState<T>(initialValues);
|
|
38
|
+
const [errors, setErrors] = useState<ValidationErrors<T>>({});
|
|
39
|
+
|
|
40
|
+
const validateField = (field: keyof T, value: T[keyof T]): string | undefined => {
|
|
41
|
+
const rules = validationRules[field];
|
|
42
|
+
if (!rules) return undefined;
|
|
43
|
+
|
|
44
|
+
if (rules.required && !value) {
|
|
45
|
+
return rules.errorMessage || "This field is required.";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (rules.pattern && !rules.pattern.test(value)) {
|
|
49
|
+
return rules.errorMessage || "Invalid format.";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (rules.minLength && value.length < rules.minLength) {
|
|
53
|
+
return rules.errorMessage || `Minimum length is ${rules.minLength}.`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (rules.maxLength && value.length > rules.maxLength) {
|
|
57
|
+
return rules.errorMessage || `Maximum length is ${rules.maxLength}.`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (rules.custom && !rules.custom(value)) {
|
|
61
|
+
return rules.errorMessage || "Invalid value.";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return undefined;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const validateAllFields = (): boolean => {
|
|
68
|
+
const newErrors: ValidationErrors<T> = {};
|
|
69
|
+
let isValid = true;
|
|
70
|
+
|
|
71
|
+
for (const field in validationRules) {
|
|
72
|
+
const value = values[field];
|
|
73
|
+
const error = validateField(field, value);
|
|
74
|
+
if (error) {
|
|
75
|
+
isValid = false;
|
|
76
|
+
newErrors[field] = error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setErrors(newErrors);
|
|
81
|
+
return isValid;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const handleChange = <K extends keyof T>(field: K, value: T[K]) => {
|
|
85
|
+
setValues({...values, [field]: value});
|
|
86
|
+
const error = validateField(field, value);
|
|
87
|
+
setErrors({...errors, [field]: error});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
values,
|
|
92
|
+
errors,
|
|
93
|
+
handleChange,
|
|
94
|
+
validateAllFields,
|
|
95
|
+
setValues,
|
|
96
|
+
};
|
|
97
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kmod-cli",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Stack components utilities fast setup in projects",
|
|
5
5
|
"author": "kumo_d",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"commander": "^14.0.0",
|
|
13
13
|
"fs-extra": "^11.3.1",
|
|
14
|
-
"inquirer": "^12.9.4"
|
|
14
|
+
"inquirer": "^12.9.4",
|
|
15
|
+
"js-cookie": "^3.0.5"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@radix-ui/react-icons": "^1.3.2",
|
|
@@ -50,7 +51,8 @@
|
|
|
50
51
|
"tailwindcss": "^4.1.12",
|
|
51
52
|
"tsup": "^8.5.0",
|
|
52
53
|
"typescript": "^5.9.2",
|
|
53
|
-
"zustand": "^5.0.8"
|
|
54
|
+
"zustand": "^5.0.8",
|
|
55
|
+
"@types/js-cookie": "^3.0.6"
|
|
54
56
|
},
|
|
55
57
|
"files": [
|
|
56
58
|
"bin",
|