@ackplus/react-tanstack-data-table 1.1.17 → 1.1.19
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/dist/lib/components/toolbar/column-filter-control.d.ts +3 -2
- package/dist/lib/components/toolbar/column-filter-control.d.ts.map +1 -1
- package/dist/lib/components/toolbar/column-filter-control.js +91 -92
- package/dist/lib/components/toolbar/table-refresh-control.d.ts.map +1 -1
- package/dist/lib/components/toolbar/table-refresh-control.js +3 -1
- package/dist/lib/features/column-filter.feature.d.ts +2 -1
- package/dist/lib/features/column-filter.feature.d.ts.map +1 -1
- package/dist/lib/features/column-filter.feature.js +14 -0
- package/dist/lib/hooks/use-data-table-engine.d.ts.map +1 -1
- package/dist/lib/hooks/use-data-table-engine.js +278 -14
- package/package.json +1 -1
- package/src/lib/components/toolbar/column-filter-control.tsx +270 -212
- package/src/lib/components/toolbar/table-refresh-control.tsx +11 -7
- package/src/lib/features/column-filter.feature.ts +15 -1
- package/src/lib/hooks/use-data-table-engine.ts +248 -14
|
@@ -44,15 +44,19 @@ export function TableRefreshControl(props: TableRefreshControlProps = {}): React
|
|
|
44
44
|
props.iconButtonProps || {}
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
+
// Wrap in span so when IconButton is disabled (loading), the tooltip still
|
|
48
|
+
// receives pointer events and closes on mouse leave (disabled elements don't fire them).
|
|
47
49
|
return (
|
|
48
50
|
<Tooltip title="Refresh data" {...props.tooltipProps}>
|
|
49
|
-
<
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
<span style={{ display: 'inline-flex' }}>
|
|
52
|
+
<IconButton {...mergedIconButtonProps}>
|
|
53
|
+
{props.loading && props.showSpinnerWhileLoading ? (
|
|
54
|
+
<CircularProgress size={16} />
|
|
55
|
+
) : (
|
|
56
|
+
<RefreshIconSlot {...refreshIconSlotProps} />
|
|
57
|
+
)}
|
|
58
|
+
</IconButton>
|
|
59
|
+
</span>
|
|
56
60
|
</Tooltip>
|
|
57
61
|
);
|
|
58
62
|
}
|
|
@@ -49,7 +49,7 @@ declare module '@tanstack/react-table' {
|
|
|
49
49
|
}
|
|
50
50
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
51
|
interface Table<TData extends RowData> {
|
|
52
|
-
setColumnFilterState: (updater: Updater<ColumnFilterState>) => void;
|
|
52
|
+
setColumnFilterState: (updater: Updater<ColumnFilterState> | ColumnFilterState) => void;
|
|
53
53
|
|
|
54
54
|
// Pending filter methods (for draft state)
|
|
55
55
|
addPendingColumnFilter: (columnId: string, operator: string, value: any) => void;
|
|
@@ -60,6 +60,7 @@ declare module '@tanstack/react-table' {
|
|
|
60
60
|
|
|
61
61
|
// Apply pending filters to active filters
|
|
62
62
|
applyPendingColumnFilters: () => void;
|
|
63
|
+
resetColumnFilter: () => void;
|
|
63
64
|
|
|
64
65
|
// Legacy methods (for backward compatibility)
|
|
65
66
|
addColumnFilter: (columnId: string, operator: string, value: any) => void;
|
|
@@ -187,6 +188,19 @@ export const ColumnFilterFeature: TableFeature<any> = {
|
|
|
187
188
|
}));
|
|
188
189
|
};
|
|
189
190
|
|
|
191
|
+
table.resetColumnFilter = () => {
|
|
192
|
+
if (!table.options.enableAdvanceColumnFilter) return;
|
|
193
|
+
const newState: ColumnFilterState = {
|
|
194
|
+
pendingFilters: [],
|
|
195
|
+
pendingLogic: 'AND',
|
|
196
|
+
filters: [],
|
|
197
|
+
logic: 'AND',
|
|
198
|
+
};
|
|
199
|
+
table.setColumnFilterState(newState);
|
|
200
|
+
// Notify engine so it can reset pagination and refetch (server mode)
|
|
201
|
+
table.options.onColumnFilterApply?.(newState);
|
|
202
|
+
};
|
|
203
|
+
|
|
190
204
|
table.setPendingFilterLogic = (logic: 'AND' | 'OR') => {
|
|
191
205
|
if (!table.options.enableAdvanceColumnFilter) return;
|
|
192
206
|
table.setColumnFilterState((old) => ({
|
|
@@ -628,7 +628,10 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
628
628
|
const delay = nextFetchDelayRef.current ?? 0;
|
|
629
629
|
nextFetchDelayRef.current = 0; // reset after using
|
|
630
630
|
|
|
631
|
-
|
|
631
|
+
const timeoutId = setTimeout(() => {
|
|
632
|
+
void fetchData({}, { delay, meta: { reason: "stateChange" } });
|
|
633
|
+
}, 0);
|
|
634
|
+
return () => clearTimeout(timeoutId);
|
|
632
635
|
}, [serverKey, fetchData]);
|
|
633
636
|
|
|
634
637
|
// columnFilter apply handler stays explicit (button), but you can also auto-fetch on change if needed
|
|
@@ -862,22 +865,155 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
862
865
|
};
|
|
863
866
|
|
|
864
867
|
// --- data
|
|
868
|
+
const getBaseData = () => {
|
|
869
|
+
const sData = serverDataRef.current;
|
|
870
|
+
return sData !== null ? sData : dataRef.current;
|
|
871
|
+
};
|
|
872
|
+
const getRowIndexById = (arr: T[], rowId: string) =>
|
|
873
|
+
arr.findIndex((row, i) => generateRowId(row, i, idKey) === rowId);
|
|
865
874
|
api.data = {
|
|
866
875
|
refresh: (options?: boolean | DataRefreshOptions) => void triggerRefresh(options, "refresh"),
|
|
867
876
|
reload: (options: DataRefreshOptions = {}) => void triggerRefresh({ ...options, reason: options.reason ?? "reload" }, "reload"),
|
|
868
877
|
resetAll: () => resetAllAndReload(),
|
|
878
|
+
getAllData: () => [...getBaseData()],
|
|
879
|
+
getRowData: (rowId: string) => {
|
|
880
|
+
const rows = tableRef.current.getRowModel().rows;
|
|
881
|
+
const row = rows.find((r: any) => r.id === rowId);
|
|
882
|
+
return row?.original as T | undefined;
|
|
883
|
+
},
|
|
884
|
+
getRowByIndex: (index: number) => tableRef.current.getRowModel().rows[index]?.original as T | undefined,
|
|
885
|
+
getDataCount: () => getBaseData().length,
|
|
886
|
+
getFilteredDataCount: () => tableRef.current.getFilteredRowModel().rows.length,
|
|
887
|
+
updateRow: (rowId: string, updates: Partial<T>) => {
|
|
888
|
+
const base = getBaseData();
|
|
889
|
+
const idx = getRowIndexById(base, rowId);
|
|
890
|
+
if (idx === -1) return;
|
|
891
|
+
const next = [...base];
|
|
892
|
+
next[idx] = { ...next[idx], ...updates } as T;
|
|
893
|
+
setServerData(next);
|
|
894
|
+
setServerTotal(next.length);
|
|
895
|
+
},
|
|
896
|
+
updateRowByIndex: (index: number, updates: Partial<T>) => {
|
|
897
|
+
const base = getBaseData();
|
|
898
|
+
if (index < 0 || index >= base.length) return;
|
|
899
|
+
const next = [...base];
|
|
900
|
+
next[index] = { ...next[index], ...updates } as T;
|
|
901
|
+
setServerData(next);
|
|
902
|
+
setServerTotal(next.length);
|
|
903
|
+
},
|
|
904
|
+
insertRow: (newRow: T, index?: number) => {
|
|
905
|
+
const base = getBaseData();
|
|
906
|
+
const next = index == null ? [...base, newRow] : [...base.slice(0, index), newRow, ...base.slice(index)];
|
|
907
|
+
setServerData(next);
|
|
908
|
+
setServerTotal(next.length);
|
|
909
|
+
},
|
|
910
|
+
deleteRow: (rowId: string) => {
|
|
911
|
+
const base = getBaseData();
|
|
912
|
+
const idx = getRowIndexById(base, rowId);
|
|
913
|
+
if (idx === -1) return;
|
|
914
|
+
const next = base.filter((_, i) => i !== idx);
|
|
915
|
+
setServerData(next);
|
|
916
|
+
setServerTotal(next.length);
|
|
917
|
+
},
|
|
918
|
+
deleteRowByIndex: (index: number) => {
|
|
919
|
+
const base = getBaseData();
|
|
920
|
+
if (index < 0 || index >= base.length) return;
|
|
921
|
+
const next = base.filter((_, i) => i !== index);
|
|
922
|
+
setServerData(next);
|
|
923
|
+
setServerTotal(next.length);
|
|
924
|
+
},
|
|
925
|
+
deleteSelectedRows: () => {
|
|
926
|
+
const state = tableRef.current.getSelectionState?.();
|
|
927
|
+
if (!state || state.type !== "include" || !state.ids.length) return;
|
|
928
|
+
const base = getBaseData();
|
|
929
|
+
const ids = new Set(state.ids);
|
|
930
|
+
const next = base.filter((row, i) => !ids.has(generateRowId(row, i, idKey)));
|
|
931
|
+
setServerData(next);
|
|
932
|
+
setServerTotal(next.length);
|
|
933
|
+
tableRef.current.deselectAll?.();
|
|
934
|
+
},
|
|
935
|
+
replaceAllData: (newData: T[]) => {
|
|
936
|
+
setServerData(newData);
|
|
937
|
+
setServerTotal(newData.length);
|
|
938
|
+
},
|
|
939
|
+
updateMultipleRows: (updates: Array<{ rowId: string; data: Partial<T> }>) => {
|
|
940
|
+
const base = getBaseData();
|
|
941
|
+
const next = [...base];
|
|
942
|
+
for (const { rowId, data: u } of updates) {
|
|
943
|
+
const idx = getRowIndexById(next, rowId);
|
|
944
|
+
if (idx !== -1) next[idx] = { ...next[idx], ...u } as T;
|
|
945
|
+
}
|
|
946
|
+
setServerData(next);
|
|
947
|
+
setServerTotal(next.length);
|
|
948
|
+
},
|
|
949
|
+
insertMultipleRows: (newRows: T[], startIndex?: number) => {
|
|
950
|
+
const base = getBaseData();
|
|
951
|
+
const idx = startIndex ?? base.length;
|
|
952
|
+
const next = [...base.slice(0, idx), ...newRows, ...base.slice(idx)];
|
|
953
|
+
setServerData(next);
|
|
954
|
+
setServerTotal(next.length);
|
|
955
|
+
},
|
|
956
|
+
deleteMultipleRows: (rowIds: string[]) => {
|
|
957
|
+
const ids = new Set(rowIds);
|
|
958
|
+
const base = getBaseData();
|
|
959
|
+
const next = base.filter((row, i) => !ids.has(generateRowId(row, i, idKey)));
|
|
960
|
+
setServerData(next);
|
|
961
|
+
setServerTotal(next.length);
|
|
962
|
+
},
|
|
963
|
+
updateField: (rowId: string, fieldName: keyof T, value: any) => {
|
|
964
|
+
api.data.updateRow(rowId, { [fieldName]: value } as Partial<T>);
|
|
965
|
+
},
|
|
966
|
+
updateFieldByIndex: (index: number, fieldName: keyof T, value: any) => {
|
|
967
|
+
api.data.updateRowByIndex(index, { [fieldName]: value } as Partial<T>);
|
|
968
|
+
},
|
|
969
|
+
findRows: (predicate: (row: T) => boolean) => getBaseData().filter(predicate),
|
|
970
|
+
findRowIndex: (predicate: (row: T) => boolean) => getBaseData().findIndex(predicate),
|
|
971
|
+
} as any;
|
|
869
972
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
973
|
+
// --- layout (save/restore column visibility, order, sizing, pinning)
|
|
974
|
+
api.layout = {
|
|
975
|
+
saveLayout: () => {
|
|
976
|
+
const s = tableRef.current.getState();
|
|
977
|
+
return {
|
|
978
|
+
columnVisibility: s.columnVisibility ?? {},
|
|
979
|
+
columnOrder: s.columnOrder ?? [],
|
|
980
|
+
columnSizing: s.columnSizing ?? {},
|
|
981
|
+
columnPinning: s.columnPinning ?? { left: [], right: [] },
|
|
982
|
+
pagination: s.pagination ?? { pageIndex: 0, pageSize: 10 },
|
|
983
|
+
globalFilter: s.globalFilter ?? "",
|
|
984
|
+
columnFilter: s.columnFilter ?? [],
|
|
985
|
+
};
|
|
874
986
|
},
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
987
|
+
restoreLayout: (layout: any) => {
|
|
988
|
+
|
|
989
|
+
if (layout.columnVisibility) dispatch({ type: "SET_COLUMN_VISIBILITY", payload: layout.columnVisibility });
|
|
990
|
+
if (layout.columnOrder) { dispatch({ type: "SET_COLUMN_ORDER", payload: layout.columnOrder }); onColumnDragEndRef.current?.(layout.columnOrder); }
|
|
991
|
+
if (layout.columnSizing) { dispatch({ type: "SET_COLUMN_SIZING", payload: layout.columnSizing }); onColumnSizingChangeRef.current?.(layout.columnSizing); }
|
|
992
|
+
if (layout.columnPinning) { dispatch({ type: "SET_COLUMN_PINNING", payload: layout.columnPinning }); onColumnPinningChangeRef.current?.(layout.columnPinning); }
|
|
993
|
+
if (layout.pagination && enablePagination) dispatch({ type: "SET_PAGINATION", payload: layout.pagination as any });
|
|
994
|
+
if (layout.globalFilter !== undefined) dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: layout.globalFilter });
|
|
995
|
+
if (layout.columnFilter) dispatch({ type: "SET_COLUMN_FILTER", payload: layout.columnFilter as any });
|
|
996
|
+
},
|
|
997
|
+
resetLayout: () => {
|
|
998
|
+
const vis = initialStateConfig.columnVisibility || {};
|
|
999
|
+
const order = initialStateConfig.columnOrder || [];
|
|
1000
|
+
const sizing = initialStateConfig.columnSizing || {};
|
|
1001
|
+
const pinning = initialStateConfig.columnPinning || { left: [] as string[], right: [] as string[] };
|
|
1002
|
+
dispatch({ type: "SET_COLUMN_VISIBILITY", payload: vis });
|
|
1003
|
+
dispatch({ type: "SET_COLUMN_ORDER", payload: order });
|
|
1004
|
+
dispatch({ type: "SET_COLUMN_SIZING", payload: sizing });
|
|
1005
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: pinning });
|
|
1006
|
+
dispatch({ type: "SET_PAGINATION", payload: { pageIndex: 0, pageSize: 10 } });
|
|
1007
|
+
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: "" });
|
|
1008
|
+
dispatch({ type: "SET_COLUMN_FILTER", payload: [] });
|
|
1009
|
+
onColumnDragEndRef.current?.(order);
|
|
1010
|
+
onColumnSizingChangeRef.current?.(sizing);
|
|
1011
|
+
onColumnPinningChangeRef.current?.(pinning);
|
|
1012
|
+
},
|
|
1013
|
+
resetAll: () => {
|
|
1014
|
+
api.layout.resetLayout();
|
|
1015
|
+
resetAllAndReload();
|
|
879
1016
|
},
|
|
880
|
-
getFilteredDataCount: () => tableRef.current.getFilteredRowModel().rows.length,
|
|
881
1017
|
} as any;
|
|
882
1018
|
|
|
883
1019
|
// --- sorting/pagination/filtering - dispatch + callbacks + server fetch policies
|
|
@@ -888,6 +1024,12 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
888
1024
|
nextFetchDelayRef.current = 0;
|
|
889
1025
|
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: cleaned });
|
|
890
1026
|
},
|
|
1027
|
+
sortColumn: (columnId: string, direction: 'asc' | 'desc' | false) => {
|
|
1028
|
+
const next: SortingState = direction === false ? [] : [{ id: columnId, desc: direction === 'desc' }];
|
|
1029
|
+
onSortingChangeRef.current?.(next);
|
|
1030
|
+
nextFetchDelayRef.current = 0;
|
|
1031
|
+
dispatch({ type: "SET_SORTING_RESET_PAGE", payload: next });
|
|
1032
|
+
},
|
|
891
1033
|
clearSorting: () => {
|
|
892
1034
|
onSortingChangeRef.current?.([]);
|
|
893
1035
|
nextFetchDelayRef.current = 0;
|
|
@@ -909,12 +1051,25 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
909
1051
|
nextFetchDelayRef.current = 0;
|
|
910
1052
|
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
911
1053
|
},
|
|
1054
|
+
nextPage: () => {
|
|
1055
|
+
const prev = uiRef.current.pagination;
|
|
1056
|
+
api.pagination.goToPage(Math.min(prev.pageIndex + 1, Math.max(0, Math.ceil((tableTotalRow ?? 0) / prev.pageSize) - 1)));
|
|
1057
|
+
},
|
|
1058
|
+
previousPage: () => {
|
|
1059
|
+
const prev = uiRef.current.pagination;
|
|
1060
|
+
api.pagination.goToPage(Math.max(0, prev.pageIndex - 1));
|
|
1061
|
+
},
|
|
912
1062
|
setPageSize: (pageSize: number) => {
|
|
913
1063
|
const next = { pageIndex: 0, pageSize };
|
|
914
1064
|
onPaginationChangeRef.current?.(next);
|
|
915
1065
|
nextFetchDelayRef.current = 0;
|
|
916
1066
|
dispatch({ type: "SET_PAGINATION", payload: next });
|
|
917
1067
|
},
|
|
1068
|
+
goToFirstPage: () => api.pagination.goToPage(0),
|
|
1069
|
+
goToLastPage: () => {
|
|
1070
|
+
const prev = uiRef.current.pagination;
|
|
1071
|
+
api.pagination.goToPage(Math.max(0, Math.ceil((tableTotalRow ?? 0) / prev.pageSize) - 1));
|
|
1072
|
+
},
|
|
918
1073
|
resetPagination: () => {
|
|
919
1074
|
const next = (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 }) as any;
|
|
920
1075
|
onPaginationChangeRef.current?.(next);
|
|
@@ -935,11 +1090,24 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
935
1090
|
dispatch({ type: "SET_GLOBAL_FILTER_RESET_PAGE", payload: "" });
|
|
936
1091
|
},
|
|
937
1092
|
setColumnFilters: (filters: ColumnFilterState, isApply = false) => handleColumnFilterChangeHandler(filters, isApply),
|
|
1093
|
+
addColumnFilter: (columnId: string, operator: string, value: any) => tableRef.current.addColumnFilter?.(columnId, operator, value),
|
|
1094
|
+
removeColumnFilter: (filterId: string) => tableRef.current.removeColumnFilter?.(filterId),
|
|
1095
|
+
clearAllFilters: () => tableRef.current.resetColumnFilter?.(),
|
|
1096
|
+
resetFilters: () => {
|
|
1097
|
+
const reset = (initialStateConfig.columnFilter ?? DEFAULT_INITIAL_STATE.columnFilter) as ColumnFilterState;
|
|
1098
|
+
handleColumnFilterChangeHandler(reset, true);
|
|
1099
|
+
},
|
|
938
1100
|
} as any;
|
|
939
1101
|
|
|
940
1102
|
api.columnVisibility = {
|
|
941
1103
|
showColumn: (id: string) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: { ...uiRef.current.columnVisibility, [id]: true } }),
|
|
942
1104
|
hideColumn: (id: string) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: { ...uiRef.current.columnVisibility, [id]: false } }),
|
|
1105
|
+
toggleColumn: (id: string) => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: { ...uiRef.current.columnVisibility, [id]: !uiRef.current.columnVisibility[id] } }),
|
|
1106
|
+
showAllColumns: () => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: {} }),
|
|
1107
|
+
hideAllColumns: () => {
|
|
1108
|
+
const all = tableRef.current.getAllLeafColumns().reduce((acc, col) => ({ ...acc, [col.id]: false }), {} as Record<string, boolean>);
|
|
1109
|
+
dispatch({ type: "SET_COLUMN_VISIBILITY", payload: all });
|
|
1110
|
+
},
|
|
943
1111
|
resetColumnVisibility: () => dispatch({ type: "SET_COLUMN_VISIBILITY", payload: initialStateConfig.columnVisibility || {} }),
|
|
944
1112
|
} as any;
|
|
945
1113
|
|
|
@@ -948,10 +1116,41 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
948
1116
|
dispatch({ type: "SET_COLUMN_ORDER", payload: next });
|
|
949
1117
|
onColumnDragEndRef.current?.(next);
|
|
950
1118
|
},
|
|
1119
|
+
moveColumn: (columnId: string, toIndex: number) => {
|
|
1120
|
+
const order = uiRef.current.columnOrder.length ? uiRef.current.columnOrder : tableRef.current.getAllLeafColumns().map((c: any) => c.id);
|
|
1121
|
+
const from = order.indexOf(columnId);
|
|
1122
|
+
if (from === -1 || toIndex < 0 || toIndex >= order.length) return;
|
|
1123
|
+
const next = [...order];
|
|
1124
|
+
next.splice(from, 1);
|
|
1125
|
+
next.splice(toIndex, 0, columnId);
|
|
1126
|
+
dispatch({ type: "SET_COLUMN_ORDER", payload: next });
|
|
1127
|
+
onColumnDragEndRef.current?.(next);
|
|
1128
|
+
},
|
|
951
1129
|
resetColumnOrder: () => dispatch({ type: "SET_COLUMN_ORDER", payload: initialStateConfig.columnOrder || [] }),
|
|
952
1130
|
} as any;
|
|
953
1131
|
|
|
954
1132
|
api.columnPinning = {
|
|
1133
|
+
pinColumnLeft: (columnId: string) => {
|
|
1134
|
+
const cur = uiRef.current.columnPinning;
|
|
1135
|
+
const left = cur.left.includes(columnId) ? cur.left : [...cur.left.filter((id: string) => id !== columnId), columnId];
|
|
1136
|
+
const right = cur.right.filter((id: string) => id !== columnId);
|
|
1137
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: { left, right } });
|
|
1138
|
+
onColumnPinningChangeRef.current?.({ left, right });
|
|
1139
|
+
},
|
|
1140
|
+
pinColumnRight: (columnId: string) => {
|
|
1141
|
+
const cur = uiRef.current.columnPinning;
|
|
1142
|
+
const left = cur.left.filter((id: string) => id !== columnId);
|
|
1143
|
+
const right = cur.right.includes(columnId) ? cur.right : [...cur.right.filter((id: string) => id !== columnId), columnId];
|
|
1144
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: { left, right } });
|
|
1145
|
+
onColumnPinningChangeRef.current?.({ left, right });
|
|
1146
|
+
},
|
|
1147
|
+
unpinColumn: (columnId: string) => {
|
|
1148
|
+
const cur = uiRef.current.columnPinning;
|
|
1149
|
+
const left = cur.left.filter((id: string) => id !== columnId);
|
|
1150
|
+
const right = cur.right.filter((id: string) => id !== columnId);
|
|
1151
|
+
dispatch({ type: "SET_COLUMN_PINNING", payload: { left, right } });
|
|
1152
|
+
onColumnPinningChangeRef.current?.({ left, right });
|
|
1153
|
+
},
|
|
955
1154
|
setPinning: (next: ColumnPinningState) => {
|
|
956
1155
|
dispatch({ type: "SET_COLUMN_PINNING", payload: next });
|
|
957
1156
|
onColumnPinningChangeRef.current?.(next);
|
|
@@ -960,17 +1159,27 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
960
1159
|
} as any;
|
|
961
1160
|
|
|
962
1161
|
api.columnResizing = {
|
|
1162
|
+
resizeColumn: (columnId: string, width: number) => {
|
|
1163
|
+
const cur = uiRef.current.columnSizing;
|
|
1164
|
+
dispatch({ type: "SET_COLUMN_SIZING", payload: { ...cur, [columnId]: width } });
|
|
1165
|
+
onColumnSizingChangeRef.current?.({ ...cur, [columnId]: width });
|
|
1166
|
+
},
|
|
1167
|
+
autoSizeColumn: (columnId: string) => { void columnId; /* no-op: would require measure; use reset for default */ },
|
|
1168
|
+
autoSizeAllColumns: () => { /* no-op */ },
|
|
963
1169
|
resetColumnSizing: () => dispatch({ type: "SET_COLUMN_SIZING", payload: initialStateConfig.columnSizing || {} }),
|
|
964
1170
|
} as any;
|
|
965
1171
|
|
|
966
1172
|
api.selection = {
|
|
1173
|
+
selectRow: (rowId: string) => tableRef.current.selectRow?.(rowId),
|
|
1174
|
+
deselectRow: (rowId: string) => tableRef.current.deselectRow?.(rowId),
|
|
1175
|
+
toggleRowSelection: (rowId: string) => tableRef.current.toggleRowSelected?.(rowId),
|
|
1176
|
+
selectAll: () => tableRef.current.selectAll?.(),
|
|
1177
|
+
deselectAll: () => tableRef.current.deselectAll?.(),
|
|
1178
|
+
toggleSelectAll: () => tableRef.current.toggleAllRowsSelected?.(),
|
|
967
1179
|
getSelectionState: () => tableRef.current.getSelectionState?.() || ({ ids: [], type: "include" } as const),
|
|
968
1180
|
getSelectedRows: () => tableRef.current.getSelectedRows(),
|
|
969
1181
|
getSelectedCount: () => tableRef.current.getSelectedCount(),
|
|
970
1182
|
isRowSelected: (rowId: string) => tableRef.current.getIsRowSelected(rowId) || false,
|
|
971
|
-
// keep using your table extension methods if you have them:
|
|
972
|
-
selectAll: () => tableRef.current.selectAll?.(),
|
|
973
|
-
deselectAll: () => tableRef.current.deselectAll?.(),
|
|
974
1183
|
} as any;
|
|
975
1184
|
|
|
976
1185
|
// --- export API (use your existing exportClientData/exportServerData)
|
|
@@ -1081,10 +1290,35 @@ export function useDataTableEngine<T extends Record<string, any>>(
|
|
|
1081
1290
|
});
|
|
1082
1291
|
},
|
|
1083
1292
|
|
|
1293
|
+
exportServerData: async (options: { format: 'csv' | 'excel'; filename?: string; fetchData: (filters?: Partial<any>, selection?: SelectionState, signal?: AbortSignal) => Promise<any>; pageSize?: number; includeHeaders?: boolean; chunkSize?: number; strictTotalCheck?: boolean; sanitizeCSV?: boolean }) => {
|
|
1294
|
+
const { format, filename: fn = exportFilename, fetchData: customFetchData, chunkSize: cs = exportChunkSize, strictTotalCheck: st = exportStrictTotalCheck, sanitizeCSV: san = exportSanitizeCSV } = options;
|
|
1295
|
+
await runExportWithPolicy({
|
|
1296
|
+
format,
|
|
1297
|
+
filename: fn,
|
|
1298
|
+
mode: "server",
|
|
1299
|
+
execute: async (controller) => {
|
|
1300
|
+
await exportServerData(tableRef.current, {
|
|
1301
|
+
format,
|
|
1302
|
+
filename: fn,
|
|
1303
|
+
fetchData: customFetchData,
|
|
1304
|
+
currentFilters: { globalFilter: tableRef.current.getState().globalFilter, columnFilter: tableRef.current.getState().columnFilter, sorting: tableRef.current.getState().sorting, pagination: tableRef.current.getState().pagination },
|
|
1305
|
+
selection: tableRef.current.getSelectionState?.(),
|
|
1306
|
+
onProgress: handleExportProgressInternal,
|
|
1307
|
+
onComplete: onExportCompleteRef.current,
|
|
1308
|
+
onError: onExportErrorRef.current,
|
|
1309
|
+
onStateChange: (s: any) => handleExportStateChangeInternal({ ...s, mode: "server", format, filename: fn, queueLength: queuedExportCount } as any),
|
|
1310
|
+
signal: controller.signal,
|
|
1311
|
+
chunkSize: cs,
|
|
1312
|
+
strictTotalCheck: st,
|
|
1313
|
+
sanitizeCSV: san,
|
|
1314
|
+
});
|
|
1315
|
+
},
|
|
1316
|
+
});
|
|
1317
|
+
},
|
|
1084
1318
|
isExporting: () => exportControllerRef.current != null,
|
|
1085
1319
|
cancelExport: () => handleCancelExport(),
|
|
1086
1320
|
} as any;
|
|
1087
|
-
}, [dataMode, exportChunkSize, exportFilename, exportSanitizeCSV, exportStrictTotalCheck, fetchData, handleCancelExport, handleColumnFilterChangeHandler, handleExportProgressInternal, handleExportStateChangeInternal, initialStateConfig, isServerMode, isServerPagination, isServerSorting, resetAllAndReload, resetPageToFirst, runExportWithPolicy, triggerRefresh, queuedExportCount, tableRef, uiRef, serverDataRef, dataRef, onSortingChangeRef, onPaginationChangeRef, onGlobalFilterChangeRef, onColumnDragEndRef, onColumnPinningChangeRef, onServerExportRef, onExportCompleteRef, onExportErrorRef]);
|
|
1321
|
+
}, [dataMode, exportChunkSize, exportFilename, exportSanitizeCSV, exportStrictTotalCheck, fetchData, handleCancelExport, handleColumnFilterChangeHandler, handleExportProgressInternal, handleExportStateChangeInternal, initialStateConfig, isServerMode, isServerPagination, isServerSorting, resetAllAndReload, resetPageToFirst, runExportWithPolicy, triggerRefresh, queuedExportCount, tableTotalRow, idKey, tableRef, uiRef, serverDataRef, dataRef, onSortingChangeRef, onPaginationChangeRef, onGlobalFilterChangeRef, onColumnDragEndRef, onColumnPinningChangeRef, onColumnSizingChangeRef, onServerExportRef, onExportCompleteRef, onExportErrorRef]);
|
|
1088
1322
|
|
|
1089
1323
|
// --- imperative handlers (used by TanStack callbacks above or view)
|
|
1090
1324
|
const handleSortingChange = useCallback(
|