@alaarab/ogrid-react 2.1.14 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +446 -52
- package/dist/types/hooks/useDataGridTableOrchestration.d.ts +5 -0
- package/dist/types/hooks/useOGridDataFetching.d.ts +2 -0
- package/dist/types/hooks/useVirtualScroll.d.ts +14 -4
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types/dataGridTypes.d.ts +8 -0
- package/dist/types/utils/index.d.ts +1 -1
- package/package.json +2 -2
package/dist/esm/index.js
CHANGED
|
@@ -507,23 +507,39 @@ function processClientSideData(data, columns, filters, sortBy, sortDirection) {
|
|
|
507
507
|
const trimmed = val.value.trim();
|
|
508
508
|
if (trimmed) {
|
|
509
509
|
const lower = trimmed.toLowerCase();
|
|
510
|
-
|
|
510
|
+
const textCache = /* @__PURE__ */ new Map();
|
|
511
|
+
for (let j = 0; j < data.length; j++) {
|
|
512
|
+
textCache.set(data[j], String(getCellValue(data[j], col) ?? "").toLowerCase());
|
|
513
|
+
}
|
|
514
|
+
predicates.push((r) => (textCache.get(r) ?? "").includes(lower));
|
|
511
515
|
}
|
|
512
516
|
break;
|
|
513
517
|
}
|
|
514
518
|
case "people": {
|
|
515
519
|
const email = val.value.email.toLowerCase();
|
|
516
|
-
|
|
520
|
+
const peopleCache = /* @__PURE__ */ new Map();
|
|
521
|
+
for (let j = 0; j < data.length; j++) {
|
|
522
|
+
peopleCache.set(data[j], String(getCellValue(data[j], col) ?? "").toLowerCase());
|
|
523
|
+
}
|
|
524
|
+
predicates.push((r) => (peopleCache.get(r) ?? "") === email);
|
|
517
525
|
break;
|
|
518
526
|
}
|
|
519
527
|
case "date": {
|
|
520
528
|
const dv = val.value;
|
|
521
529
|
const fromTs = dv.from ? (/* @__PURE__ */ new Date(dv.from + "T00:00:00")).getTime() : NaN;
|
|
522
530
|
const toTs = dv.to ? (/* @__PURE__ */ new Date(dv.to + "T23:59:59.999")).getTime() : NaN;
|
|
531
|
+
const dateCache = /* @__PURE__ */ new Map();
|
|
532
|
+
for (let j = 0; j < data.length; j++) {
|
|
533
|
+
const cellVal = getCellValue(data[j], col);
|
|
534
|
+
if (cellVal == null) {
|
|
535
|
+
dateCache.set(data[j], NaN);
|
|
536
|
+
} else {
|
|
537
|
+
const t = new Date(String(cellVal)).getTime();
|
|
538
|
+
dateCache.set(data[j], Number.isNaN(t) ? NaN : t);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
523
541
|
predicates.push((r) => {
|
|
524
|
-
const
|
|
525
|
-
if (cellVal == null) return false;
|
|
526
|
-
const cellTs = new Date(String(cellVal)).getTime();
|
|
542
|
+
const cellTs = dateCache.get(r) ?? NaN;
|
|
527
543
|
if (Number.isNaN(cellTs)) return false;
|
|
528
544
|
if (!Number.isNaN(fromTs) && cellTs < fromTs) return false;
|
|
529
545
|
if (!Number.isNaN(toTs) && cellTs > toTs) return false;
|
|
@@ -699,6 +715,285 @@ function calculateDropTarget(params) {
|
|
|
699
715
|
}
|
|
700
716
|
return { targetIndex, indicatorX };
|
|
701
717
|
}
|
|
718
|
+
function computeVisibleColumnRange(scrollLeft, columnWidths, containerWidth, overscan = 2) {
|
|
719
|
+
if (columnWidths.length === 0 || containerWidth <= 0) {
|
|
720
|
+
return { startIndex: 0, endIndex: -1, leftOffset: 0, rightOffset: 0 };
|
|
721
|
+
}
|
|
722
|
+
let cumWidth = 0;
|
|
723
|
+
let rawStart = columnWidths.length;
|
|
724
|
+
let rawEnd = -1;
|
|
725
|
+
for (let i = 0; i < columnWidths.length; i++) {
|
|
726
|
+
const colStart = cumWidth;
|
|
727
|
+
cumWidth += columnWidths[i];
|
|
728
|
+
if (cumWidth > scrollLeft && rawStart === columnWidths.length) {
|
|
729
|
+
rawStart = i;
|
|
730
|
+
}
|
|
731
|
+
if (colStart < scrollLeft + containerWidth) {
|
|
732
|
+
rawEnd = i;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (rawStart > rawEnd) {
|
|
736
|
+
return { startIndex: 0, endIndex: -1, leftOffset: 0, rightOffset: 0 };
|
|
737
|
+
}
|
|
738
|
+
const startIndex = Math.max(0, rawStart - overscan);
|
|
739
|
+
const endIndex = Math.min(columnWidths.length - 1, rawEnd + overscan);
|
|
740
|
+
let leftOffset = 0;
|
|
741
|
+
for (let i = 0; i < startIndex; i++) {
|
|
742
|
+
leftOffset += columnWidths[i];
|
|
743
|
+
}
|
|
744
|
+
let rightOffset = 0;
|
|
745
|
+
for (let i = endIndex + 1; i < columnWidths.length; i++) {
|
|
746
|
+
rightOffset += columnWidths[i];
|
|
747
|
+
}
|
|
748
|
+
return { startIndex, endIndex, leftOffset, rightOffset };
|
|
749
|
+
}
|
|
750
|
+
function partitionColumnsForVirtualization(visibleCols, columnRange, pinnedColumns) {
|
|
751
|
+
const pinnedLeft = [];
|
|
752
|
+
const pinnedRight = [];
|
|
753
|
+
const unpinned = [];
|
|
754
|
+
for (const col of visibleCols) {
|
|
755
|
+
const pin = pinnedColumns?.[col.columnId];
|
|
756
|
+
if (pin === "left") pinnedLeft.push(col);
|
|
757
|
+
else if (pin === "right") pinnedRight.push(col);
|
|
758
|
+
else unpinned.push(col);
|
|
759
|
+
}
|
|
760
|
+
if (!columnRange || columnRange.endIndex < 0) {
|
|
761
|
+
return {
|
|
762
|
+
pinnedLeft,
|
|
763
|
+
virtualizedUnpinned: unpinned,
|
|
764
|
+
pinnedRight,
|
|
765
|
+
leftSpacerWidth: 0,
|
|
766
|
+
rightSpacerWidth: 0
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
const virtualizedUnpinned = unpinned.slice(columnRange.startIndex, columnRange.endIndex + 1);
|
|
770
|
+
return {
|
|
771
|
+
pinnedLeft,
|
|
772
|
+
virtualizedUnpinned,
|
|
773
|
+
pinnedRight,
|
|
774
|
+
leftSpacerWidth: columnRange.leftOffset,
|
|
775
|
+
rightSpacerWidth: columnRange.rightOffset
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function workerBody() {
|
|
779
|
+
const ctx = self;
|
|
780
|
+
ctx.onmessage = (e) => {
|
|
781
|
+
const msg = e.data;
|
|
782
|
+
if (msg.type !== "sort-filter") return;
|
|
783
|
+
const { requestId, values, filters, sort } = msg;
|
|
784
|
+
const rowCount = values.length;
|
|
785
|
+
let indices = [];
|
|
786
|
+
const filterEntries = Object.entries(filters);
|
|
787
|
+
if (filterEntries.length === 0) {
|
|
788
|
+
indices = new Array(rowCount);
|
|
789
|
+
for (let i = 0; i < rowCount; i++) indices[i] = i;
|
|
790
|
+
} else {
|
|
791
|
+
for (let r = 0; r < rowCount; r++) {
|
|
792
|
+
let pass = true;
|
|
793
|
+
for (let f = 0; f < filterEntries.length; f++) {
|
|
794
|
+
const colIdx = Number(filterEntries[f][0]);
|
|
795
|
+
const filter = filterEntries[f][1];
|
|
796
|
+
const cellVal = values[r][colIdx];
|
|
797
|
+
switch (filter.type) {
|
|
798
|
+
case "text": {
|
|
799
|
+
const trimmed = filter.value.trim().toLowerCase();
|
|
800
|
+
if (trimmed && !String(cellVal ?? "").toLowerCase().includes(trimmed)) {
|
|
801
|
+
pass = false;
|
|
802
|
+
}
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
case "multiSelect": {
|
|
806
|
+
if (filter.value.length > 0) {
|
|
807
|
+
const set = new Set(filter.value);
|
|
808
|
+
if (!set.has(String(cellVal ?? ""))) {
|
|
809
|
+
pass = false;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
break;
|
|
813
|
+
}
|
|
814
|
+
case "date": {
|
|
815
|
+
if (cellVal == null) {
|
|
816
|
+
pass = false;
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
const ts = new Date(String(cellVal)).getTime();
|
|
820
|
+
if (isNaN(ts)) {
|
|
821
|
+
pass = false;
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
if (filter.value.from) {
|
|
825
|
+
const fromTs = (/* @__PURE__ */ new Date(filter.value.from + "T00:00:00")).getTime();
|
|
826
|
+
if (ts < fromTs) {
|
|
827
|
+
pass = false;
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (filter.value.to) {
|
|
832
|
+
const toTs = (/* @__PURE__ */ new Date(filter.value.to + "T23:59:59.999")).getTime();
|
|
833
|
+
if (ts > toTs) {
|
|
834
|
+
pass = false;
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (!pass) break;
|
|
842
|
+
}
|
|
843
|
+
if (pass) indices.push(r);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
if (sort) {
|
|
847
|
+
const { columnIndex, direction } = sort;
|
|
848
|
+
const dir = direction === "asc" ? 1 : -1;
|
|
849
|
+
indices.sort((a, b) => {
|
|
850
|
+
const av = values[a][columnIndex];
|
|
851
|
+
const bv = values[b][columnIndex];
|
|
852
|
+
if (av == null && bv == null) return 0;
|
|
853
|
+
if (av == null) return -1 * dir;
|
|
854
|
+
if (bv == null) return 1 * dir;
|
|
855
|
+
if (typeof av === "number" && typeof bv === "number") {
|
|
856
|
+
return av === bv ? 0 : av > bv ? dir : -dir;
|
|
857
|
+
}
|
|
858
|
+
const sa = String(av).toLowerCase();
|
|
859
|
+
const sb = String(bv).toLowerCase();
|
|
860
|
+
return sa === sb ? 0 : sa > sb ? dir : -dir;
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
const response = {
|
|
864
|
+
type: "sort-filter-result",
|
|
865
|
+
requestId,
|
|
866
|
+
indices
|
|
867
|
+
};
|
|
868
|
+
ctx.postMessage(response);
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
var workerInstance = null;
|
|
872
|
+
var requestCounter = 0;
|
|
873
|
+
var pendingRequests = /* @__PURE__ */ new Map();
|
|
874
|
+
function createSortFilterWorker() {
|
|
875
|
+
if (workerInstance) return workerInstance;
|
|
876
|
+
if (typeof Worker === "undefined" || typeof Blob === "undefined" || typeof URL === "undefined") {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
const fnStr = workerBody.toString();
|
|
881
|
+
const blob = new Blob(
|
|
882
|
+
[`(${fnStr})()`],
|
|
883
|
+
{ type: "application/javascript" }
|
|
884
|
+
);
|
|
885
|
+
const url = URL.createObjectURL(blob);
|
|
886
|
+
workerInstance = new Worker(url);
|
|
887
|
+
URL.revokeObjectURL(url);
|
|
888
|
+
workerInstance.onmessage = (e) => {
|
|
889
|
+
const { requestId, indices } = e.data;
|
|
890
|
+
const pending = pendingRequests.get(requestId);
|
|
891
|
+
if (pending) {
|
|
892
|
+
pendingRequests.delete(requestId);
|
|
893
|
+
pending.resolve(indices);
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
workerInstance.onerror = (err) => {
|
|
897
|
+
for (const [id, pending] of pendingRequests) {
|
|
898
|
+
pending.reject(new Error(err.message || "Worker error"));
|
|
899
|
+
pendingRequests.delete(id);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
return workerInstance;
|
|
903
|
+
} catch {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function extractValueMatrix(data, columns) {
|
|
908
|
+
const matrix = new Array(data.length);
|
|
909
|
+
for (let r = 0; r < data.length; r++) {
|
|
910
|
+
const row = new Array(columns.length);
|
|
911
|
+
for (let c = 0; c < columns.length; c++) {
|
|
912
|
+
const val = getCellValue(data[r], columns[c]);
|
|
913
|
+
if (val == null) {
|
|
914
|
+
row[c] = null;
|
|
915
|
+
} else if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
|
|
916
|
+
row[c] = val;
|
|
917
|
+
} else {
|
|
918
|
+
row[c] = String(val);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
matrix[r] = row;
|
|
922
|
+
}
|
|
923
|
+
return matrix;
|
|
924
|
+
}
|
|
925
|
+
function processClientSideDataAsync(data, columns, filters, sortBy, sortDirection) {
|
|
926
|
+
if (sortBy) {
|
|
927
|
+
const sortCol = columns.find((c) => c.columnId === sortBy);
|
|
928
|
+
if (sortCol?.compare) {
|
|
929
|
+
return Promise.resolve(processClientSideData(data, columns, filters, sortBy, sortDirection));
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
const worker = createSortFilterWorker();
|
|
933
|
+
if (!worker) {
|
|
934
|
+
return Promise.resolve(processClientSideData(data, columns, filters, sortBy, sortDirection));
|
|
935
|
+
}
|
|
936
|
+
const columnIndexMap = /* @__PURE__ */ new Map();
|
|
937
|
+
for (let i = 0; i < columns.length; i++) {
|
|
938
|
+
columnIndexMap.set(columns[i].columnId, i);
|
|
939
|
+
}
|
|
940
|
+
const values = extractValueMatrix(data, columns);
|
|
941
|
+
const columnMeta = columns.map((col, idx) => ({
|
|
942
|
+
type: col.type ?? "text",
|
|
943
|
+
index: idx
|
|
944
|
+
}));
|
|
945
|
+
const workerFilters = {};
|
|
946
|
+
for (const col of columns) {
|
|
947
|
+
const filterKey = getFilterField(col);
|
|
948
|
+
const val = filters[filterKey];
|
|
949
|
+
if (!val) continue;
|
|
950
|
+
const colIdx = columnIndexMap.get(col.columnId);
|
|
951
|
+
if (colIdx === void 0) continue;
|
|
952
|
+
switch (val.type) {
|
|
953
|
+
case "text":
|
|
954
|
+
workerFilters[colIdx] = { type: "text", value: val.value };
|
|
955
|
+
break;
|
|
956
|
+
case "multiSelect":
|
|
957
|
+
workerFilters[colIdx] = { type: "multiSelect", value: val.value };
|
|
958
|
+
break;
|
|
959
|
+
case "date":
|
|
960
|
+
workerFilters[colIdx] = { type: "date", value: { from: val.value.from, to: val.value.to } };
|
|
961
|
+
break;
|
|
962
|
+
// 'people' filter has a UserLike object — fall back to sync
|
|
963
|
+
case "people":
|
|
964
|
+
return Promise.resolve(processClientSideData(data, columns, filters, sortBy, sortDirection));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
let sort;
|
|
968
|
+
if (sortBy) {
|
|
969
|
+
const sortColIdx = columnIndexMap.get(sortBy);
|
|
970
|
+
if (sortColIdx !== void 0) {
|
|
971
|
+
sort = { columnIndex: sortColIdx, direction: sortDirection ?? "asc" };
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
const requestId = ++requestCounter;
|
|
975
|
+
return new Promise((resolve, reject) => {
|
|
976
|
+
pendingRequests.set(requestId, {
|
|
977
|
+
resolve: (indices) => {
|
|
978
|
+
const result = new Array(indices.length);
|
|
979
|
+
for (let i = 0; i < indices.length; i++) {
|
|
980
|
+
result[i] = data[indices[i]];
|
|
981
|
+
}
|
|
982
|
+
resolve(result);
|
|
983
|
+
},
|
|
984
|
+
reject
|
|
985
|
+
});
|
|
986
|
+
const request = {
|
|
987
|
+
type: "sort-filter",
|
|
988
|
+
requestId,
|
|
989
|
+
values,
|
|
990
|
+
columnMeta,
|
|
991
|
+
filters: workerFilters,
|
|
992
|
+
sort
|
|
993
|
+
};
|
|
994
|
+
worker.postMessage(request);
|
|
995
|
+
});
|
|
996
|
+
}
|
|
702
997
|
function getHeaderFilterConfig(col, input) {
|
|
703
998
|
const filterable = isFilterConfig(col.filterable) ? col.filterable : null;
|
|
704
999
|
const filterType = filterable?.type ?? "none";
|
|
@@ -1220,7 +1515,7 @@ function computeRowSelectionState(selectedIds, items, getRowId) {
|
|
|
1220
1515
|
if (selectedIds.size === 0 || items.length === 0) {
|
|
1221
1516
|
return { allSelected: false, someSelected: false };
|
|
1222
1517
|
}
|
|
1223
|
-
const allSelected = items.every((item) => selectedIds.has(getRowId(item)));
|
|
1518
|
+
const allSelected = selectedIds.size >= items.length && items.every((item) => selectedIds.has(getRowId(item)));
|
|
1224
1519
|
const someSelected = !allSelected && selectedIds.size > 0;
|
|
1225
1520
|
return { allSelected, someSelected };
|
|
1226
1521
|
}
|
|
@@ -1541,7 +1836,7 @@ function useFilterOptions(dataSource, fields) {
|
|
|
1541
1836
|
);
|
|
1542
1837
|
setFilterOptions(results);
|
|
1543
1838
|
setLoadingOptions(EMPTY_LOADING);
|
|
1544
|
-
}, [stableFields]);
|
|
1839
|
+
}, [stableFields, dataSourceRef]);
|
|
1545
1840
|
useEffect(() => {
|
|
1546
1841
|
load().catch(() => {
|
|
1547
1842
|
});
|
|
@@ -1703,11 +1998,13 @@ function useOGridDataFetching(params) {
|
|
|
1703
1998
|
page,
|
|
1704
1999
|
pageSize,
|
|
1705
2000
|
onError,
|
|
1706
|
-
onFirstDataRendered
|
|
2001
|
+
onFirstDataRendered,
|
|
2002
|
+
workerSort
|
|
1707
2003
|
} = params;
|
|
1708
2004
|
const isClientSide = !isServerSide;
|
|
2005
|
+
const useWorker = workerSort === true || workerSort === "auto" && displayData.length > 5e3;
|
|
1709
2006
|
const clientItemsAndTotal = useMemo(() => {
|
|
1710
|
-
if (!isClientSide) return null;
|
|
2007
|
+
if (!isClientSide || useWorker) return null;
|
|
1711
2008
|
const rows = processClientSideData(
|
|
1712
2009
|
displayData,
|
|
1713
2010
|
columns,
|
|
@@ -1719,7 +2016,29 @@ function useOGridDataFetching(params) {
|
|
|
1719
2016
|
const start = (page - 1) * pageSize;
|
|
1720
2017
|
const paged = rows.slice(start, start + pageSize);
|
|
1721
2018
|
return { items: paged, totalCount: total };
|
|
1722
|
-
}, [isClientSide, displayData, columns, stableFilters, sort.field, sort.direction, page, pageSize]);
|
|
2019
|
+
}, [isClientSide, useWorker, displayData, columns, stableFilters, sort.field, sort.direction, page, pageSize]);
|
|
2020
|
+
const [asyncItems, setAsyncItems] = useState(null);
|
|
2021
|
+
const asyncIdRef = useRef(0);
|
|
2022
|
+
useEffect(() => {
|
|
2023
|
+
if (!isClientSide || !useWorker) {
|
|
2024
|
+
setAsyncItems(null);
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
const id = ++asyncIdRef.current;
|
|
2028
|
+
processClientSideDataAsync(
|
|
2029
|
+
displayData,
|
|
2030
|
+
columns,
|
|
2031
|
+
stableFilters,
|
|
2032
|
+
sort.field,
|
|
2033
|
+
sort.direction
|
|
2034
|
+
).then((rows) => {
|
|
2035
|
+
if (id !== asyncIdRef.current) return;
|
|
2036
|
+
const total = rows.length;
|
|
2037
|
+
const start = (page - 1) * pageSize;
|
|
2038
|
+
const paged = rows.slice(start, start + pageSize);
|
|
2039
|
+
setAsyncItems({ items: paged, totalCount: total });
|
|
2040
|
+
});
|
|
2041
|
+
}, [isClientSide, useWorker, displayData, columns, stableFilters, sort.field, sort.direction, page, pageSize]);
|
|
1723
2042
|
const [serverItems, setServerItems] = useState([]);
|
|
1724
2043
|
const [serverTotalCount, setServerTotalCount] = useState(0);
|
|
1725
2044
|
const [serverLoading, setServerLoading] = useState(true);
|
|
@@ -1752,9 +2071,10 @@ function useOGridDataFetching(params) {
|
|
|
1752
2071
|
}).finally(() => {
|
|
1753
2072
|
if (id === fetchIdRef.current) setServerLoading(false);
|
|
1754
2073
|
});
|
|
1755
|
-
}, [isServerSide, page, pageSize, sort.field, sort.direction, stableFilters, refreshCounter]);
|
|
1756
|
-
const
|
|
1757
|
-
const
|
|
2074
|
+
}, [isServerSide, page, pageSize, sort.field, sort.direction, stableFilters, refreshCounter, dataSourceRef, onErrorRef]);
|
|
2075
|
+
const clientResult = clientItemsAndTotal ?? asyncItems;
|
|
2076
|
+
const displayItems = isClientSide && clientResult ? clientResult.items : serverItems;
|
|
2077
|
+
const displayTotalCount = isClientSide && clientResult ? clientResult.totalCount : serverTotalCount;
|
|
1758
2078
|
const onFirstDataRenderedRef = useLatestRef(onFirstDataRendered);
|
|
1759
2079
|
const firstDataRenderedRef = useRef(false);
|
|
1760
2080
|
useEffect(() => {
|
|
@@ -1762,7 +2082,7 @@ function useOGridDataFetching(params) {
|
|
|
1762
2082
|
firstDataRenderedRef.current = true;
|
|
1763
2083
|
onFirstDataRenderedRef.current?.();
|
|
1764
2084
|
}
|
|
1765
|
-
}, [displayItems.length]);
|
|
2085
|
+
}, [displayItems.length, onFirstDataRenderedRef]);
|
|
1766
2086
|
return {
|
|
1767
2087
|
displayItems,
|
|
1768
2088
|
displayTotalCount,
|
|
@@ -1861,34 +2181,35 @@ function useOGrid(props, ref) {
|
|
|
1861
2181
|
virtualScroll,
|
|
1862
2182
|
rowHeight,
|
|
1863
2183
|
density = "normal",
|
|
2184
|
+
workerSort,
|
|
1864
2185
|
"aria-label": ariaLabel,
|
|
1865
2186
|
"aria-labelledby": ariaLabelledBy
|
|
1866
2187
|
} = props;
|
|
1867
2188
|
const getRowIdStableRef = useLatestRef(getRowIdProp);
|
|
1868
2189
|
const getRowId = useCallback((item) => getRowIdStableRef.current(item), [getRowIdStableRef]);
|
|
1869
2190
|
const onColumnOrderChangeRef = useLatestRef(onColumnOrderChangeProp);
|
|
2191
|
+
const hasColumnOrderChange = onColumnOrderChangeProp != null;
|
|
1870
2192
|
const onColumnOrderChange = useMemo(
|
|
1871
|
-
() =>
|
|
1872
|
-
|
|
1873
|
-
[!!onColumnOrderChangeProp]
|
|
2193
|
+
() => hasColumnOrderChange ? (order) => onColumnOrderChangeRef.current?.(order) : void 0,
|
|
2194
|
+
[hasColumnOrderChange, onColumnOrderChangeRef]
|
|
1874
2195
|
);
|
|
1875
2196
|
const onCellValueChangedRef = useLatestRef(onCellValueChangedProp);
|
|
2197
|
+
const hasCellValueChanged = onCellValueChangedProp != null;
|
|
1876
2198
|
const onCellValueChanged = useMemo(
|
|
1877
|
-
() =>
|
|
1878
|
-
|
|
1879
|
-
[!!onCellValueChangedProp]
|
|
2199
|
+
() => hasCellValueChanged ? (event) => onCellValueChangedRef.current?.(event) : void 0,
|
|
2200
|
+
[hasCellValueChanged, onCellValueChangedRef]
|
|
1880
2201
|
);
|
|
1881
2202
|
const onUndoRef = useLatestRef(onUndoProp);
|
|
2203
|
+
const hasUndo = onUndoProp != null;
|
|
1882
2204
|
const onUndo = useMemo(
|
|
1883
|
-
() =>
|
|
1884
|
-
|
|
1885
|
-
[!!onUndoProp]
|
|
2205
|
+
() => hasUndo ? () => onUndoRef.current?.() : void 0,
|
|
2206
|
+
[hasUndo, onUndoRef]
|
|
1886
2207
|
);
|
|
1887
2208
|
const onRedoRef = useLatestRef(onRedoProp);
|
|
2209
|
+
const hasRedo = onRedoProp != null;
|
|
1888
2210
|
const onRedo = useMemo(
|
|
1889
|
-
() =>
|
|
1890
|
-
|
|
1891
|
-
[!!onRedoProp]
|
|
2211
|
+
() => hasRedo ? () => onRedoRef.current?.() : void 0,
|
|
2212
|
+
[hasRedo, onRedoRef]
|
|
1892
2213
|
);
|
|
1893
2214
|
const columnChooserPlacement = columnChooserProp === false ? "none" : columnChooserProp === "sidebar" ? "sidebar" : "toolbar";
|
|
1894
2215
|
const columns = useMemo(() => flattenColumns(columnsProp), [columnsProp]);
|
|
@@ -1896,7 +2217,7 @@ function useOGrid(props, ref) {
|
|
|
1896
2217
|
const rowIdsValidatedRef = useRef(false);
|
|
1897
2218
|
useEffect(() => {
|
|
1898
2219
|
validateColumns(columns);
|
|
1899
|
-
}, []);
|
|
2220
|
+
}, [columns]);
|
|
1900
2221
|
const defaultSortField = defaultSortBy ?? columns[0]?.columnId ?? "";
|
|
1901
2222
|
const [internalData, setInternalData] = useState([]);
|
|
1902
2223
|
const [internalLoading, setInternalLoading] = useState(false);
|
|
@@ -1934,7 +2255,8 @@ function useOGrid(props, ref) {
|
|
|
1934
2255
|
page: paginationState.page,
|
|
1935
2256
|
pageSize: paginationState.pageSize,
|
|
1936
2257
|
onError,
|
|
1937
|
-
onFirstDataRendered
|
|
2258
|
+
onFirstDataRendered,
|
|
2259
|
+
workerSort
|
|
1938
2260
|
});
|
|
1939
2261
|
useEffect(() => {
|
|
1940
2262
|
const items = dataFetchingState.displayItems;
|
|
@@ -1992,7 +2314,13 @@ function useOGrid(props, ref) {
|
|
|
1992
2314
|
[selectedRows, onSelectionChange]
|
|
1993
2315
|
);
|
|
1994
2316
|
const [columnWidthOverrides, setColumnWidthOverrides] = useState({});
|
|
1995
|
-
const [pinnedOverrides, setPinnedOverrides] = useState({
|
|
2317
|
+
const [pinnedOverrides, setPinnedOverrides] = useState(() => {
|
|
2318
|
+
const initial = {};
|
|
2319
|
+
for (const col of flattenColumns(columnsProp)) {
|
|
2320
|
+
if (col.pinned) initial[col.columnId] = col.pinned;
|
|
2321
|
+
}
|
|
2322
|
+
return initial;
|
|
2323
|
+
});
|
|
1996
2324
|
const handleColumnResized = useCallback(
|
|
1997
2325
|
(columnId, width) => {
|
|
1998
2326
|
setColumnWidthOverrides((prev) => ({ ...prev, [columnId]: width }));
|
|
@@ -2518,15 +2846,17 @@ function useCellSelection(params) {
|
|
|
2518
2846
|
}
|
|
2519
2847
|
}
|
|
2520
2848
|
if (!cellIndex) cellIndex = buildCellIndex(wrapperRef.current);
|
|
2849
|
+
let rebuilt = false;
|
|
2521
2850
|
for (let r = minR; r <= maxR; r++) {
|
|
2522
2851
|
for (let c = minC; c <= maxC; c++) {
|
|
2523
2852
|
const key = `${r},${c + colOff}`;
|
|
2524
2853
|
let el = cellIndex?.get(key);
|
|
2525
|
-
if (el && !el.isConnected) {
|
|
2854
|
+
if (el && !el.isConnected && !rebuilt) {
|
|
2855
|
+
rebuilt = true;
|
|
2526
2856
|
cellIndex = buildCellIndex(wrapperRef.current);
|
|
2527
2857
|
el = cellIndex?.get(key);
|
|
2528
2858
|
}
|
|
2529
|
-
if (el) {
|
|
2859
|
+
if (el && el.isConnected) {
|
|
2530
2860
|
styleCellInRange(el, r, c, minR, maxR, minC, maxC, anchor);
|
|
2531
2861
|
}
|
|
2532
2862
|
}
|
|
@@ -2661,10 +2991,13 @@ function useCellSelection(params) {
|
|
|
2661
2991
|
const finalRange = liveDragRangeRef.current;
|
|
2662
2992
|
if (finalRange) {
|
|
2663
2993
|
setSelectionRange(finalRange);
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2994
|
+
const anchor = dragStartRef.current;
|
|
2995
|
+
if (anchor) {
|
|
2996
|
+
setActiveCell({
|
|
2997
|
+
rowIndex: anchor.row,
|
|
2998
|
+
columnIndex: anchor.col + colOffsetRef.current
|
|
2999
|
+
});
|
|
3000
|
+
}
|
|
2668
3001
|
}
|
|
2669
3002
|
}
|
|
2670
3003
|
clearDragAttrs();
|
|
@@ -3129,8 +3462,7 @@ function useUndoRedo(params) {
|
|
|
3129
3462
|
}
|
|
3130
3463
|
onCellValueChangedRef.current(event);
|
|
3131
3464
|
},
|
|
3132
|
-
|
|
3133
|
-
[getStack]
|
|
3465
|
+
[getStack, onCellValueChangedRef]
|
|
3134
3466
|
);
|
|
3135
3467
|
const beginBatch = useCallback(() => {
|
|
3136
3468
|
getStack().beginBatch();
|
|
@@ -3156,7 +3488,7 @@ function useUndoRedo(params) {
|
|
|
3156
3488
|
newValue: ev.oldValue
|
|
3157
3489
|
});
|
|
3158
3490
|
}
|
|
3159
|
-
}, [getStack]);
|
|
3491
|
+
}, [getStack, onCellValueChangedRef]);
|
|
3160
3492
|
const redo = useCallback(() => {
|
|
3161
3493
|
if (!onCellValueChangedRef.current) return;
|
|
3162
3494
|
const stack = getStack();
|
|
@@ -3167,7 +3499,7 @@ function useUndoRedo(params) {
|
|
|
3167
3499
|
for (const ev of nextBatch) {
|
|
3168
3500
|
onCellValueChangedRef.current(ev);
|
|
3169
3501
|
}
|
|
3170
|
-
}, [getStack]);
|
|
3502
|
+
}, [getStack, onCellValueChangedRef]);
|
|
3171
3503
|
return {
|
|
3172
3504
|
onCellValueChanged: onCellValueChanged ? wrapped : void 0,
|
|
3173
3505
|
undo,
|
|
@@ -3307,7 +3639,7 @@ function useFillHandle(params) {
|
|
|
3307
3639
|
endCol: end.endCol
|
|
3308
3640
|
});
|
|
3309
3641
|
setSelectionRange(norm);
|
|
3310
|
-
setActiveCell({ rowIndex:
|
|
3642
|
+
setActiveCell({ rowIndex: fillDrag.startRow, columnIndex: fillDrag.startCol + colOffsetRef.current });
|
|
3311
3643
|
const fillEvents = applyFillValues(norm, fillDrag.startRow, fillDrag.startCol, items, visibleCols);
|
|
3312
3644
|
if (fillEvents.length > 0) {
|
|
3313
3645
|
beginBatch?.();
|
|
@@ -3334,7 +3666,8 @@ function useFillHandle(params) {
|
|
|
3334
3666
|
beginBatch,
|
|
3335
3667
|
endBatch,
|
|
3336
3668
|
colOffsetRef,
|
|
3337
|
-
wrapperRef
|
|
3669
|
+
wrapperRef,
|
|
3670
|
+
onCellValueChangedRef
|
|
3338
3671
|
]);
|
|
3339
3672
|
const selectionRangeRef = useRef(selectionRange);
|
|
3340
3673
|
selectionRangeRef.current = selectionRange;
|
|
@@ -3369,7 +3702,7 @@ function useFillHandle(params) {
|
|
|
3369
3702
|
for (const evt of fillEvents) onCellValueChangedRef.current(evt);
|
|
3370
3703
|
endBatch?.();
|
|
3371
3704
|
}
|
|
3372
|
-
}, [editable, beginBatch, endBatch]);
|
|
3705
|
+
}, [editable, beginBatch, endBatch, onCellValueChangedRef, itemsRef, visibleColsRef]);
|
|
3373
3706
|
return { fillDrag, setFillDrag, handleFillHandleMouseDown, fillDown };
|
|
3374
3707
|
}
|
|
3375
3708
|
function useTableLayout(params) {
|
|
@@ -3869,8 +4202,7 @@ function useDataGridEditing(params) {
|
|
|
3869
4202
|
setSelectionRange({ startRow: newRow, startCol: localCol, endRow: newRow, endCol: localCol });
|
|
3870
4203
|
}
|
|
3871
4204
|
},
|
|
3872
|
-
|
|
3873
|
-
[setEditingCell, setPendingEditorValue, setActiveCell, setSelectionRange, colOffset, visibleColsRef, itemsLengthRef]
|
|
4205
|
+
[setEditingCell, setPendingEditorValue, setActiveCell, setSelectionRange, colOffset, visibleColsRef, itemsLengthRef, onCellValueChangedRef]
|
|
3874
4206
|
);
|
|
3875
4207
|
const cancelPopoverEdit = useCallback(() => {
|
|
3876
4208
|
setEditingCell(null);
|
|
@@ -6003,11 +6335,14 @@ function useVirtualScroll(params) {
|
|
|
6003
6335
|
enabled,
|
|
6004
6336
|
overscan = 5,
|
|
6005
6337
|
threshold = DEFAULT_PASSTHROUGH_THRESHOLD,
|
|
6006
|
-
containerRef
|
|
6338
|
+
containerRef,
|
|
6339
|
+
columnVirtualization = false,
|
|
6340
|
+
columnWidths,
|
|
6341
|
+
columnOverscan = 2
|
|
6007
6342
|
} = params;
|
|
6008
6343
|
useEffect(() => {
|
|
6009
6344
|
validateVirtualScrollConfig({ enabled, rowHeight });
|
|
6010
|
-
}, []);
|
|
6345
|
+
}, [enabled, rowHeight]);
|
|
6011
6346
|
const isActive = enabled && totalRows >= threshold;
|
|
6012
6347
|
const getScrollElement = useCallback(
|
|
6013
6348
|
() => containerRef.current,
|
|
@@ -6062,11 +6397,51 @@ function useVirtualScroll(params) {
|
|
|
6062
6397
|
},
|
|
6063
6398
|
[isActive, containerRef, rowHeight]
|
|
6064
6399
|
);
|
|
6400
|
+
const [scrollLeft, setScrollLeft] = useState(0);
|
|
6401
|
+
const scrollLeftRaf = useRef(0);
|
|
6402
|
+
const onHorizontalScroll = useCallback(
|
|
6403
|
+
(sl) => {
|
|
6404
|
+
if (scrollLeftRaf.current) cancelAnimationFrame(scrollLeftRaf.current);
|
|
6405
|
+
scrollLeftRaf.current = requestAnimationFrame(() => {
|
|
6406
|
+
scrollLeftRaf.current = 0;
|
|
6407
|
+
setScrollLeft(sl);
|
|
6408
|
+
});
|
|
6409
|
+
},
|
|
6410
|
+
[]
|
|
6411
|
+
);
|
|
6412
|
+
useEffect(() => {
|
|
6413
|
+
return () => {
|
|
6414
|
+
if (scrollLeftRaf.current) cancelAnimationFrame(scrollLeftRaf.current);
|
|
6415
|
+
};
|
|
6416
|
+
}, []);
|
|
6417
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
6418
|
+
useEffect(() => {
|
|
6419
|
+
if (!columnVirtualization) return;
|
|
6420
|
+
const el = containerRef.current;
|
|
6421
|
+
if (!el) return;
|
|
6422
|
+
setContainerWidth(el.clientWidth);
|
|
6423
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
6424
|
+
const ro = new ResizeObserver((entries) => {
|
|
6425
|
+
if (entries.length > 0) {
|
|
6426
|
+
setContainerWidth(entries[0].contentRect.width);
|
|
6427
|
+
}
|
|
6428
|
+
});
|
|
6429
|
+
ro.observe(el);
|
|
6430
|
+
return () => ro.disconnect();
|
|
6431
|
+
}, [columnVirtualization, containerRef]);
|
|
6432
|
+
const columnRange = useMemo(() => {
|
|
6433
|
+
if (!columnVirtualization || !columnWidths || columnWidths.length === 0 || containerWidth <= 0) {
|
|
6434
|
+
return null;
|
|
6435
|
+
}
|
|
6436
|
+
return computeVisibleColumnRange(scrollLeft, columnWidths, containerWidth, columnOverscan);
|
|
6437
|
+
}, [columnVirtualization, columnWidths, containerWidth, scrollLeft, columnOverscan]);
|
|
6065
6438
|
return {
|
|
6066
6439
|
virtualizer: isActive ? virtualizer : null,
|
|
6067
6440
|
totalHeight,
|
|
6068
6441
|
visibleRange: activeRange,
|
|
6069
|
-
scrollToIndex
|
|
6442
|
+
scrollToIndex,
|
|
6443
|
+
columnRange,
|
|
6444
|
+
onHorizontalScroll: columnVirtualization ? onHorizontalScroll : void 0
|
|
6070
6445
|
};
|
|
6071
6446
|
}
|
|
6072
6447
|
function useListVirtualizer(opts) {
|
|
@@ -6177,13 +6552,28 @@ function useDataGridTableOrchestration(params) {
|
|
|
6177
6552
|
});
|
|
6178
6553
|
const virtualScrollEnabled = virtualScroll?.enabled === true;
|
|
6179
6554
|
const virtualRowHeight = virtualScroll?.rowHeight ?? 36;
|
|
6180
|
-
const
|
|
6555
|
+
const columnVirtualization = virtualScroll?.columns === true;
|
|
6556
|
+
const unpinnedColumnWidths = useMemo(() => {
|
|
6557
|
+
if (!columnVirtualization) return void 0;
|
|
6558
|
+
const widths = [];
|
|
6559
|
+
for (const col of visibleCols) {
|
|
6560
|
+
const pin = pinnedColumns?.[col.columnId];
|
|
6561
|
+
if (!pin) {
|
|
6562
|
+
widths.push(getColumnWidth(col));
|
|
6563
|
+
}
|
|
6564
|
+
}
|
|
6565
|
+
return widths;
|
|
6566
|
+
}, [columnVirtualization, visibleCols, pinnedColumns, getColumnWidth]);
|
|
6567
|
+
const { visibleRange, columnRange, onHorizontalScroll } = useVirtualScroll({
|
|
6181
6568
|
totalRows: items.length,
|
|
6182
6569
|
rowHeight: virtualRowHeight,
|
|
6183
6570
|
enabled: virtualScrollEnabled,
|
|
6184
6571
|
overscan: virtualScroll?.overscan,
|
|
6185
6572
|
threshold: virtualScroll?.threshold,
|
|
6186
|
-
containerRef: wrapperRef
|
|
6573
|
+
containerRef: wrapperRef,
|
|
6574
|
+
columnVirtualization,
|
|
6575
|
+
columnWidths: unpinnedColumnWidths,
|
|
6576
|
+
columnOverscan: virtualScroll?.columnOverscan
|
|
6187
6577
|
});
|
|
6188
6578
|
const editCallbacks = useMemo(
|
|
6189
6579
|
() => ({ commitCellEdit, setEditingCell, setPendingEditorValue, cancelPopoverEdit }),
|
|
@@ -6201,8 +6591,10 @@ function useDataGridTableOrchestration(params) {
|
|
|
6201
6591
|
const currentVersion = CellDescriptorCache.computeVersion(cellDescriptorInput);
|
|
6202
6592
|
cellDescriptorCacheRef.current.updateVersion(currentVersion);
|
|
6203
6593
|
const prevItemsRef = useRef(items);
|
|
6204
|
-
|
|
6594
|
+
const prevVisibleColsRef = useRef(visibleCols);
|
|
6595
|
+
if (prevItemsRef.current !== items || prevVisibleColsRef.current !== visibleCols) {
|
|
6205
6596
|
prevItemsRef.current = items;
|
|
6597
|
+
prevVisibleColsRef.current = visibleCols;
|
|
6206
6598
|
cellDescriptorCacheRef.current.clear();
|
|
6207
6599
|
}
|
|
6208
6600
|
const handleSingleRowClick = useCallback((e) => {
|
|
@@ -6237,6 +6629,8 @@ function useDataGridTableOrchestration(params) {
|
|
|
6237
6629
|
virtualScrollEnabled,
|
|
6238
6630
|
virtualRowHeight,
|
|
6239
6631
|
visibleRange,
|
|
6632
|
+
columnRange,
|
|
6633
|
+
onHorizontalScroll,
|
|
6240
6634
|
// Derived from props
|
|
6241
6635
|
items,
|
|
6242
6636
|
columns,
|
|
@@ -7137,7 +7531,7 @@ function MarchingAntsOverlay({
|
|
|
7137
7531
|
const selR = selRect ? roundRect(selRect) : null;
|
|
7138
7532
|
const clipR = clipRect ? roundRect(clipRect) : null;
|
|
7139
7533
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7140
|
-
selR && !isDragging && !clipRangeMatchesSel && /* @__PURE__ */ jsx(
|
|
7534
|
+
selR && !isDragging && !clipRangeMatchesSel && !(selectionRange && selectionRange.startRow === selectionRange.endRow && selectionRange.startCol === selectionRange.endCol) && /* @__PURE__ */ jsx(
|
|
7141
7535
|
"svg",
|
|
7142
7536
|
{
|
|
7143
7537
|
style: {
|
|
@@ -7539,4 +7933,4 @@ function renderFilterContent(filterType, state, options, isLoadingOptions, selec
|
|
|
7539
7933
|
return null;
|
|
7540
7934
|
}
|
|
7541
7935
|
|
|
7542
|
-
export { BaseColumnHeaderMenu, BaseDropIndicator, BaseEmptyState, BaseInlineCellEditor, BaseLoadingOverlay, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, CURSOR_CELL_STYLE, CellDescriptorCache, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, DateFilterContent, EmptyState, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, GRID_ROOT_STYLE, GridContextMenu, MAX_PAGE_BUTTONS, MarchingAntsOverlay, NOOP3 as NOOP, OGridLayout, PAGE_SIZE_OPTIONS, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, ROW_NUMBER_COLUMN_WIDTH, STOP_PROPAGATION, SideBar, StatusBar, UndoRedoStack, areGridRowPropsEqual, booleanParser, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps2 as buildInlineEditorProps, buildPopoverEditorProps2 as buildPopoverEditorProps, clampSelectionToBounds, computeAggregations, computeAutoScrollSpeed, computeTabNavigation, createOGrid, currencyParser, dateParser, deriveFilterOptionsFromData, editorInputStyle, editorWrapperStyle, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellInteractionProps, getCellRenderDescriptor, getCellValue, getColumnHeaderFilterStateParams, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getDateFilterContentProps, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getStatusBarParts, isInSelectionRange, isRowInRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, processClientSideData, rangesEqual, renderFilterContent, resolveCellDisplayContent2 as resolveCellDisplayContent, resolveCellStyle2 as resolveCellStyle, richSelectDropdownStyle, richSelectNoMatchesStyle, richSelectOptionHighlightedStyle, richSelectOptionStyle, richSelectWrapperStyle, selectChevronStyle, selectDisplayStyle, selectEditorStyle, toUserLike, triggerCsvDownload, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnMeta, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableOrchestration, useDateFilterState, useDebounce, useFillHandle, useFilterOptions, useInlineCellEditorState, useKeyboardNavigation, useLatestRef, useListVirtualizer, useMultiSelectFilterState, useOGrid, usePaginationControls, usePeopleFilterState, useRichSelectState, useRowSelection, useSelectState, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll };
|
|
7936
|
+
export { BaseColumnHeaderMenu, BaseDropIndicator, BaseEmptyState, BaseInlineCellEditor, BaseLoadingOverlay, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, CURSOR_CELL_STYLE, CellDescriptorCache, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, DateFilterContent, EmptyState, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, GRID_ROOT_STYLE, GridContextMenu, MAX_PAGE_BUTTONS, MarchingAntsOverlay, NOOP3 as NOOP, OGridLayout, PAGE_SIZE_OPTIONS, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, ROW_NUMBER_COLUMN_WIDTH, STOP_PROPAGATION, SideBar, StatusBar, UndoRedoStack, areGridRowPropsEqual, booleanParser, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps2 as buildInlineEditorProps, buildPopoverEditorProps2 as buildPopoverEditorProps, clampSelectionToBounds, computeAggregations, computeAutoScrollSpeed, computeTabNavigation, createOGrid, currencyParser, dateParser, deriveFilterOptionsFromData, editorInputStyle, editorWrapperStyle, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellInteractionProps, getCellRenderDescriptor, getCellValue, getColumnHeaderFilterStateParams, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getDateFilterContentProps, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getStatusBarParts, isInSelectionRange, isRowInRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, partitionColumnsForVirtualization, processClientSideData, rangesEqual, renderFilterContent, resolveCellDisplayContent2 as resolveCellDisplayContent, resolveCellStyle2 as resolveCellStyle, richSelectDropdownStyle, richSelectNoMatchesStyle, richSelectOptionHighlightedStyle, richSelectOptionStyle, richSelectWrapperStyle, selectChevronStyle, selectDisplayStyle, selectEditorStyle, toUserLike, triggerCsvDownload, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnMeta, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableOrchestration, useDateFilterState, useDebounce, useFillHandle, useFilterOptions, useInlineCellEditorState, useKeyboardNavigation, useLatestRef, useListVirtualizer, useMultiSelectFilterState, useOGrid, usePaginationControls, usePeopleFilterState, useRichSelectState, useRowSelection, useSelectState, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll };
|
|
@@ -4,6 +4,7 @@ import type { DataGridLayoutState, DataGridRowSelectionState, DataGridEditingSta
|
|
|
4
4
|
import type { UseColumnResizeResult } from './useColumnResize';
|
|
5
5
|
import type { UseColumnReorderResult } from './useColumnReorder';
|
|
6
6
|
import type { UseVirtualScrollResult } from './useVirtualScroll';
|
|
7
|
+
import type { IVisibleColumnRange } from '@alaarab/ogrid-core';
|
|
7
8
|
import type { HeaderFilterConfigInput, CellRenderDescriptorInput } from '../utils';
|
|
8
9
|
import type { IStatusBarProps, RowId, HeaderRow } from '../types';
|
|
9
10
|
import { CellDescriptorCache } from '@alaarab/ogrid-core';
|
|
@@ -32,6 +33,10 @@ export interface UseDataGridTableOrchestrationResult<T> {
|
|
|
32
33
|
virtualScrollEnabled: boolean;
|
|
33
34
|
virtualRowHeight: number;
|
|
34
35
|
visibleRange: UseVirtualScrollResult['visibleRange'];
|
|
36
|
+
/** Visible column range for horizontal virtualization (null when disabled). */
|
|
37
|
+
columnRange: IVisibleColumnRange | null;
|
|
38
|
+
/** Callback for horizontal scroll events (column virtualization). */
|
|
39
|
+
onHorizontalScroll?: (scrollLeft: number) => void;
|
|
35
40
|
items: T[];
|
|
36
41
|
columns: IOGridDataGridProps<T>['columns'];
|
|
37
42
|
getRowId: IOGridDataGridProps<T>['getRowId'];
|
|
@@ -14,6 +14,8 @@ export interface UseOGridDataFetchingParams<T> {
|
|
|
14
14
|
pageSize: number;
|
|
15
15
|
onError?: (err: unknown) => void;
|
|
16
16
|
onFirstDataRendered?: () => void;
|
|
17
|
+
/** Worker sort mode: true=always, 'auto'=when data > 5000 rows, false=sync. */
|
|
18
|
+
workerSort?: boolean | 'auto';
|
|
17
19
|
}
|
|
18
20
|
export interface UseOGridDataFetchingState<T> {
|
|
19
21
|
displayItems: T[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Virtualizer } from '@tanstack/react-virtual';
|
|
2
2
|
import type { RefObject } from 'react';
|
|
3
|
-
import type { IVisibleRange } from '@alaarab/ogrid-core';
|
|
3
|
+
import type { IVisibleRange, IVisibleColumnRange } from '@alaarab/ogrid-core';
|
|
4
4
|
export type { IVirtualScrollConfig } from '@alaarab/ogrid-core';
|
|
5
5
|
export interface UseVirtualScrollParams {
|
|
6
6
|
/** Total number of rows in the data set. */
|
|
@@ -18,6 +18,12 @@ export interface UseVirtualScrollParams {
|
|
|
18
18
|
threshold?: number;
|
|
19
19
|
/** Ref to the scrollable container element. */
|
|
20
20
|
containerRef: RefObject<HTMLElement | null>;
|
|
21
|
+
/** Enable column virtualization (only render visible columns). */
|
|
22
|
+
columnVirtualization?: boolean;
|
|
23
|
+
/** Column widths for horizontal virtualization (unpinned columns only). */
|
|
24
|
+
columnWidths?: number[];
|
|
25
|
+
/** Column overscan count. Default: 2. */
|
|
26
|
+
columnOverscan?: number;
|
|
21
27
|
}
|
|
22
28
|
export interface UseVirtualScrollResult {
|
|
23
29
|
/** The TanStack virtualizer instance (null when disabled). */
|
|
@@ -28,11 +34,15 @@ export interface UseVirtualScrollResult {
|
|
|
28
34
|
visibleRange: IVisibleRange;
|
|
29
35
|
/** Scroll to a specific row index. */
|
|
30
36
|
scrollToIndex: (index: number) => void;
|
|
37
|
+
/** Visible column range for horizontal virtualization (null when column virtualization disabled). */
|
|
38
|
+
columnRange: IVisibleColumnRange | null;
|
|
39
|
+
/** Callback to attach to scroll container's onScroll for horizontal tracking. */
|
|
40
|
+
onHorizontalScroll?: (scrollLeft: number) => void;
|
|
31
41
|
}
|
|
32
42
|
/**
|
|
33
|
-
* Wraps TanStack Virtual for row virtualization.
|
|
43
|
+
* Wraps TanStack Virtual for row virtualization, with optional column virtualization.
|
|
34
44
|
* When disabled or when totalRows < threshold, returns a pass-through (all rows visible).
|
|
35
|
-
* @param params - Total rows, row height, enabled flag, overscan, threshold, and
|
|
36
|
-
* @returns Virtualizer instance, total height, visible range, and
|
|
45
|
+
* @param params - Total rows, row height, enabled flag, overscan, threshold, container ref, and column virtualization params.
|
|
46
|
+
* @returns Virtualizer instance, total height, visible range, scrollToIndex, columnRange, and onHorizontalScroll.
|
|
37
47
|
*/
|
|
38
48
|
export declare function useVirtualScroll(params: UseVirtualScrollParams): UseVirtualScrollResult;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export { BaseDropIndicator } from './components/BaseDropIndicator';
|
|
|
32
32
|
export type { BaseDropIndicatorProps } from './components/BaseDropIndicator';
|
|
33
33
|
export { DateFilterContent, getColumnHeaderFilterStateParams, getDateFilterContentProps, } from './components/ColumnHeaderFilterContent';
|
|
34
34
|
export type { IColumnHeaderFilterProps, DateFilterContentProps, DateFilterClassNames, } from './components/ColumnHeaderFilterContent';
|
|
35
|
-
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, GRID_CONTEXT_MENU_ITEMS, COLUMN_HEADER_MENU_ITEMS, getContextMenuHandlers, getColumnHeaderMenuItems, formatShortcut, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, getHeaderFilterConfig, getCellRenderDescriptor, CellDescriptorCache, isRowInRange, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, areGridRowPropsEqual, findCtrlArrowTarget, computeTabNavigation, rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, UndoRedoStack, } from './utils';
|
|
35
|
+
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, GRID_CONTEXT_MENU_ITEMS, COLUMN_HEADER_MENU_ITEMS, getContextMenuHandlers, getColumnHeaderMenuItems, formatShortcut, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, getHeaderFilterConfig, getCellRenderDescriptor, CellDescriptorCache, isRowInRange, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, partitionColumnsForVirtualization, areGridRowPropsEqual, findCtrlArrowTarget, computeTabNavigation, rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, UndoRedoStack, } from './utils';
|
|
36
36
|
export type { CsvColumn, StatusBarPart, StatusBarPartsInput, GridContextMenuItem, GridContextMenuHandlerProps, PaginationViewModel, HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, CellInteractionHandlers, ParseValueResult, AggregationResult, GridRowComparatorProps, IColumnHeaderMenuItem, ColumnHeaderMenuInput, ColumnHeaderMenuHandlers, } from './utils';
|
|
37
37
|
export { renderFilterContent } from './components/ColumnHeaderFilterRenderers';
|
|
38
38
|
export type { FilterContentRenderers, MultiSelectRendererProps, TextRendererProps, PeopleRendererProps, DateRendererProps, } from './components/ColumnHeaderFilterRenderers';
|
|
@@ -80,6 +80,14 @@ interface IOGridBaseProps<T> {
|
|
|
80
80
|
rowHeight?: number;
|
|
81
81
|
/** Cell spacing/density preset. Controls cell padding throughout the grid. Default: 'normal'. */
|
|
82
82
|
density?: 'compact' | 'normal' | 'comfortable';
|
|
83
|
+
/**
|
|
84
|
+
* Offload sorting to a Web Worker to avoid blocking the main thread.
|
|
85
|
+
* - `true`: always use worker sort
|
|
86
|
+
* - `'auto'`: use worker sort when data.length > 5000
|
|
87
|
+
* - `false` (default): use synchronous sort
|
|
88
|
+
* Columns with custom `compare` functions fall back to synchronous sort.
|
|
89
|
+
*/
|
|
90
|
+
workerSort?: boolean | 'auto';
|
|
83
91
|
/** Fires once when the grid first renders with data (useful for restoring column state). */
|
|
84
92
|
onFirstDataRendered?: () => void;
|
|
85
93
|
/** Called when server-side fetchPage fails. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, GRID_CONTEXT_MENU_ITEMS, COLUMN_HEADER_MENU_ITEMS, getContextMenuHandlers, getColumnHeaderMenuItems, formatShortcut, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, computeNextSortState, measureColumnContentWidth, AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, findCtrlArrowTarget, computeTabNavigation, rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, applyFillValues, computeArrowNavigation, applyCellDeletion, applyRangeRowSelection, computeRowSelectionState, UndoRedoStack, buildCellIndex, } from '@alaarab/ogrid-core';
|
|
1
|
+
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, GRID_CONTEXT_MENU_ITEMS, COLUMN_HEADER_MENU_ITEMS, getContextMenuHandlers, getColumnHeaderMenuItems, formatShortcut, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, partitionColumnsForVirtualization, computeNextSortState, measureColumnContentWidth, AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, findCtrlArrowTarget, computeTabNavigation, rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, applyFillValues, computeArrowNavigation, applyCellDeletion, applyRangeRowSelection, computeRowSelectionState, UndoRedoStack, buildCellIndex, } from '@alaarab/ogrid-core';
|
|
2
2
|
export type { CsvColumn, StatusBarPart, StatusBarPartsInput, GridContextMenuItem, GridContextMenuHandlerProps, PaginationViewModel, ParseValueResult, AggregationResult, IColumnHeaderMenuItem, ColumnHeaderMenuInput, ColumnHeaderMenuHandlers, ArrowNavigationContext, ArrowNavigationResult, } from '@alaarab/ogrid-core';
|
|
3
3
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './dataGridViewModel';
|
|
4
4
|
export { CellDescriptorCache } from '@alaarab/ogrid-core';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "OGrid React – React hooks, headless components, and utilities for OGrid data grids.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"node": ">=18"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@alaarab/ogrid-core": "2.
|
|
42
|
+
"@alaarab/ogrid-core": "2.2.0",
|
|
43
43
|
"@tanstack/react-virtual": "^3.0.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|