react-restyle-components 0.4.24 → 0.4.26
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/lib/src/core-components/src/components/Badge/Badge.d.ts +1 -1
- package/lib/src/core-components/src/components/FormField/FormField.d.ts +1 -1
- package/lib/src/core-components/src/components/Table/Table.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/Table.js +510 -46
- package/lib/src/core-components/src/components/Table/elements.d.ts +3 -0
- package/lib/src/core-components/src/components/Table/elements.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/elements.js +109 -76
- package/lib/src/core-components/src/components/Table/filters.d.ts +225 -8
- package/lib/src/core-components/src/components/Table/filters.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/filters.js +374 -64
- package/lib/src/core-components/src/components/Table/index.d.ts +1 -0
- package/lib/src/core-components/src/components/Table/index.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/types.d.ts +302 -7
- package/lib/src/core-components/src/components/Table/types.d.ts.map +1 -1
- package/lib/src/core-components/src/tc.global.css +28 -2
- package/lib/src/core-components/src/tc.module.css +3 -2
- package/package.json +1 -1
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React, { forwardRef, useState, useCallback, useMemo, useRef, } from 'react';
|
|
4
|
-
import { TableRoot, Toolbar, ToolbarGroup, SearchInput, ToolbarButton, TableWrapper, StyledTable, TableHeader, HeaderRow, HeaderCell,
|
|
4
|
+
import { TableRoot, Toolbar, ToolbarGroup, SearchInput, ToolbarButton, TableWrapper, StyledTable, TableHeader, HeaderRow, HeaderCell, TableBody, TableRow, TableCell, Checkbox, ExpandButton, ExpandedRow, ExpandedCell, TableFooter, FooterRow, FooterCell, PaginationWrapper, PaginationInfo, PaginationControls, PageButton, PageSizeSelect, QuickJumper, EmptyState, LoadingOverlay, LoadingSpinner, EditableCell, CellEditor, ColumnTogglePanel, ColumnToggleHeader, ColumnToggleSearch, ColumnToggleList, ColumnToggleItem, } from './elements';
|
|
5
5
|
import { useSortState, useFilterState, usePaginationState, useRowSelection, useRowExpansion, useColumnVisibility, useTableDebounce, sortData, filterData, paginateData, getNestedValue, exportToCSV, } from './hooks';
|
|
6
6
|
import { getFilterComponent } from './filters';
|
|
7
|
+
import { Tooltip } from '../Tooltip';
|
|
7
8
|
// Icons
|
|
8
9
|
const SearchIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("circle", { cx: "11", cy: "11", r: "8" }), _jsx("path", { d: "M21 21l-4.35-4.35", strokeLinecap: "round" })] }));
|
|
10
|
+
// Arrow Up Icon with configurable size
|
|
11
|
+
const ArrowUpIcon = ({ size = 14 }) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { width: size, height: size }, children: _jsx("path", { d: "M12 19V5M5 12l7-7 7 7" }) }));
|
|
12
|
+
// Arrow Down Icon with configurable size
|
|
13
|
+
const ArrowDownIcon = ({ size = 14 }) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { width: size, height: size }, children: _jsx("path", { d: "M12 5v14M5 12l7 7 7-7" }) }));
|
|
14
|
+
// Legacy triangle icons (kept for backward compatibility)
|
|
9
15
|
const SortUpIcon = () => (_jsx("svg", { viewBox: "0 0 10 10", fill: "currentColor", children: _jsx("path", { d: "M5 0L10 6H0L5 0z" }) }));
|
|
10
16
|
const SortDownIcon = () => (_jsx("svg", { viewBox: "0 0 10 10", fill: "currentColor", children: _jsx("path", { d: "M5 10L0 4h10L5 10z" }) }));
|
|
17
|
+
// Default sort caret component with arrow icons
|
|
18
|
+
const DefaultSortCaret = ({ order, }) => {
|
|
19
|
+
const getSizeConfig = () => {
|
|
20
|
+
switch (order) {
|
|
21
|
+
case 'asc':
|
|
22
|
+
return { up: 16, down: 10 };
|
|
23
|
+
case 'desc':
|
|
24
|
+
return { up: 10, down: 16 };
|
|
25
|
+
default:
|
|
26
|
+
return { up: 14, down: 14 };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const { up, down } = getSizeConfig();
|
|
30
|
+
return (_jsxs("div", { style: {
|
|
31
|
+
display: 'flex',
|
|
32
|
+
flexDirection: 'row',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
gap: 2,
|
|
36
|
+
color: 'white',
|
|
37
|
+
}, children: [_jsx(ArrowUpIcon, { size: up }), _jsx(ArrowDownIcon, { size: down })] }));
|
|
38
|
+
};
|
|
11
39
|
const ChevronLeftIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M15 18l-6-6 6-6", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
12
40
|
const ChevronRightIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M9 18l6-6-6-6", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
13
41
|
const ChevronsLeftIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M11 17l-5-5 5-5M18 17l-5-5 5-5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
@@ -18,14 +46,84 @@ const FilterIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stro
|
|
|
18
46
|
const DownloadIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
19
47
|
const ColumnsIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("rect", { x: "3", y: "3", width: "7", height: "18", rx: "1" }), _jsx("rect", { x: "14", y: "3", width: "7", height: "18", rx: "1" })] }));
|
|
20
48
|
const EmptyIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), _jsx("path", { d: "M3 9h18M9 3v18", strokeLinecap: "round" })] }));
|
|
49
|
+
const EditIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
50
|
+
const DeleteIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
51
|
+
const ViewIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
|
|
52
|
+
const RefreshIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M23 4v6h-6M1 20v-6h6", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
53
|
+
const PrintIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M6 9V2h12v7M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("rect", { x: "6", y: "14", width: "12", height: "8" })] }));
|
|
54
|
+
const ErrorIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 8v4M12 16h.01", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
21
55
|
export const Table = forwardRef(function TableComponent(props, ref) {
|
|
22
|
-
const { id, data, columns, keyField = '_id', loading = false, loadingIndicator, pagination = true, paginationConfig, totalSize, remote = false, defaultSort, sort: controlledSort, filterable = false, defaultFilters, filters: controlledFilters, searchable =
|
|
56
|
+
const { id, data, columns, keyField = '_id', loading = false, loadingIndicator, pagination = true, paginationConfig, totalSize, remote = false, defaultSort, sort: controlledSort, filterable = false, defaultFilters, filters: controlledFilters, defaultShowFilters = true, showFilters: controlledShowFilters, onShowFiltersChange, showFilterToggle = true, searchable = true, searchPlaceholder = 'Search...', defaultSearchValue = '', searchValue: controlledSearchValue, searchDebounce = 300, rowSelection, expandable, editMode = 'none', onCellEdit, exportable = true, exportFileName = 'table_export', columnToggle = false, bordered = true, striped = false, hover = true, compact = false, cellPadding, stickyHeader = false, maxHeight, rowClassName, rowStyle, classNames = {}, styles = {}, className, style, emptyText = 'No data available', onChange, onPageChange, onSortChange, onFilterChange, onSearch, onRowClick, onRowDoubleClick, onClearFilters, toolbar, hideToolbar = false, showFooter = false, caption,
|
|
57
|
+
// Quick configuration props
|
|
58
|
+
isDelete = false, isEditModify, isUpdate, isExport, isSelectRow, fileName, hideExcelSheet = false,
|
|
59
|
+
// Quick callbacks
|
|
60
|
+
onSelectedRow, onUpdateItem, onPageSizeChange, onFilter, clearAllFilter,
|
|
61
|
+
// Dynamic configuration
|
|
62
|
+
dynamicStylingFields, fieldTypeConfig,
|
|
63
|
+
// Action column
|
|
64
|
+
showActionColumn, actionColumnWidth = 100, actionColumnTitle = 'Actions', actionColumnPosition = 'last', actionColumnRender, onDelete, onEdit, onView, isView = false,
|
|
65
|
+
// Row number
|
|
66
|
+
showRowNumber = false, rowNumberWidth = 50, rowNumberTitle = '#', rowNumberRender,
|
|
67
|
+
// Toolbar customization
|
|
68
|
+
toolbarPosition = 'top', toolbarLeft, toolbarRight, toolbarCenter,
|
|
69
|
+
// Refresh
|
|
70
|
+
refreshable = false, onRefresh,
|
|
71
|
+
// Print
|
|
72
|
+
printable = false, onPrint,
|
|
73
|
+
// Size
|
|
74
|
+
size = 'medium',
|
|
75
|
+
// Error state
|
|
76
|
+
error, onRetry,
|
|
77
|
+
// Skeleton loading
|
|
78
|
+
skeletonLoading = false, skeletonRowCount = 5,
|
|
79
|
+
// Hide header
|
|
80
|
+
hideHeader = false,
|
|
81
|
+
// Highlighted rows
|
|
82
|
+
highlightedRowKeys = [], highlightRowStyle, highlightRowClassName,
|
|
83
|
+
// Events
|
|
84
|
+
onRowMouseEnter, onRowMouseLeave, onCellClick, onHeaderClick, ...rest } = props;
|
|
85
|
+
// Resolve aliases
|
|
86
|
+
const resolvedExportable = isExport ?? exportable;
|
|
87
|
+
const resolvedExportFileName = fileName ?? exportFileName;
|
|
88
|
+
const resolvedIsEdit = isEditModify ?? isUpdate ?? false;
|
|
89
|
+
const resolvedIsView = isView;
|
|
90
|
+
const resolvedShowActionColumn = showActionColumn ?? (isDelete || resolvedIsEdit || resolvedIsView);
|
|
91
|
+
// Handle isSelectRow shorthand
|
|
92
|
+
const resolvedRowSelection = isSelectRow
|
|
93
|
+
? {
|
|
94
|
+
mode: 'checkbox',
|
|
95
|
+
...rowSelection,
|
|
96
|
+
onChange: (keys, rows) => {
|
|
97
|
+
rowSelection?.onChange?.(keys, rows);
|
|
98
|
+
onSelectedRow?.(rows);
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
: rowSelection;
|
|
102
|
+
// Size configuration
|
|
103
|
+
const sizeConfig = {
|
|
104
|
+
small: { padding: '4px 8px', fontSize: '12px' },
|
|
105
|
+
medium: { padding: '8px 12px', fontSize: '14px' },
|
|
106
|
+
large: { padding: '12px 16px', fontSize: '16px' },
|
|
107
|
+
};
|
|
23
108
|
// Refs
|
|
24
109
|
const tableRef = useRef(null);
|
|
25
110
|
// State
|
|
26
111
|
const [internalSearchValue, setInternalSearchValue] = useState(defaultSearchValue);
|
|
112
|
+
const [internalShowFilters, setInternalShowFilters] = useState(defaultShowFilters);
|
|
27
113
|
const [columnToggleOpen, setColumnToggleOpen] = useState(false);
|
|
28
114
|
const [columnSearch, setColumnSearch] = useState('');
|
|
115
|
+
// Filter visibility (controlled or uncontrolled)
|
|
116
|
+
const isFilterVisibilityControlled = controlledShowFilters !== undefined;
|
|
117
|
+
const showFilterRow = isFilterVisibilityControlled
|
|
118
|
+
? controlledShowFilters
|
|
119
|
+
: internalShowFilters;
|
|
120
|
+
const handleToggleFilters = useCallback(() => {
|
|
121
|
+
const newValue = !showFilterRow;
|
|
122
|
+
if (!isFilterVisibilityControlled) {
|
|
123
|
+
setInternalShowFilters(newValue);
|
|
124
|
+
}
|
|
125
|
+
onShowFiltersChange?.(newValue);
|
|
126
|
+
}, [showFilterRow, isFilterVisibilityControlled, onShowFiltersChange]);
|
|
29
127
|
const [editingCell, setEditingCell] = useState(null);
|
|
30
128
|
const [editValue, setEditValue] = useState(null);
|
|
31
129
|
const searchValue = controlledSearchValue ?? internalSearchValue;
|
|
@@ -58,7 +156,17 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
58
156
|
result = paginateData(result, page, pageSize);
|
|
59
157
|
}
|
|
60
158
|
return result;
|
|
61
|
-
}, [
|
|
159
|
+
}, [
|
|
160
|
+
data,
|
|
161
|
+
filters,
|
|
162
|
+
sort,
|
|
163
|
+
page,
|
|
164
|
+
pageSize,
|
|
165
|
+
debouncedSearchValue,
|
|
166
|
+
remote,
|
|
167
|
+
pagination,
|
|
168
|
+
columns,
|
|
169
|
+
]);
|
|
62
170
|
// Calculate total for client-side
|
|
63
171
|
const calculatedTotal = useMemo(() => {
|
|
64
172
|
if (remote)
|
|
@@ -82,14 +190,17 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
82
190
|
// Handle filter
|
|
83
191
|
const handleFilterChange = useCallback((field, value) => {
|
|
84
192
|
setFilter(field, value);
|
|
85
|
-
|
|
86
|
-
|
|
193
|
+
const newFilters = { ...filters, [field]: value };
|
|
194
|
+
onFilterChange?.(newFilters);
|
|
195
|
+
onFilter?.('filter', newFilters, page, pageSize);
|
|
196
|
+
onChange?.({ type: 'filter', filters: newFilters });
|
|
87
197
|
}, [filters, setFilter, onFilterChange, onChange]);
|
|
88
198
|
// Handle clear all filters
|
|
89
199
|
const handleClearFilters = useCallback(() => {
|
|
90
200
|
clearFilters();
|
|
91
201
|
setInternalSearchValue('');
|
|
92
202
|
onClearFilters?.();
|
|
203
|
+
clearAllFilter?.();
|
|
93
204
|
onFilterChange?.({});
|
|
94
205
|
onChange?.({ type: 'filter', filters: {} });
|
|
95
206
|
}, [clearFilters, onClearFilters, onFilterChange, onChange]);
|
|
@@ -97,13 +208,18 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
97
208
|
const handlePageChange = useCallback((newPage) => {
|
|
98
209
|
goToPage(newPage);
|
|
99
210
|
onPageChange?.(newPage, pageSize);
|
|
211
|
+
onPageSizeChange?.(newPage, pageSize);
|
|
100
212
|
onChange?.({ type: 'pagination', pagination: { page: newPage, pageSize } });
|
|
101
|
-
}, [goToPage, pageSize, onPageChange, onChange]);
|
|
213
|
+
}, [goToPage, pageSize, onPageChange, onPageSizeChange, onChange]);
|
|
102
214
|
// Handle page size change
|
|
103
215
|
const handlePageSizeChange = useCallback((newSize) => {
|
|
104
216
|
changePageSize(newSize);
|
|
105
217
|
onPageChange?.(0, newSize);
|
|
106
|
-
|
|
218
|
+
onPageSizeChange?.(0, newSize);
|
|
219
|
+
onChange?.({
|
|
220
|
+
type: 'pagination',
|
|
221
|
+
pagination: { page: 0, pageSize: newSize },
|
|
222
|
+
});
|
|
107
223
|
}, [changePageSize, onPageChange, onChange]);
|
|
108
224
|
// Handle row click
|
|
109
225
|
const handleRowClick = useCallback((row, rowIndex, e) => {
|
|
@@ -123,22 +239,45 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
123
239
|
}
|
|
124
240
|
onRowClick?.(row, rowIndex, e);
|
|
125
241
|
}, [rowSelection, expandable, toggleRow, toggleExpand, onRowClick]);
|
|
242
|
+
// Helper to check if cell is editable and get custom editor
|
|
243
|
+
const getCellEditableInfo = useCallback((column, row, rowIndex, colIndex) => {
|
|
244
|
+
if (!column.editable) {
|
|
245
|
+
return { isEditable: false };
|
|
246
|
+
}
|
|
247
|
+
if (typeof column.editable === 'boolean') {
|
|
248
|
+
return { isEditable: column.editable };
|
|
249
|
+
}
|
|
250
|
+
// It's a function
|
|
251
|
+
const cellValue = getNestedValue(row, column.dataField);
|
|
252
|
+
const result = column.editable(cellValue, row, rowIndex, colIndex);
|
|
253
|
+
if (typeof result === 'boolean') {
|
|
254
|
+
return { isEditable: result };
|
|
255
|
+
}
|
|
256
|
+
// Result is a custom editor (ReactNode)
|
|
257
|
+
return { isEditable: true, customEditor: result };
|
|
258
|
+
}, []);
|
|
126
259
|
// Handle cell edit
|
|
127
|
-
const handleCellDoubleClick = useCallback((row, rowIndex, column, e) => {
|
|
128
|
-
if (editMode === 'none'
|
|
260
|
+
const handleCellDoubleClick = useCallback((row, rowIndex, column, colIndex, e) => {
|
|
261
|
+
if (editMode === 'none')
|
|
262
|
+
return;
|
|
263
|
+
const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
|
|
264
|
+
if (!isEditable)
|
|
129
265
|
return;
|
|
130
266
|
if (editMode === 'dblclick') {
|
|
131
267
|
setEditingCell({ row: rowIndex, field: column.dataField });
|
|
132
268
|
setEditValue(getNestedValue(row, column.dataField));
|
|
133
269
|
}
|
|
134
270
|
onRowDoubleClick?.(row, rowIndex, e);
|
|
135
|
-
}, [editMode, onRowDoubleClick]);
|
|
136
|
-
const handleCellClick = useCallback((row, rowIndex, column) => {
|
|
137
|
-
if (editMode !== 'click'
|
|
271
|
+
}, [editMode, onRowDoubleClick, getCellEditableInfo]);
|
|
272
|
+
const handleCellClick = useCallback((row, rowIndex, column, colIndex) => {
|
|
273
|
+
if (editMode !== 'click')
|
|
274
|
+
return;
|
|
275
|
+
const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
|
|
276
|
+
if (!isEditable)
|
|
138
277
|
return;
|
|
139
278
|
setEditingCell({ row: rowIndex, field: column.dataField });
|
|
140
279
|
setEditValue(getNestedValue(row, column.dataField));
|
|
141
|
-
}, [editMode]);
|
|
280
|
+
}, [editMode, getCellEditableInfo]);
|
|
142
281
|
const handleCellEditComplete = useCallback((row, rowIndex, column) => {
|
|
143
282
|
if (editingCell) {
|
|
144
283
|
// Validate
|
|
@@ -150,15 +289,159 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
150
289
|
return;
|
|
151
290
|
}
|
|
152
291
|
}
|
|
292
|
+
const rowId = row[keyField];
|
|
153
293
|
onCellEdit?.(editValue, column.dataField, row, rowIndex);
|
|
294
|
+
onUpdateItem?.(editValue, column.dataField, rowId);
|
|
154
295
|
}
|
|
155
296
|
setEditingCell(null);
|
|
156
|
-
}, [editingCell, editValue, onCellEdit]);
|
|
297
|
+
}, [editingCell, editValue, onCellEdit, onUpdateItem, keyField]);
|
|
298
|
+
// Helper to get nested value from object
|
|
299
|
+
const getNestedValueLocal = (obj, path) => {
|
|
300
|
+
return path.split('.').reduce((acc, key) => acc?.[key], obj);
|
|
301
|
+
};
|
|
302
|
+
// Process field value based on fieldTypeConfig (matching reference implementation)
|
|
303
|
+
const processFieldValue = useCallback((value, dataField, row) => {
|
|
304
|
+
const config = fieldTypeConfig?.[dataField];
|
|
305
|
+
const fieldType = config?.type || 'string';
|
|
306
|
+
switch (fieldType) {
|
|
307
|
+
case 'array':
|
|
308
|
+
if (config?.fields && config.fields.length > 0) {
|
|
309
|
+
// Array of objects with specific fields to extract
|
|
310
|
+
if (!Array.isArray(value))
|
|
311
|
+
return value || '';
|
|
312
|
+
return value
|
|
313
|
+
.slice(0, config.maxItems || value.length)
|
|
314
|
+
.map((item) => {
|
|
315
|
+
if (typeof item === 'object' && config.fields) {
|
|
316
|
+
// Extract only specified fields from the object
|
|
317
|
+
return config.fields
|
|
318
|
+
.map((field) => item[field])
|
|
319
|
+
.filter(Boolean)
|
|
320
|
+
.join(', ');
|
|
321
|
+
}
|
|
322
|
+
else if (typeof item === 'string') {
|
|
323
|
+
return item;
|
|
324
|
+
}
|
|
325
|
+
return '';
|
|
326
|
+
})
|
|
327
|
+
.filter(Boolean)
|
|
328
|
+
.join(config.separator || '; ');
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
// Default array handling
|
|
332
|
+
if (!Array.isArray(value))
|
|
333
|
+
return value || '';
|
|
334
|
+
return value
|
|
335
|
+
.map((item) => typeof item === 'object' ? JSON.stringify(item) : item)
|
|
336
|
+
.join('; ');
|
|
337
|
+
}
|
|
338
|
+
case 'object':
|
|
339
|
+
if (!value || typeof value !== 'object')
|
|
340
|
+
return '';
|
|
341
|
+
const fields = config?.fields || config?.keys || [];
|
|
342
|
+
const labelMap = config?.labelMap || {};
|
|
343
|
+
if (fields.length > 0) {
|
|
344
|
+
// Extract specific fields with optional label mapping
|
|
345
|
+
return fields
|
|
346
|
+
.map((field) => {
|
|
347
|
+
const nestedValue = getNestedValueLocal(value, field);
|
|
348
|
+
if (nestedValue !== undefined && nestedValue !== null) {
|
|
349
|
+
const label = labelMap[field] || field;
|
|
350
|
+
return `${label}: ${nestedValue}`;
|
|
351
|
+
}
|
|
352
|
+
return null;
|
|
353
|
+
})
|
|
354
|
+
.filter(Boolean)
|
|
355
|
+
.join(', ');
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
// Default object handling
|
|
359
|
+
return Object.entries(value)
|
|
360
|
+
.map(([key, val]) => typeof val === 'boolean'
|
|
361
|
+
? `${key}: ${val ? 'Yes' : 'No'}`
|
|
362
|
+
: `${key}: ${val}`)
|
|
363
|
+
.join(', ');
|
|
364
|
+
}
|
|
365
|
+
case 'date':
|
|
366
|
+
if (!value)
|
|
367
|
+
return '';
|
|
368
|
+
try {
|
|
369
|
+
const date = new Date(value);
|
|
370
|
+
const format = config?.dateFormat || 'YYYY-MM-DD HH:mm:ss';
|
|
371
|
+
// Simple date formatting
|
|
372
|
+
return date.toISOString().slice(0, 19).replace('T', ' ');
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return String(value);
|
|
376
|
+
}
|
|
377
|
+
case 'number':
|
|
378
|
+
return value !== undefined && value !== null
|
|
379
|
+
? String(Number(value))
|
|
380
|
+
: '';
|
|
381
|
+
case 'boolean':
|
|
382
|
+
return typeof value === 'boolean' ? (value ? 'Yes' : 'No') : '';
|
|
383
|
+
case 'string':
|
|
384
|
+
case 'text':
|
|
385
|
+
default:
|
|
386
|
+
if (typeof value === 'boolean')
|
|
387
|
+
return value ? 'Yes' : 'No';
|
|
388
|
+
return value !== undefined && value !== null ? String(value) : '';
|
|
389
|
+
}
|
|
390
|
+
}, [fieldTypeConfig]);
|
|
157
391
|
// Handle export
|
|
158
392
|
const handleExport = useCallback(() => {
|
|
159
|
-
const exportData = remote
|
|
160
|
-
|
|
161
|
-
|
|
393
|
+
const exportData = remote
|
|
394
|
+
? data
|
|
395
|
+
: filterData(data, filters, columns, debouncedSearchValue);
|
|
396
|
+
// Filter columns based on hideExcelSheet array and csvExport !== false
|
|
397
|
+
let exportColumns = visibleColumns.filter((col) => col.csvExport !== false);
|
|
398
|
+
if (Array.isArray(hideExcelSheet)) {
|
|
399
|
+
exportColumns = exportColumns.filter((col) => !hideExcelSheet.includes(col.dataField));
|
|
400
|
+
}
|
|
401
|
+
// Also filter based on fieldTypeConfig hideFromExport or csvExport
|
|
402
|
+
if (fieldTypeConfig) {
|
|
403
|
+
exportColumns = exportColumns.filter((col) => {
|
|
404
|
+
const config = fieldTypeConfig[col.dataField];
|
|
405
|
+
if (config?.hideFromExport)
|
|
406
|
+
return false;
|
|
407
|
+
if (config?.csvExport === false)
|
|
408
|
+
return false;
|
|
409
|
+
return true;
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
// Create enhanced columns with export formatters
|
|
413
|
+
const enhancedColumns = exportColumns.map((col) => {
|
|
414
|
+
const config = fieldTypeConfig?.[col.dataField];
|
|
415
|
+
// If column already has csvFormatter, use it
|
|
416
|
+
if (col.csvFormatter) {
|
|
417
|
+
return col;
|
|
418
|
+
}
|
|
419
|
+
// If config has exportFormatter, use it
|
|
420
|
+
if (config?.exportFormatter) {
|
|
421
|
+
return { ...col, csvFormatter: config.exportFormatter };
|
|
422
|
+
}
|
|
423
|
+
// If config has type, create formatter based on type
|
|
424
|
+
if (config?.type) {
|
|
425
|
+
return {
|
|
426
|
+
...col,
|
|
427
|
+
csvFormatter: (cell, row) => processFieldValue(cell, col.dataField, row),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return col;
|
|
431
|
+
});
|
|
432
|
+
exportToCSV(exportData, enhancedColumns, resolvedExportFileName);
|
|
433
|
+
}, [
|
|
434
|
+
data,
|
|
435
|
+
filters,
|
|
436
|
+
columns,
|
|
437
|
+
debouncedSearchValue,
|
|
438
|
+
visibleColumns,
|
|
439
|
+
hideExcelSheet,
|
|
440
|
+
fieldTypeConfig,
|
|
441
|
+
processFieldValue,
|
|
442
|
+
resolvedExportFileName,
|
|
443
|
+
remote,
|
|
444
|
+
]);
|
|
162
445
|
// Handle checkbox change
|
|
163
446
|
const handleCheckboxChange = useCallback((row, e) => {
|
|
164
447
|
e.stopPropagation();
|
|
@@ -190,8 +473,27 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
190
473
|
// Render cell content
|
|
191
474
|
const renderCellContent = useCallback((row, column, rowIndex, colIndex) => {
|
|
192
475
|
const value = getNestedValue(row, column.dataField);
|
|
193
|
-
const isEditing = editingCell?.row === rowIndex &&
|
|
476
|
+
const isEditing = editingCell?.row === rowIndex &&
|
|
477
|
+
editingCell?.field === column.dataField;
|
|
194
478
|
if (isEditing) {
|
|
479
|
+
// Check for custom editorRenderer
|
|
480
|
+
if (column.editorRenderer) {
|
|
481
|
+
const editorProps = {
|
|
482
|
+
value: editValue,
|
|
483
|
+
onUpdate: (newValue) => {
|
|
484
|
+
setEditValue(newValue);
|
|
485
|
+
handleCellEditComplete(row, rowIndex, column);
|
|
486
|
+
},
|
|
487
|
+
onCancel: () => setEditingCell(null),
|
|
488
|
+
onBlur: () => handleCellEditComplete(row, rowIndex, column),
|
|
489
|
+
row,
|
|
490
|
+
column,
|
|
491
|
+
rowIndex,
|
|
492
|
+
columnIndex: colIndex,
|
|
493
|
+
};
|
|
494
|
+
return column.editorRenderer(editorProps, editValue, row, column, rowIndex, colIndex);
|
|
495
|
+
}
|
|
496
|
+
// Default editor
|
|
195
497
|
return (_jsx(CellEditor, { type: column.editorType === 'number' ? 'number' : 'text', value: editValue ?? '', onChange: (e) => setEditValue(e.target.value), onBlur: () => handleCellEditComplete(row, rowIndex, column), onKeyDown: (e) => {
|
|
196
498
|
if (e.key === 'Enter') {
|
|
197
499
|
handleCellEditComplete(row, rowIndex, column);
|
|
@@ -199,7 +501,7 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
199
501
|
if (e.key === 'Escape') {
|
|
200
502
|
setEditingCell(null);
|
|
201
503
|
}
|
|
202
|
-
}, autoFocus: true }));
|
|
504
|
+
}, className: column.editorClasses, style: column.editorStyle, autoFocus: true }));
|
|
203
505
|
}
|
|
204
506
|
if (column.formatter) {
|
|
205
507
|
return column.formatter(value, row, rowIndex, colIndex);
|
|
@@ -227,7 +529,25 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
227
529
|
if (toolbar)
|
|
228
530
|
return toolbar;
|
|
229
531
|
const hasFilters = Object.keys(filters).length > 0 || searchValue;
|
|
230
|
-
return (_jsxs(Toolbar, { className: classNames.toolbar, style: styles.toolbar, children: [_jsxs(ToolbarGroup, { children: [searchable && (_jsxs(SearchInput, { children: [_jsx(SearchIcon, {}), _jsx("input", { type: "text", value: searchValue, onChange: (e) => handleSearchChange(e.target.value), placeholder: searchPlaceholder })] })),
|
|
532
|
+
return (_jsxs(Toolbar, { className: classNames.toolbar, style: styles.toolbar, children: [_jsxs(ToolbarGroup, { children: [toolbarLeft, searchable && (_jsxs(SearchInput, { children: [_jsx(SearchIcon, {}), _jsx("input", { type: "text", value: searchValue, onChange: (e) => handleSearchChange(e.target.value), placeholder: searchPlaceholder })] })), searchable && (_jsx(ToolbarButton, { onClick: () => handleSearchChange(''), disabled: !searchValue, style: { opacity: searchValue ? 1 : 0.6 }, children: "Clear" })), _jsx(ToolbarButton, { onClick: handleClearFilters, disabled: !hasFilters, style: { opacity: hasFilters ? 1 : 0.6 }, children: "Clear all filters" }), resolvedExportable && hideExcelSheet !== true && (_jsxs(ToolbarButton, { onClick: handleExport, children: [_jsx(DownloadIcon, {}), "Export CSV"] })), showFilterToggle && (_jsxs("div", { style: { position: 'relative' }, children: [_jsx(Tooltip, { content: "Show/Hide Columns", position: "bottom", children: _jsx(ToolbarButton, { "$active": columnToggleOpen, onClick: () => setColumnToggleOpen(!columnToggleOpen), "aria-label": "Toggle column visibility", style: { padding: '0 8px' }, children: _jsx(FilterIcon, {}) }) }), columnToggleOpen && (_jsxs(ColumnTogglePanel, { children: [_jsxs(ColumnToggleHeader, { children: [_jsx("span", { children: "Show/Hide Columns" }), _jsx("button", { onClick: () => setColumnToggleOpen(false), children: _jsx(CloseIcon, {}) })] }), _jsx(ColumnToggleSearch, { children: _jsx("input", { type: "text", value: columnSearch, onChange: (e) => setColumnSearch(e.target.value), placeholder: "Search columns..." }) }), _jsxs(ColumnToggleList, { children: [_jsxs(ColumnToggleItem, { style: {
|
|
533
|
+
borderBottom: '1px solid #e5e7eb',
|
|
534
|
+
paddingBottom: 8,
|
|
535
|
+
marginBottom: 4,
|
|
536
|
+
}, children: [_jsx("input", { type: "checkbox", checked: filteredToggleColumns.length > 0 &&
|
|
537
|
+
filteredToggleColumns.every((col) => !isColumnHidden(col.dataField)), onChange: (e) => {
|
|
538
|
+
filteredToggleColumns.forEach((col) => {
|
|
539
|
+
if (e.target.checked) {
|
|
540
|
+
if (isColumnHidden(col.dataField)) {
|
|
541
|
+
toggleColumn(col.dataField);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
if (!isColumnHidden(col.dataField)) {
|
|
546
|
+
toggleColumn(col.dataField);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
} }), _jsx("span", { style: { fontWeight: 600 }, children: "Select All" })] }), filteredToggleColumns.map((column) => (_jsxs(ColumnToggleItem, { children: [_jsx("input", { type: "checkbox", checked: !isColumnHidden(column.dataField), onChange: () => toggleColumn(column.dataField) }), _jsx("span", { children: column.text })] }, column.dataField)))] })] }))] }))] }), toolbarCenter, _jsxs(ToolbarGroup, { children: [refreshable && (_jsxs(ToolbarButton, { onClick: onRefresh, children: [_jsx(RefreshIcon, {}), "Refresh"] })), printable && (_jsxs(ToolbarButton, { onClick: onPrint, children: [_jsx(PrintIcon, {}), "Print"] })), columnToggle && (_jsxs("div", { style: { position: 'relative' }, children: [_jsxs(ToolbarButton, { "$active": columnToggleOpen, onClick: () => setColumnToggleOpen(!columnToggleOpen), children: [_jsx(ColumnsIcon, {}), "Columns"] }), columnToggleOpen && (_jsxs(ColumnTogglePanel, { children: [_jsxs(ColumnToggleHeader, { children: [_jsx("span", { children: "Toggle Columns" }), _jsx("button", { onClick: () => setColumnToggleOpen(false), children: _jsx(CloseIcon, {}) })] }), _jsx(ColumnToggleSearch, { children: _jsx("input", { type: "text", value: columnSearch, onChange: (e) => setColumnSearch(e.target.value), placeholder: "Search columns..." }) }), _jsx(ColumnToggleList, { children: filteredToggleColumns.map((column) => (_jsxs(ColumnToggleItem, { children: [_jsx("input", { type: "checkbox", checked: !isColumnHidden(column.dataField), onChange: () => toggleColumn(column.dataField) }), _jsx("span", { children: column.text })] }, column.dataField))) })] }))] })), toolbarRight] })] }));
|
|
231
551
|
};
|
|
232
552
|
// Render pagination
|
|
233
553
|
const renderPagination = () => {
|
|
@@ -287,28 +607,103 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
287
607
|
}
|
|
288
608
|
} })] }))] }));
|
|
289
609
|
};
|
|
290
|
-
//
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
610
|
+
// Check if any columns have filters
|
|
611
|
+
const hasFilterableColumns = filterable ||
|
|
612
|
+
columns.some((c) => typeof c.filter === 'function' ||
|
|
613
|
+
c.filterComponent ||
|
|
614
|
+
c.filter === true);
|
|
615
|
+
// Should show filter row - check if there are filterable columns AND filters are visible
|
|
616
|
+
const shouldShowFilterRow = hasFilterableColumns && showFilterRow;
|
|
617
|
+
return (_jsxs(TableRoot, { ref: ref, "$bordered": bordered, "$compact": compact, className: className || classNames.root, style: { ...styles.root, ...style, position: 'relative' }, "aria-label": rest['aria-label'], "aria-labelledby": rest['aria-labelledby'], children: [loading && (_jsx(LoadingOverlay, { className: classNames.loading, style: styles.loading, children: loadingIndicator || _jsx(LoadingSpinner, {}) })), renderToolbar(), _jsx(TableWrapper, { "$maxHeight": maxHeight, "$stickyHeader": stickyHeader, className: classNames.wrapper, style: styles.wrapper, children: _jsxs(StyledTable, { ref: tableRef, "$striped": striped, "$hover": hover, "$compact": compact, role: "grid", children: [caption && _jsx("caption", { className: "sr-only", children: caption }), _jsx(TableHeader, { "$sticky": stickyHeader, className: classNames.header, style: styles.header, children: _jsxs(HeaderRow, { className: classNames.headerRow, style: styles.headerRow, children: [rowSelection?.mode === 'checkbox' && (_jsx(HeaderCell, { "$align": "center", "$sortable": false, "$compact": compact, "$width": rowSelection.columnWidth || 40, children: !rowSelection.hideSelectAll && (_jsx(Checkbox, { checked: isAllSelected, ref: (el) => {
|
|
618
|
+
if (el)
|
|
619
|
+
el.indeterminate = isIndeterminate;
|
|
620
|
+
}, onChange: handleSelectAllChange })) })), expandable && (_jsx(HeaderCell, { "$align": "center", "$sortable": false, "$compact": compact, "$width": expandable.columnWidth || 40 })), showRowNumber && (_jsx(HeaderCell, { "$align": "center", "$sortable": false, "$compact": compact, "$width": rowNumberWidth, children: rowNumberTitle })), visibleColumns.map((column, colIndex) => {
|
|
621
|
+
// Determine if column has a filter
|
|
622
|
+
const hasColumnFilter = typeof column.filter === 'function' ||
|
|
623
|
+
column.filter === true ||
|
|
624
|
+
column.filterComponent ||
|
|
625
|
+
column.filterRenderer;
|
|
626
|
+
// Get the filter component
|
|
627
|
+
const FilterComponent = hasColumnFilter
|
|
628
|
+
? (typeof column.filter === 'function'
|
|
629
|
+
? column.filter
|
|
630
|
+
: null) ||
|
|
631
|
+
column.filterComponent ||
|
|
632
|
+
getFilterComponent(column.filterType || 'text')
|
|
633
|
+
: null;
|
|
634
|
+
const onFilter = (value) => handleFilterChange(column.dataField, value);
|
|
635
|
+
return (_jsx(HeaderCell, { "$align": column.headerAlign || column.align || 'left', "$sortable": !!column.sort, "$compact": compact, "$width": column.width, "$minWidth": column.minWidth, "$pinned": column.pinned, "$customClass": !!column.headerClasses, className: [column.headerClasses, classNames.headerCell]
|
|
636
|
+
.filter(Boolean)
|
|
637
|
+
.join(' '), style: typeof column.headerStyle === 'function'
|
|
296
638
|
? column.headerStyle(column)
|
|
297
|
-
: column.headerStyle || styles.headerCell,
|
|
639
|
+
: column.headerStyle || styles.headerCell, role: "columnheader", "aria-sort": sort.field === column.dataField
|
|
298
640
|
? sort.order === 'asc'
|
|
299
641
|
? 'ascending'
|
|
300
642
|
: sort.order === 'desc'
|
|
301
643
|
? 'descending'
|
|
302
644
|
: 'none'
|
|
303
|
-
: undefined, children:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
645
|
+
: undefined, children: (() => {
|
|
646
|
+
// Check visibility props (default to true if not specified)
|
|
647
|
+
const headerStyleObj = typeof column.headerStyle === 'function'
|
|
648
|
+
? column.headerStyle(column)
|
|
649
|
+
: column.headerStyle;
|
|
650
|
+
// isHeaderTitle: show title (default true, false to hide)
|
|
651
|
+
const showTitle = column.isHeaderTitle !== false &&
|
|
652
|
+
column.hideHeaderText !== true &&
|
|
653
|
+
!(headerStyleObj && headerStyleObj.fontSize === 0);
|
|
654
|
+
// isHeaderFilterComp: show filter (default true)
|
|
655
|
+
const showFilter = column.isHeaderFilterComp !== false &&
|
|
656
|
+
shouldShowFilterRow &&
|
|
657
|
+
hasColumnFilter &&
|
|
658
|
+
FilterComponent;
|
|
659
|
+
// isHeaderSort: show sort icon (default true)
|
|
660
|
+
const showSort = column.isHeaderSort !== false && column.sort;
|
|
661
|
+
return (_jsxs("div", { style: {
|
|
662
|
+
display: 'flex',
|
|
663
|
+
flexDirection: 'column',
|
|
664
|
+
gap: 4,
|
|
665
|
+
width: '100%',
|
|
666
|
+
}, children: [showTitle && (_jsx("span", { style: {
|
|
667
|
+
color: 'white',
|
|
668
|
+
fontWeight: 600,
|
|
669
|
+
fontSize: 12,
|
|
670
|
+
whiteSpace: 'nowrap',
|
|
671
|
+
cursor: showSort ? 'pointer' : 'default',
|
|
672
|
+
}, onClick: () => showSort && handleSortClick(column), children: column.headerFormatter
|
|
673
|
+
? column.headerFormatter(column, colIndex)
|
|
674
|
+
: column.headerText || column.text })), (showFilter || showSort) && (_jsxs("div", { style: {
|
|
675
|
+
display: 'flex',
|
|
676
|
+
alignItems: 'center',
|
|
677
|
+
justifyContent: 'center',
|
|
678
|
+
gap: 6,
|
|
679
|
+
width: '100%',
|
|
680
|
+
minHeight: 24,
|
|
681
|
+
}, children: [showFilter && (_jsx("div", { style: {
|
|
682
|
+
width: showSort ? '80%' : '100%',
|
|
683
|
+
minWidth: 0,
|
|
684
|
+
flexShrink: 1,
|
|
685
|
+
display: 'flex',
|
|
686
|
+
alignItems: 'center',
|
|
687
|
+
}, onClick: (e) => e.stopPropagation(), children: column.filterRenderer ? (column.filterRenderer(onFilter, column)) : (_jsx(FilterComponent, { column: column, value: filters[column.dataField], onChange: onFilter, onClear: () => handleFilterChange(column.dataField, null) })) })), showSort && (_jsx("div", { style: {
|
|
688
|
+
width: showFilter ? '20%' : '100%',
|
|
689
|
+
minWidth: 24,
|
|
690
|
+
height: 24,
|
|
691
|
+
display: 'flex',
|
|
692
|
+
alignItems: 'center',
|
|
693
|
+
justifyContent: 'center',
|
|
694
|
+
flexShrink: 0,
|
|
695
|
+
cursor: 'pointer',
|
|
696
|
+
}, onClick: () => handleSortClick(column), children: column.sortCaret ? (column.sortCaret(sort.field === column.dataField
|
|
697
|
+
? sort.order
|
|
698
|
+
: null, column)) : (_jsx(DefaultSortCaret, { order: sort.field === column.dataField
|
|
699
|
+
? sort.order
|
|
700
|
+
: null, column: column })) }))] }))] }));
|
|
701
|
+
})() }, column.dataField));
|
|
702
|
+
}), resolvedShowActionColumn && (_jsx(HeaderCell, { "$align": "center", "$sortable": false, "$compact": compact, "$width": actionColumnWidth, children: "Actions" }))] }) }), _jsx(TableBody, { className: classNames.body, style: styles.body, children: processedData.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: visibleColumns.length +
|
|
310
703
|
(rowSelection?.mode === 'checkbox' ? 1 : 0) +
|
|
311
|
-
(expandable ? 1 : 0)
|
|
704
|
+
(expandable ? 1 : 0) +
|
|
705
|
+
(showRowNumber ? 1 : 0) +
|
|
706
|
+
(resolvedShowActionColumn ? 1 : 0), children: _jsxs(EmptyState, { className: classNames.empty, style: styles.empty, children: [_jsx(EmptyIcon, {}), _jsx("span", { children: emptyText })] }) }) })) : (processedData.map((row, rowIndex) => {
|
|
312
707
|
const rowKey = getRowKey(row);
|
|
313
708
|
const rowSelected = isSelected(rowKey);
|
|
314
709
|
const rowExpanded = isExpanded(rowKey);
|
|
@@ -328,30 +723,99 @@ export const Table = forwardRef(function TableComponent(props, ref) {
|
|
|
328
723
|
return (_jsxs(React.Fragment, { children: [_jsxs(TableRow, { "$selected": rowSelected, "$clickable": !!onRowClick ||
|
|
329
724
|
rowSelection?.mode === 'single' ||
|
|
330
725
|
expandable?.expandRowByClick === true, "$disabled": !!checkboxProps?.disabled, className: `${classNames.row || ''} ${rowClass || ''} ${rowSelected
|
|
331
|
-
? typeof rowSelection?.selectedRowClassName ===
|
|
726
|
+
? typeof rowSelection?.selectedRowClassName ===
|
|
727
|
+
'function'
|
|
332
728
|
? rowSelection.selectedRowClassName(row)
|
|
333
729
|
: rowSelection?.selectedRowClassName || ''
|
|
334
|
-
: ''}`, style: { ...styles.row, ...rowStyles, ...selectedStyle }, onClick: (e) => handleRowClick(row, rowIndex, e), onDoubleClick: (e) => handleCellDoubleClick(row, rowIndex, visibleColumns[0], e), role: "row", "aria-selected": rowSelected, children: [rowSelection?.mode === 'checkbox' && (_jsx(TableCell, { "$align": "center", "$compact": compact, children: _jsx(Checkbox, { checked: rowSelected, disabled: checkboxProps?.disabled, onChange: (e) => handleCheckboxChange(row, e), onClick: (e) => e.stopPropagation() }) })), expandable && (_jsx(TableCell, { "$align": "center", "$compact": compact, children: isExpandable && (_jsx(ExpandButton, { "$expanded": rowExpanded, onClick: (e) => handleExpandClick(row, e), children: expandable.expandIcon ? (expandable.expandIcon({
|
|
730
|
+
: ''}`, style: { ...styles.row, ...rowStyles, ...selectedStyle }, onClick: (e) => handleRowClick(row, rowIndex, e), onDoubleClick: (e) => handleCellDoubleClick(row, rowIndex, visibleColumns[0], 0, e), role: "row", "aria-selected": rowSelected, children: [rowSelection?.mode === 'checkbox' && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, children: _jsx(Checkbox, { checked: rowSelected, disabled: checkboxProps?.disabled, onChange: (e) => handleCheckboxChange(row, e), onClick: (e) => e.stopPropagation() }) })), expandable && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, children: isExpandable && (_jsx(ExpandButton, { "$expanded": rowExpanded, onClick: (e) => handleExpandClick(row, e), children: expandable.expandIcon ? (expandable.expandIcon({
|
|
335
731
|
expanded: rowExpanded,
|
|
336
732
|
row,
|
|
337
733
|
onExpand: () => toggleExpand(row),
|
|
338
|
-
})) : (_jsx(ExpandIcon, {})) })) })),
|
|
734
|
+
})) : (_jsx(ExpandIcon, {})) })) })), showRowNumber && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, style: {
|
|
735
|
+
width: rowNumberWidth,
|
|
736
|
+
color: '#6b7280',
|
|
737
|
+
fontWeight: 500,
|
|
738
|
+
}, children: rowNumberRender
|
|
739
|
+
? rowNumberRender(rowIndex + 1, row)
|
|
740
|
+
: rowIndex + 1 + page * pageSize })), visibleColumns.map((column, colIndex) => {
|
|
339
741
|
const cellClass = typeof column.classes === 'function'
|
|
340
|
-
? column.classes(getNestedValue(row, column.dataField), row, rowIndex)
|
|
742
|
+
? column.classes(getNestedValue(row, column.dataField), row, rowIndex, colIndex)
|
|
341
743
|
: column.classes;
|
|
342
744
|
const cellStyle = typeof column.style === 'function'
|
|
343
|
-
? column.style(getNestedValue(row, column.dataField), row, rowIndex)
|
|
745
|
+
? column.style(getNestedValue(row, column.dataField), row, rowIndex, colIndex)
|
|
344
746
|
: column.style;
|
|
345
|
-
return (_jsx(TableCell, { "$align": column.align || 'left', "$compact": compact, "$pinned": column.pinned, className: cellClass || classNames.cell, style: { ...styles.cell, ...cellStyle }, onClick: () => handleCellClick(row, rowIndex, column), onDoubleClick: (e) => handleCellDoubleClick(row, rowIndex, column, e), role: "gridcell", children:
|
|
346
|
-
|
|
347
|
-
|
|
747
|
+
return (_jsx(TableCell, { "$align": column.align || 'left', "$compact": compact, "$padding": cellPadding, "$pinned": column.pinned, className: cellClass || classNames.cell, style: { ...styles.cell, ...cellStyle }, onClick: () => handleCellClick(row, rowIndex, column, colIndex), onDoubleClick: (e) => handleCellDoubleClick(row, rowIndex, column, colIndex, e), role: "gridcell", children: (() => {
|
|
748
|
+
const editInfo = getCellEditableInfo(column, row, rowIndex, colIndex);
|
|
749
|
+
if (editInfo.isEditable &&
|
|
750
|
+
editMode !== 'none') {
|
|
751
|
+
// Check for custom editor
|
|
752
|
+
if (editInfo.customEditor) {
|
|
753
|
+
return editInfo.customEditor;
|
|
754
|
+
}
|
|
755
|
+
return (_jsx(EditableCell, { "$editing": editingCell?.row === rowIndex &&
|
|
756
|
+
editingCell?.field === column.dataField, children: renderCellContent(row, column, rowIndex, colIndex) }));
|
|
757
|
+
}
|
|
758
|
+
return renderCellContent(row, column, rowIndex, colIndex);
|
|
759
|
+
})() }, column.dataField));
|
|
760
|
+
}), resolvedShowActionColumn && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, style: {
|
|
761
|
+
width: actionColumnWidth,
|
|
762
|
+
whiteSpace: 'nowrap',
|
|
763
|
+
}, children: actionColumnRender ? (actionColumnRender(row, rowIndex)) : (_jsxs("div", { style: {
|
|
764
|
+
display: 'flex',
|
|
765
|
+
gap: '4px',
|
|
766
|
+
justifyContent: 'center',
|
|
767
|
+
}, children: [resolvedIsView && (_jsx("button", { onClick: (e) => {
|
|
768
|
+
e.stopPropagation();
|
|
769
|
+
onView?.(row, rowIndex);
|
|
770
|
+
}, style: {
|
|
771
|
+
padding: '4px 8px',
|
|
772
|
+
background: '#10b981',
|
|
773
|
+
color: 'white',
|
|
774
|
+
border: 'none',
|
|
775
|
+
borderRadius: '4px',
|
|
776
|
+
cursor: 'pointer',
|
|
777
|
+
display: 'flex',
|
|
778
|
+
alignItems: 'center',
|
|
779
|
+
gap: '4px',
|
|
780
|
+
fontSize: '12px',
|
|
781
|
+
}, title: "View", children: _jsx(ViewIcon, {}) })), resolvedIsEdit && (_jsx("button", { onClick: (e) => {
|
|
782
|
+
e.stopPropagation();
|
|
783
|
+
onEdit?.(row, rowIndex);
|
|
784
|
+
}, style: {
|
|
785
|
+
padding: '4px 8px',
|
|
786
|
+
background: '#3b82f6',
|
|
787
|
+
color: 'white',
|
|
788
|
+
border: 'none',
|
|
789
|
+
borderRadius: '4px',
|
|
790
|
+
cursor: 'pointer',
|
|
791
|
+
display: 'flex',
|
|
792
|
+
alignItems: 'center',
|
|
793
|
+
gap: '4px',
|
|
794
|
+
fontSize: '12px',
|
|
795
|
+
}, title: "Edit", children: _jsx(EditIcon, {}) })), isDelete && (_jsx("button", { onClick: (e) => {
|
|
796
|
+
e.stopPropagation();
|
|
797
|
+
onDelete?.(row, rowIndex);
|
|
798
|
+
}, style: {
|
|
799
|
+
padding: '4px 8px',
|
|
800
|
+
background: '#ef4444',
|
|
801
|
+
color: 'white',
|
|
802
|
+
border: 'none',
|
|
803
|
+
borderRadius: '4px',
|
|
804
|
+
cursor: 'pointer',
|
|
805
|
+
display: 'flex',
|
|
806
|
+
alignItems: 'center',
|
|
807
|
+
gap: '4px',
|
|
808
|
+
fontSize: '12px',
|
|
809
|
+
}, title: "Delete", children: _jsx(DeleteIcon, {}) }))] })) }))] }), expandable && rowExpanded && isExpandable && (_jsx(ExpandedRow, { children: _jsx(ExpandedCell, { colSpan: visibleColumns.length +
|
|
348
810
|
(rowSelection?.mode === 'checkbox' ? 1 : 0) +
|
|
349
|
-
|
|
350
|
-
|
|
811
|
+
(expandable ? 1 : 0) +
|
|
812
|
+
(showRowNumber ? 1 : 0) +
|
|
813
|
+
(resolvedShowActionColumn ? 1 : 0), children: expandable.expandedRowRender?.(row, rowIndex, rowExpanded) }) }))] }, rowKey));
|
|
814
|
+
})) }), showFooter && (_jsx(TableFooter, { className: classNames.footer, style: styles.footer, children: _jsxs(FooterRow, { className: classNames.footerRow, style: styles.footerRow, children: [rowSelection?.mode === 'checkbox' && (_jsx(FooterCell, { "$align": "center", "$compact": compact })), expandable && (_jsx(FooterCell, { "$align": "center", "$compact": compact })), showRowNumber && (_jsx(FooterCell, { "$align": "center", "$compact": compact })), visibleColumns.map((column) => (_jsx(FooterCell, { "$align": column.align || 'left', "$compact": compact, className: classNames.footerCell, style: styles.footerCell, children: typeof column.footer === 'function'
|
|
351
815
|
? column.footer(column, data)
|
|
352
816
|
: column.footerFormatter
|
|
353
817
|
? column.footerFormatter(column, data)
|
|
354
|
-
: column.footer }, column.dataField)))] }) }))] }) }), renderPagination()] }));
|
|
818
|
+
: column.footer }, column.dataField))), resolvedShowActionColumn && (_jsx(FooterCell, { "$align": "center", "$compact": compact }))] }) }))] }) }), renderPagination()] }));
|
|
355
819
|
});
|
|
356
820
|
Table.displayName = 'Table';
|
|
357
821
|
export default Table;
|