react-glide-table 1.4.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -2
- package/dist/compound.cjs +1222 -119
- package/dist/compound.d.cts +11 -3
- package/dist/compound.d.ts +11 -3
- package/dist/compound.js +1224 -114
- package/dist/core.cjs +874 -48
- package/dist/core.d.cts +73 -6
- package/dist/core.d.ts +73 -6
- package/dist/core.js +868 -52
- package/dist/index.cjs +1270 -133
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1252 -125
- package/dist/{types-CHQnBz91.d.cts → types-Cs9MiZs1.d.cts} +104 -1
- package/dist/{types-CHQnBz91.d.ts → types-Cs9MiZs1.d.ts} +104 -1
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -5,7 +5,12 @@ var DEFAULT_DATA_TABLE_LABELS = {
|
|
|
5
5
|
selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
|
|
6
6
|
expandRow: "Expand row",
|
|
7
7
|
collapseRow: "Collapse row",
|
|
8
|
-
resizeColumn: "Resize column"
|
|
8
|
+
resizeColumn: "Resize column",
|
|
9
|
+
searchPlaceholder: "Search\u2026",
|
|
10
|
+
searchResultHint: "Type to search",
|
|
11
|
+
searchPrevious: "Previous result",
|
|
12
|
+
searchNext: "Next result",
|
|
13
|
+
searchClose: "Close search"
|
|
9
14
|
};
|
|
10
15
|
function resolveDataTableLabels(partial) {
|
|
11
16
|
return {
|
|
@@ -29,11 +34,11 @@ import {
|
|
|
29
34
|
useVirtualizer
|
|
30
35
|
} from "@tanstack/react-virtual";
|
|
31
36
|
import {
|
|
32
|
-
useCallback as
|
|
33
|
-
useEffect as
|
|
34
|
-
useMemo as
|
|
35
|
-
useRef as
|
|
36
|
-
useState as
|
|
37
|
+
useCallback as useCallback4,
|
|
38
|
+
useEffect as useEffect5,
|
|
39
|
+
useMemo as useMemo3,
|
|
40
|
+
useRef as useRef5,
|
|
41
|
+
useState as useState4
|
|
37
42
|
} from "react";
|
|
38
43
|
|
|
39
44
|
// src/components/ui/table/constants.ts
|
|
@@ -191,6 +196,36 @@ function getCellSelectionBounds(start, end) {
|
|
|
191
196
|
endCol: Math.max(start.col, end.col)
|
|
192
197
|
};
|
|
193
198
|
}
|
|
199
|
+
function getCellNavigationDelta(key) {
|
|
200
|
+
switch (key) {
|
|
201
|
+
case "ArrowUp":
|
|
202
|
+
case "w":
|
|
203
|
+
case "W":
|
|
204
|
+
return { row: -1, col: 0 };
|
|
205
|
+
case "ArrowDown":
|
|
206
|
+
case "s":
|
|
207
|
+
case "S":
|
|
208
|
+
return { row: 1, col: 0 };
|
|
209
|
+
case "ArrowLeft":
|
|
210
|
+
case "a":
|
|
211
|
+
case "A":
|
|
212
|
+
return { row: 0, col: -1 };
|
|
213
|
+
case "ArrowRight":
|
|
214
|
+
case "d":
|
|
215
|
+
case "D":
|
|
216
|
+
return { row: 0, col: 1 };
|
|
217
|
+
default:
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function clampCellPosition(position, rowCount, columnCount) {
|
|
222
|
+
const maxRow = Math.max(rowCount - 1, 0);
|
|
223
|
+
const maxCol = Math.max(columnCount - 1, 0);
|
|
224
|
+
return {
|
|
225
|
+
row: Math.min(Math.max(position.row, 0), maxRow),
|
|
226
|
+
col: Math.min(Math.max(position.col, 0), maxCol)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
194
229
|
function measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement) {
|
|
195
230
|
if (rowSpan <= 1) return void 0;
|
|
196
231
|
const tbody = cellElement?.closest("tbody") ?? (typeof document !== "undefined" ? document.querySelector("tbody.data-table-body") : null);
|
|
@@ -714,26 +749,44 @@ function useCellSelection({
|
|
|
714
749
|
data,
|
|
715
750
|
rows,
|
|
716
751
|
enabled = true,
|
|
752
|
+
columnCount = 0,
|
|
717
753
|
enableSubtreeCopy = false,
|
|
718
754
|
enableInsertPaste = true,
|
|
719
755
|
onDataChange,
|
|
720
756
|
onBatchChange,
|
|
721
|
-
onRowsPaste
|
|
757
|
+
onRowsPaste,
|
|
758
|
+
onCellNavigate
|
|
722
759
|
}) {
|
|
723
760
|
const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
|
|
724
761
|
const pendingPasteModeRef = useRef2(null);
|
|
762
|
+
const dragStateRef = useRef2(dragState);
|
|
763
|
+
const onCellNavigateRef = useRef2(onCellNavigate);
|
|
764
|
+
dragStateRef.current = dragState;
|
|
765
|
+
onCellNavigateRef.current = onCellNavigate;
|
|
725
766
|
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
726
767
|
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
727
768
|
const handleCellMouseDown = useCallback2(
|
|
728
|
-
(rowIndex, colIndex) => {
|
|
769
|
+
(rowIndex, colIndex, options) => {
|
|
729
770
|
if (!enabled) return;
|
|
730
|
-
setDragState({
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
771
|
+
setDragState((prev) => {
|
|
772
|
+
if (options?.shiftKey && prev.start) {
|
|
773
|
+
return {
|
|
774
|
+
...prev,
|
|
775
|
+
isSelecting: true,
|
|
776
|
+
isFillDragging: false,
|
|
777
|
+
end: { row: rowIndex, col: colIndex },
|
|
778
|
+
fillAnchor: null,
|
|
779
|
+
fillEnd: null
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
isSelecting: true,
|
|
784
|
+
isFillDragging: false,
|
|
785
|
+
start: { row: rowIndex, col: colIndex },
|
|
786
|
+
end: { row: rowIndex, col: colIndex },
|
|
787
|
+
fillAnchor: null,
|
|
788
|
+
fillEnd: null
|
|
789
|
+
};
|
|
737
790
|
});
|
|
738
791
|
},
|
|
739
792
|
[enabled]
|
|
@@ -775,6 +828,53 @@ function useCellSelection({
|
|
|
775
828
|
setDragState(INITIAL_DRAG_STATE);
|
|
776
829
|
}
|
|
777
830
|
}, [enabled]);
|
|
831
|
+
useEffect2(() => {
|
|
832
|
+
if (!enabled) return;
|
|
833
|
+
const handleKeyDown = (e) => {
|
|
834
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
835
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
const delta = getCellNavigationDelta(e.key);
|
|
839
|
+
if (!delta) return;
|
|
840
|
+
const prev = dragStateRef.current;
|
|
841
|
+
if (!prev.start || !prev.end) return;
|
|
842
|
+
if (prev.isSelecting || prev.isFillDragging) return;
|
|
843
|
+
const rowCount = rows.length;
|
|
844
|
+
const resolvedColumnCount = columnCount > 0 ? columnCount : rows[0]?.getVisibleCells().length ?? 0;
|
|
845
|
+
if (rowCount <= 0 || resolvedColumnCount <= 0) return;
|
|
846
|
+
const nextEnd = clampCellPosition(
|
|
847
|
+
{
|
|
848
|
+
row: prev.end.row + delta.row,
|
|
849
|
+
col: prev.end.col + delta.col
|
|
850
|
+
},
|
|
851
|
+
rowCount,
|
|
852
|
+
resolvedColumnCount
|
|
853
|
+
);
|
|
854
|
+
if (nextEnd.row === prev.end.row && nextEnd.col === prev.end.col) return;
|
|
855
|
+
e.preventDefault();
|
|
856
|
+
const nextState = e.shiftKey ? {
|
|
857
|
+
...prev,
|
|
858
|
+
isSelecting: false,
|
|
859
|
+
isFillDragging: false,
|
|
860
|
+
end: nextEnd,
|
|
861
|
+
fillAnchor: null,
|
|
862
|
+
fillEnd: null
|
|
863
|
+
} : {
|
|
864
|
+
isSelecting: false,
|
|
865
|
+
isFillDragging: false,
|
|
866
|
+
start: nextEnd,
|
|
867
|
+
end: nextEnd,
|
|
868
|
+
fillAnchor: null,
|
|
869
|
+
fillEnd: null
|
|
870
|
+
};
|
|
871
|
+
dragStateRef.current = nextState;
|
|
872
|
+
setDragState(nextState);
|
|
873
|
+
onCellNavigateRef.current?.(nextEnd);
|
|
874
|
+
};
|
|
875
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
876
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
877
|
+
}, [columnCount, enabled, rows]);
|
|
778
878
|
const copySelection = useCallback2(
|
|
779
879
|
async (options) => {
|
|
780
880
|
if (!enabled || !activeSelectionBounds) return false;
|
|
@@ -1011,12 +1111,473 @@ function getColumnFreezeStyle(offset, options) {
|
|
|
1011
1111
|
position: "sticky",
|
|
1012
1112
|
...offset.side === "left" ? { left: offset.offset } : { right: offset.offset },
|
|
1013
1113
|
zIndex: zBase + offset.stack,
|
|
1014
|
-
...options?.isHeader ? { top: 0 } : {}
|
|
1114
|
+
...options?.isHeader ? { top: options.headerTop ?? 0 } : {}
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// src/components/ui/table/features/inline-search/inlineSearch.ts
|
|
1119
|
+
var INLINE_SEARCH_MAX_RESULTS = 1e3;
|
|
1120
|
+
var INLINE_SEARCH_TARGET_TICK_MS = 10;
|
|
1121
|
+
var INLINE_SEARCH_INITIAL_STRIDE = 10;
|
|
1122
|
+
function escapeSearchRegex(value) {
|
|
1123
|
+
return value.replace(/([$()*+.?[\\\]^{|}-])/g, "\\$1");
|
|
1124
|
+
}
|
|
1125
|
+
function createSearchRegex(query) {
|
|
1126
|
+
const trimmed = query.trim();
|
|
1127
|
+
if (!trimmed) return null;
|
|
1128
|
+
return new RegExp(escapeSearchRegex(trimmed), "i");
|
|
1129
|
+
}
|
|
1130
|
+
function cellValueToSearchText(value) {
|
|
1131
|
+
if (value == null) return void 0;
|
|
1132
|
+
if (typeof value === "string") return value;
|
|
1133
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1134
|
+
return String(value);
|
|
1135
|
+
}
|
|
1136
|
+
if (Array.isArray(value)) {
|
|
1137
|
+
return value.map((item) => cellValueToSearchText(item) ?? "").join(" ");
|
|
1138
|
+
}
|
|
1139
|
+
if (typeof value === "object") {
|
|
1140
|
+
try {
|
|
1141
|
+
return JSON.stringify(value);
|
|
1142
|
+
} catch {
|
|
1143
|
+
return String(value);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return String(value);
|
|
1147
|
+
}
|
|
1148
|
+
function formatSearchResultLabel(status) {
|
|
1149
|
+
const countLabel = status.results >= INLINE_SEARCH_MAX_RESULTS ? `over ${INLINE_SEARCH_MAX_RESULTS}` : `${status.results} result${status.results !== 1 ? "s" : ""}`;
|
|
1150
|
+
if (status.selectedIndex >= 0 && status.results > 0) {
|
|
1151
|
+
return `${status.selectedIndex + 1} of ${countLabel}`;
|
|
1152
|
+
}
|
|
1153
|
+
return countLabel;
|
|
1154
|
+
}
|
|
1155
|
+
function nextSearchIndex(selectedIndex, results) {
|
|
1156
|
+
if (results <= 0) return -1;
|
|
1157
|
+
if (selectedIndex < 0) return 0;
|
|
1158
|
+
return (selectedIndex + 1) % results;
|
|
1159
|
+
}
|
|
1160
|
+
function previousSearchIndex(selectedIndex, results) {
|
|
1161
|
+
if (results <= 0) return -1;
|
|
1162
|
+
if (selectedIndex < 0) return results - 1;
|
|
1163
|
+
let next = (selectedIndex - 1) % results;
|
|
1164
|
+
if (next < 0) next += results;
|
|
1165
|
+
return next;
|
|
1166
|
+
}
|
|
1167
|
+
function buildSearchMatchKey(colIndex, rowIndex) {
|
|
1168
|
+
return `${colIndex}:${rowIndex}`;
|
|
1169
|
+
}
|
|
1170
|
+
function buildSearchMatchKeys(results) {
|
|
1171
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1172
|
+
for (const [colIndex, rowIndex] of results) {
|
|
1173
|
+
keys.add(buildSearchMatchKey(colIndex, rowIndex));
|
|
1174
|
+
}
|
|
1175
|
+
return keys;
|
|
1176
|
+
}
|
|
1177
|
+
function collectSearchMatchesInRange(options) {
|
|
1178
|
+
const {
|
|
1179
|
+
query,
|
|
1180
|
+
startRow,
|
|
1181
|
+
rowCount,
|
|
1182
|
+
columnCount,
|
|
1183
|
+
getCellValue,
|
|
1184
|
+
maxResults = INLINE_SEARCH_MAX_RESULTS
|
|
1185
|
+
} = options;
|
|
1186
|
+
const regex = createSearchRegex(query);
|
|
1187
|
+
if (!regex || rowCount <= 0 || columnCount <= 0) return [];
|
|
1188
|
+
const matches = [];
|
|
1189
|
+
for (let rowOffset = 0; rowOffset < rowCount; rowOffset += 1) {
|
|
1190
|
+
const rowIndex = startRow + rowOffset;
|
|
1191
|
+
for (let colIndex = 0; colIndex < columnCount; colIndex += 1) {
|
|
1192
|
+
const text = cellValueToSearchText(getCellValue(rowIndex, colIndex));
|
|
1193
|
+
if (text !== void 0 && regex.test(text)) {
|
|
1194
|
+
matches.push([colIndex, rowIndex]);
|
|
1195
|
+
if (matches.length >= maxResults) {
|
|
1196
|
+
return matches;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return matches;
|
|
1202
|
+
}
|
|
1203
|
+
function nextSearchStride(currentStride, elapsedMs, targetMs = INLINE_SEARCH_TARGET_TICK_MS) {
|
|
1204
|
+
const rounded = Math.max(elapsedMs, 1);
|
|
1205
|
+
const scalar = targetMs / rounded;
|
|
1206
|
+
return Math.max(1, Math.ceil(currentStride * scalar));
|
|
1207
|
+
}
|
|
1208
|
+
function buildFlatSearchCorpus(rows, getRowId) {
|
|
1209
|
+
return rows.map((data, index) => ({
|
|
1210
|
+
id: getRowId(data, index),
|
|
1211
|
+
data,
|
|
1212
|
+
ancestorToggleKeys: []
|
|
1213
|
+
}));
|
|
1214
|
+
}
|
|
1215
|
+
function buildTreeSearchCorpus(visibleRows, options) {
|
|
1216
|
+
const { toggleField, getRowId } = options;
|
|
1217
|
+
const corpus = [];
|
|
1218
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1219
|
+
const walk = (node, ancestorToggleKeys) => {
|
|
1220
|
+
const id = getRowId(node, corpus.length);
|
|
1221
|
+
if (seen.has(id)) return;
|
|
1222
|
+
seen.add(id);
|
|
1223
|
+
corpus.push({
|
|
1224
|
+
id,
|
|
1225
|
+
data: node,
|
|
1226
|
+
ancestorToggleKeys
|
|
1227
|
+
});
|
|
1228
|
+
const children = node.children;
|
|
1229
|
+
if (!Array.isArray(children) || children.length === 0) return;
|
|
1230
|
+
const toggleValue = node[toggleField];
|
|
1231
|
+
const childAncestors = typeof toggleValue === "string" && toggleValue.length > 0 ? [...ancestorToggleKeys, toggleValue] : ancestorToggleKeys;
|
|
1232
|
+
for (const child of children) {
|
|
1233
|
+
if (child && typeof child === "object") {
|
|
1234
|
+
walk(child, childAncestors);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
for (const row of visibleRows) {
|
|
1239
|
+
const level = row.level;
|
|
1240
|
+
if (level === 0 || level === void 0) {
|
|
1241
|
+
walk(row, []);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
for (const row of visibleRows) {
|
|
1245
|
+
const id = getRowId(row, corpus.length);
|
|
1246
|
+
if (seen.has(id)) continue;
|
|
1247
|
+
walk(row, []);
|
|
1248
|
+
}
|
|
1249
|
+
return corpus;
|
|
1250
|
+
}
|
|
1251
|
+
function mapSearchResultsToVisibleKeys(results, corpus, visibleRowIndexById) {
|
|
1252
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1253
|
+
for (const [colIndex, corpusRowIndex] of results) {
|
|
1254
|
+
const corpusRow = corpus[corpusRowIndex];
|
|
1255
|
+
if (!corpusRow) continue;
|
|
1256
|
+
const visibleRowIndex = visibleRowIndexById.get(corpusRow.id);
|
|
1257
|
+
if (visibleRowIndex === void 0) continue;
|
|
1258
|
+
keys.add(buildSearchMatchKey(colIndex, visibleRowIndex));
|
|
1259
|
+
}
|
|
1260
|
+
return keys;
|
|
1261
|
+
}
|
|
1262
|
+
function mapSearchResultToVisibleItem(item, corpus, visibleRowIndexById) {
|
|
1263
|
+
const [colIndex, corpusRowIndex] = item;
|
|
1264
|
+
const corpusRow = corpus[corpusRowIndex];
|
|
1265
|
+
if (!corpusRow) return null;
|
|
1266
|
+
const visibleRowIndex = visibleRowIndexById.get(corpusRow.id);
|
|
1267
|
+
if (visibleRowIndex === void 0) return null;
|
|
1268
|
+
return [colIndex, visibleRowIndex];
|
|
1269
|
+
}
|
|
1270
|
+
function collectAncestorKeysToExpand(corpusRow, expandedRows) {
|
|
1271
|
+
return corpusRow.ancestorToggleKeys.filter((key) => !expandedRows.has(key));
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// src/components/ui/table/features/inline-search/useInlineSearch.ts
|
|
1275
|
+
import {
|
|
1276
|
+
useCallback as useCallback3,
|
|
1277
|
+
useEffect as useEffect3,
|
|
1278
|
+
useId,
|
|
1279
|
+
useMemo,
|
|
1280
|
+
useRef as useRef3,
|
|
1281
|
+
useState as useState3
|
|
1282
|
+
} from "react";
|
|
1283
|
+
var EMPTY_MATCH_KEYS = /* @__PURE__ */ new Set();
|
|
1284
|
+
function useInlineSearch({
|
|
1285
|
+
enabled = false,
|
|
1286
|
+
rowCount,
|
|
1287
|
+
columnCount,
|
|
1288
|
+
getCellValue,
|
|
1289
|
+
initialStartRow = 0,
|
|
1290
|
+
showSearch: controlledShowSearch,
|
|
1291
|
+
searchValue: controlledSearchValue,
|
|
1292
|
+
searchResults: controlledSearchResults,
|
|
1293
|
+
onSearchValueChange,
|
|
1294
|
+
onSearchClose,
|
|
1295
|
+
onSearchResultsChanged,
|
|
1296
|
+
onNavigateToResult,
|
|
1297
|
+
rootRef
|
|
1298
|
+
}) {
|
|
1299
|
+
const searchInputId = useId();
|
|
1300
|
+
const searchInputRef = useRef3(null);
|
|
1301
|
+
const [internalShowSearch, setInternalShowSearch] = useState3(false);
|
|
1302
|
+
const [internalSearchValue, setInternalSearchValue] = useState3("");
|
|
1303
|
+
const [internalResults, setInternalResults] = useState3(
|
|
1304
|
+
[]
|
|
1305
|
+
);
|
|
1306
|
+
const [searchStatus, setSearchStatus] = useState3();
|
|
1307
|
+
const searchStatusRef = useRef3(searchStatus);
|
|
1308
|
+
searchStatusRef.current = searchStatus;
|
|
1309
|
+
const abortControllerRef = useRef3(null);
|
|
1310
|
+
const searchHandleRef = useRef3(void 0);
|
|
1311
|
+
const initialStartRowRef = useRef3(initialStartRow);
|
|
1312
|
+
initialStartRowRef.current = initialStartRow;
|
|
1313
|
+
const getCellValueRef = useRef3(getCellValue);
|
|
1314
|
+
getCellValueRef.current = getCellValue;
|
|
1315
|
+
const showSearch = controlledShowSearch ?? internalShowSearch;
|
|
1316
|
+
const searchValue = controlledSearchValue ?? internalSearchValue;
|
|
1317
|
+
const searchResults = controlledSearchResults ?? internalResults;
|
|
1318
|
+
const setSearchValue = useCallback3(
|
|
1319
|
+
(value) => {
|
|
1320
|
+
setInternalSearchValue(value);
|
|
1321
|
+
onSearchValueChange?.(value);
|
|
1322
|
+
},
|
|
1323
|
+
[onSearchValueChange]
|
|
1324
|
+
);
|
|
1325
|
+
const cancelSearch = useCallback3(() => {
|
|
1326
|
+
if (searchHandleRef.current !== void 0) {
|
|
1327
|
+
window.cancelAnimationFrame(searchHandleRef.current);
|
|
1328
|
+
searchHandleRef.current = void 0;
|
|
1329
|
+
}
|
|
1330
|
+
abortControllerRef.current?.abort();
|
|
1331
|
+
}, []);
|
|
1332
|
+
const emitResultsChanged = useCallback3(
|
|
1333
|
+
(results, navIndex) => {
|
|
1334
|
+
onSearchResultsChanged?.(results, navIndex);
|
|
1335
|
+
},
|
|
1336
|
+
[onSearchResultsChanged]
|
|
1337
|
+
);
|
|
1338
|
+
const navigateToIndex = useCallback3(
|
|
1339
|
+
(results, navIndex) => {
|
|
1340
|
+
if (onSearchResultsChanged) return;
|
|
1341
|
+
if (navIndex < 0 || navIndex >= results.length) return;
|
|
1342
|
+
const item = results[navIndex];
|
|
1343
|
+
if (!item) return;
|
|
1344
|
+
onNavigateToResult?.(item);
|
|
1345
|
+
},
|
|
1346
|
+
[onNavigateToResult, onSearchResultsChanged]
|
|
1347
|
+
);
|
|
1348
|
+
const beginSearch = useCallback3(
|
|
1349
|
+
(query) => {
|
|
1350
|
+
if (controlledSearchResults !== void 0) return;
|
|
1351
|
+
const totalRows = rowCount;
|
|
1352
|
+
if (totalRows === 0 || columnCount === 0) {
|
|
1353
|
+
setSearchStatus(void 0);
|
|
1354
|
+
setInternalResults([]);
|
|
1355
|
+
emitResultsChanged([], -1);
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
let startY = Math.min(
|
|
1359
|
+
Math.max(0, initialStartRowRef.current),
|
|
1360
|
+
totalRows - 1
|
|
1361
|
+
);
|
|
1362
|
+
let searchStride = Math.min(INLINE_SEARCH_INITIAL_STRIDE, totalRows);
|
|
1363
|
+
let rowsSearched = 0;
|
|
1364
|
+
const runningResult = [];
|
|
1365
|
+
setSearchStatus(void 0);
|
|
1366
|
+
setInternalResults([]);
|
|
1367
|
+
const tick = () => {
|
|
1368
|
+
if (abortControllerRef.current?.signal.aborted) return;
|
|
1369
|
+
const tStart = performance.now();
|
|
1370
|
+
const rowsLeft = totalRows - rowsSearched;
|
|
1371
|
+
const height = Math.min(searchStride, rowsLeft, totalRows - startY);
|
|
1372
|
+
if (height <= 0) {
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
const chunk = collectSearchMatchesInRange({
|
|
1376
|
+
query,
|
|
1377
|
+
startRow: startY,
|
|
1378
|
+
rowCount: height,
|
|
1379
|
+
columnCount,
|
|
1380
|
+
getCellValue: (rowIndex, colIndex) => getCellValueRef.current(rowIndex, colIndex),
|
|
1381
|
+
maxResults: INLINE_SEARCH_MAX_RESULTS - runningResult.length
|
|
1382
|
+
});
|
|
1383
|
+
if (chunk.length > 0) {
|
|
1384
|
+
runningResult.push(...chunk);
|
|
1385
|
+
setInternalResults([...runningResult]);
|
|
1386
|
+
}
|
|
1387
|
+
rowsSearched += height;
|
|
1388
|
+
const selectedIndex = searchStatusRef.current?.selectedIndex ?? -1;
|
|
1389
|
+
setSearchStatus({
|
|
1390
|
+
results: runningResult.length,
|
|
1391
|
+
rowsSearched,
|
|
1392
|
+
selectedIndex
|
|
1393
|
+
});
|
|
1394
|
+
emitResultsChanged(runningResult, selectedIndex);
|
|
1395
|
+
if (startY + height >= totalRows) {
|
|
1396
|
+
startY = 0;
|
|
1397
|
+
} else {
|
|
1398
|
+
startY += height;
|
|
1399
|
+
}
|
|
1400
|
+
searchStride = nextSearchStride(
|
|
1401
|
+
searchStride,
|
|
1402
|
+
performance.now() - tStart
|
|
1403
|
+
);
|
|
1404
|
+
if (rowsSearched < totalRows && runningResult.length < INLINE_SEARCH_MAX_RESULTS) {
|
|
1405
|
+
searchHandleRef.current = window.requestAnimationFrame(tick);
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
cancelSearch();
|
|
1409
|
+
abortControllerRef.current = new AbortController();
|
|
1410
|
+
searchHandleRef.current = window.requestAnimationFrame(tick);
|
|
1411
|
+
},
|
|
1412
|
+
[
|
|
1413
|
+
cancelSearch,
|
|
1414
|
+
columnCount,
|
|
1415
|
+
controlledSearchResults,
|
|
1416
|
+
emitResultsChanged,
|
|
1417
|
+
rowCount
|
|
1418
|
+
]
|
|
1419
|
+
);
|
|
1420
|
+
const openSearch = useCallback3(() => {
|
|
1421
|
+
if (controlledShowSearch === void 0) {
|
|
1422
|
+
setInternalShowSearch(true);
|
|
1423
|
+
}
|
|
1424
|
+
}, [controlledShowSearch]);
|
|
1425
|
+
const closeSearch = useCallback3(() => {
|
|
1426
|
+
if (controlledShowSearch === void 0) {
|
|
1427
|
+
setInternalShowSearch(false);
|
|
1428
|
+
}
|
|
1429
|
+
onSearchClose?.();
|
|
1430
|
+
setSearchStatus(void 0);
|
|
1431
|
+
setInternalResults([]);
|
|
1432
|
+
emitResultsChanged([], -1);
|
|
1433
|
+
cancelSearch();
|
|
1434
|
+
}, [
|
|
1435
|
+
cancelSearch,
|
|
1436
|
+
controlledShowSearch,
|
|
1437
|
+
emitResultsChanged,
|
|
1438
|
+
onSearchClose
|
|
1439
|
+
]);
|
|
1440
|
+
const goToNext = useCallback3(() => {
|
|
1441
|
+
if (!searchStatus || searchStatus.results === 0) return;
|
|
1442
|
+
const newIndex = nextSearchIndex(
|
|
1443
|
+
searchStatus.selectedIndex,
|
|
1444
|
+
searchStatus.results
|
|
1445
|
+
);
|
|
1446
|
+
setSearchStatus({ ...searchStatus, selectedIndex: newIndex });
|
|
1447
|
+
emitResultsChanged(searchResults, newIndex);
|
|
1448
|
+
navigateToIndex(searchResults, newIndex);
|
|
1449
|
+
}, [emitResultsChanged, navigateToIndex, searchResults, searchStatus]);
|
|
1450
|
+
const goToPrevious = useCallback3(() => {
|
|
1451
|
+
if (!searchStatus || searchStatus.results === 0) return;
|
|
1452
|
+
const newIndex = previousSearchIndex(
|
|
1453
|
+
searchStatus.selectedIndex,
|
|
1454
|
+
searchStatus.results
|
|
1455
|
+
);
|
|
1456
|
+
setSearchStatus({ ...searchStatus, selectedIndex: newIndex });
|
|
1457
|
+
emitResultsChanged(searchResults, newIndex);
|
|
1458
|
+
navigateToIndex(searchResults, newIndex);
|
|
1459
|
+
}, [emitResultsChanged, navigateToIndex, searchResults, searchStatus]);
|
|
1460
|
+
useEffect3(() => {
|
|
1461
|
+
if (controlledSearchResults === void 0) return;
|
|
1462
|
+
if (controlledSearchResults.length > 0) {
|
|
1463
|
+
setSearchStatus((current) => ({
|
|
1464
|
+
rowsSearched: rowCount,
|
|
1465
|
+
results: controlledSearchResults.length,
|
|
1466
|
+
selectedIndex: current?.selectedIndex ?? -1
|
|
1467
|
+
}));
|
|
1468
|
+
} else {
|
|
1469
|
+
setSearchStatus(void 0);
|
|
1470
|
+
}
|
|
1471
|
+
}, [controlledSearchResults, rowCount]);
|
|
1472
|
+
useEffect3(() => {
|
|
1473
|
+
if (!enabled) return;
|
|
1474
|
+
setSearchStatus(void 0);
|
|
1475
|
+
setInternalResults([]);
|
|
1476
|
+
emitResultsChanged([], -1);
|
|
1477
|
+
if (showSearch) {
|
|
1478
|
+
queueMicrotask(() => {
|
|
1479
|
+
searchInputRef.current?.focus({ preventScroll: true });
|
|
1480
|
+
});
|
|
1481
|
+
} else {
|
|
1482
|
+
cancelSearch();
|
|
1483
|
+
}
|
|
1484
|
+
}, [enabled, showSearch]);
|
|
1485
|
+
useEffect3(() => {
|
|
1486
|
+
if (!enabled || !showSearch) return;
|
|
1487
|
+
if (controlledSearchResults !== void 0) return;
|
|
1488
|
+
if (searchValue.trim() === "") {
|
|
1489
|
+
setSearchStatus(void 0);
|
|
1490
|
+
setInternalResults([]);
|
|
1491
|
+
cancelSearch();
|
|
1492
|
+
emitResultsChanged([], -1);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
beginSearch(searchValue);
|
|
1496
|
+
}, [
|
|
1497
|
+
beginSearch,
|
|
1498
|
+
cancelSearch,
|
|
1499
|
+
controlledSearchResults,
|
|
1500
|
+
emitResultsChanged,
|
|
1501
|
+
enabled,
|
|
1502
|
+
searchValue,
|
|
1503
|
+
showSearch
|
|
1504
|
+
]);
|
|
1505
|
+
useEffect3(() => {
|
|
1506
|
+
if (!enabled) return;
|
|
1507
|
+
const handleKeyDown = (event) => {
|
|
1508
|
+
if (!(event.ctrlKey || event.metaKey)) return;
|
|
1509
|
+
if (event.key.toLowerCase() !== "f") return;
|
|
1510
|
+
const root = rootRef?.current;
|
|
1511
|
+
if (root) {
|
|
1512
|
+
const active = document.activeElement;
|
|
1513
|
+
const focusInside = active === root || active instanceof Node && root.contains(active);
|
|
1514
|
+
if (!focusInside && active !== document.body) {
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
event.preventDefault();
|
|
1519
|
+
event.stopPropagation();
|
|
1520
|
+
if (showSearch) {
|
|
1521
|
+
searchInputRef.current?.focus({ preventScroll: true });
|
|
1522
|
+
searchInputRef.current?.select();
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
if (controlledShowSearch === void 0) {
|
|
1526
|
+
setInternalShowSearch(true);
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
window.addEventListener("keydown", handleKeyDown, true);
|
|
1530
|
+
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
1531
|
+
}, [controlledShowSearch, enabled, rootRef, showSearch]);
|
|
1532
|
+
useEffect3(() => () => cancelSearch(), [cancelSearch]);
|
|
1533
|
+
const searchMatchKeys = useMemo(
|
|
1534
|
+
() => buildSearchMatchKeys(searchResults),
|
|
1535
|
+
[searchResults]
|
|
1536
|
+
);
|
|
1537
|
+
const activeMatch = useMemo(() => {
|
|
1538
|
+
if (!searchStatus || searchStatus.selectedIndex < 0) return null;
|
|
1539
|
+
return searchResults[searchStatus.selectedIndex] ?? null;
|
|
1540
|
+
}, [searchResults, searchStatus]);
|
|
1541
|
+
if (!enabled) {
|
|
1542
|
+
return {
|
|
1543
|
+
enabled: false,
|
|
1544
|
+
showSearch: false,
|
|
1545
|
+
searchValue: "",
|
|
1546
|
+
searchResults: [],
|
|
1547
|
+
searchStatus: void 0,
|
|
1548
|
+
searchMatchKeys: EMPTY_MATCH_KEYS,
|
|
1549
|
+
activeMatch: null,
|
|
1550
|
+
searchInputRef,
|
|
1551
|
+
searchInputId,
|
|
1552
|
+
canClose: false,
|
|
1553
|
+
openSearch,
|
|
1554
|
+
closeSearch,
|
|
1555
|
+
setSearchValue,
|
|
1556
|
+
goToNext,
|
|
1557
|
+
goToPrevious
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
return {
|
|
1561
|
+
enabled: true,
|
|
1562
|
+
showSearch,
|
|
1563
|
+
searchValue,
|
|
1564
|
+
searchResults,
|
|
1565
|
+
searchStatus,
|
|
1566
|
+
searchMatchKeys,
|
|
1567
|
+
activeMatch,
|
|
1568
|
+
searchInputRef,
|
|
1569
|
+
searchInputId,
|
|
1570
|
+
canClose: controlledShowSearch === void 0 || onSearchClose !== void 0,
|
|
1571
|
+
openSearch,
|
|
1572
|
+
closeSearch,
|
|
1573
|
+
setSearchValue,
|
|
1574
|
+
goToNext,
|
|
1575
|
+
goToPrevious
|
|
1015
1576
|
};
|
|
1016
1577
|
}
|
|
1017
1578
|
|
|
1018
1579
|
// src/components/ui/table/features/row-expand/row-expand.ts
|
|
1019
|
-
import { useEffect as
|
|
1580
|
+
import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4 } from "react";
|
|
1020
1581
|
function getFieldValue(row, key) {
|
|
1021
1582
|
return row[key];
|
|
1022
1583
|
}
|
|
@@ -1046,12 +1607,12 @@ var useConvertTreeData = ({
|
|
|
1046
1607
|
expandedRows,
|
|
1047
1608
|
onExpandedRowsChange
|
|
1048
1609
|
}) => {
|
|
1049
|
-
const onExpandedRowsChangeRef =
|
|
1050
|
-
const hasInitializedRef =
|
|
1051
|
-
|
|
1610
|
+
const onExpandedRowsChangeRef = useRef4(onExpandedRowsChange);
|
|
1611
|
+
const hasInitializedRef = useRef4(false);
|
|
1612
|
+
useEffect4(() => {
|
|
1052
1613
|
onExpandedRowsChangeRef.current = onExpandedRowsChange;
|
|
1053
1614
|
}, [onExpandedRowsChange]);
|
|
1054
|
-
|
|
1615
|
+
useEffect4(() => {
|
|
1055
1616
|
if (!data || data.length === 0) {
|
|
1056
1617
|
hasInitializedRef.current = false;
|
|
1057
1618
|
return;
|
|
@@ -1061,7 +1622,7 @@ var useConvertTreeData = ({
|
|
|
1061
1622
|
onExpandedRowsChangeRef.current?.(new Set(ids));
|
|
1062
1623
|
hasInitializedRef.current = true;
|
|
1063
1624
|
}, [enabled, data, toggleField]);
|
|
1064
|
-
const processedData =
|
|
1625
|
+
const processedData = useMemo2(() => {
|
|
1065
1626
|
if (!enabled || !data || data.length === 0) return [];
|
|
1066
1627
|
const flattenedData = [];
|
|
1067
1628
|
const flattenItems = (items) => {
|
|
@@ -1125,7 +1686,7 @@ var useConvertTreeData = ({
|
|
|
1125
1686
|
});
|
|
1126
1687
|
return rootItems;
|
|
1127
1688
|
}, [enabled, data, toggleField, childField, flattenField]);
|
|
1128
|
-
const flattenTree =
|
|
1689
|
+
const flattenTree = useMemo2(() => {
|
|
1129
1690
|
if (!enabled) return [];
|
|
1130
1691
|
const flatten = (nodes, result = [], level = 0) => {
|
|
1131
1692
|
nodes.forEach((node, index) => {
|
|
@@ -1175,7 +1736,7 @@ var useConvertTreeData = ({
|
|
|
1175
1736
|
preventExpand,
|
|
1176
1737
|
expandedRows
|
|
1177
1738
|
]);
|
|
1178
|
-
const sortedData =
|
|
1739
|
+
const sortedData = useMemo2(() => {
|
|
1179
1740
|
if (!enabled) {
|
|
1180
1741
|
return data ?? [];
|
|
1181
1742
|
}
|
|
@@ -1281,6 +1842,7 @@ function collectRowSpanColumns(columns) {
|
|
|
1281
1842
|
|
|
1282
1843
|
// src/core/useGlideTable.ts
|
|
1283
1844
|
var EMPTY_COLUMN_FREEZE_OFFSETS = /* @__PURE__ */ new Map();
|
|
1845
|
+
var EMPTY_SEARCH_MATCH_KEYS = /* @__PURE__ */ new Set();
|
|
1284
1846
|
function useGlideTable(options) {
|
|
1285
1847
|
const {
|
|
1286
1848
|
data,
|
|
@@ -1321,9 +1883,16 @@ function useGlideTable(options) {
|
|
|
1321
1883
|
columnSizing: controlledColumnSizing,
|
|
1322
1884
|
onColumnSizingChange,
|
|
1323
1885
|
columnResizeMode = "onChange",
|
|
1324
|
-
enableColumnFreeze = false
|
|
1886
|
+
enableColumnFreeze = false,
|
|
1887
|
+
enableInlineSearch = false,
|
|
1888
|
+
showSearch,
|
|
1889
|
+
searchValue,
|
|
1890
|
+
onSearchValueChange,
|
|
1891
|
+
onSearchClose,
|
|
1892
|
+
searchResults,
|
|
1893
|
+
onSearchResultsChanged
|
|
1325
1894
|
} = options;
|
|
1326
|
-
const labels =
|
|
1895
|
+
const labels = useMemo3(() => {
|
|
1327
1896
|
const resolved = resolveDataTableLabels(labelsProp);
|
|
1328
1897
|
return {
|
|
1329
1898
|
...resolved,
|
|
@@ -1334,15 +1903,16 @@ function useGlideTable(options) {
|
|
|
1334
1903
|
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
1335
1904
|
const enableExpand = Boolean(toggleField);
|
|
1336
1905
|
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
1337
|
-
const [internalRowSelection, setInternalRowSelection] =
|
|
1338
|
-
const [internalColumnSizing, setInternalColumnSizing] =
|
|
1339
|
-
const [internalExpandedRows, setInternalExpandedRows] =
|
|
1906
|
+
const [internalRowSelection, setInternalRowSelection] = useState4({});
|
|
1907
|
+
const [internalColumnSizing, setInternalColumnSizing] = useState4({});
|
|
1908
|
+
const [internalExpandedRows, setInternalExpandedRows] = useState4(
|
|
1340
1909
|
() => /* @__PURE__ */ new Set()
|
|
1341
1910
|
);
|
|
1342
|
-
const [hoveredRowIndex, setHoveredRowIndex] =
|
|
1343
|
-
const scrollRef =
|
|
1911
|
+
const [hoveredRowIndex, setHoveredRowIndex] = useState4(null);
|
|
1912
|
+
const scrollRef = useRef5(null);
|
|
1913
|
+
const rootRef = useRef5(null);
|
|
1344
1914
|
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
1345
|
-
|
|
1915
|
+
useEffect5(() => {
|
|
1346
1916
|
if (enableVirtualization && enableRowSpan) {
|
|
1347
1917
|
console.warn(
|
|
1348
1918
|
"[useGlideTable] enableRowSpan is on; virtualization is disabled to preserve cell merges."
|
|
@@ -1356,7 +1926,7 @@ function useGlideTable(options) {
|
|
|
1356
1926
|
);
|
|
1357
1927
|
const columnSizing = controlledColumnSizing ?? internalColumnSizing;
|
|
1358
1928
|
const expandedRows = controlledExpandedRows ?? internalExpandedRows;
|
|
1359
|
-
const handleExpandedRowsChange =
|
|
1929
|
+
const handleExpandedRowsChange = useCallback4(
|
|
1360
1930
|
(next) => {
|
|
1361
1931
|
if (onExpandedRowsChange) {
|
|
1362
1932
|
onExpandedRowsChange(next);
|
|
@@ -1417,13 +1987,13 @@ function useGlideTable(options) {
|
|
|
1417
1987
|
getCoreRowModel: getCoreRowModel(),
|
|
1418
1988
|
getRowId: getRowId ? (originalRow, index) => getRowId(originalRow, index) : (_originalRow, index) => String(index)
|
|
1419
1989
|
});
|
|
1420
|
-
const rowSpanColumnKeys =
|
|
1990
|
+
const rowSpanColumnKeys = useMemo3(() => {
|
|
1421
1991
|
if (!enableRowSpan) return [];
|
|
1422
1992
|
return collectRowSpanColumns(columns);
|
|
1423
1993
|
}, [enableRowSpan, columns]);
|
|
1424
1994
|
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
1425
1995
|
const primaryRowSpanColumnId = rowSpanColumnKeys[0]?.columnId;
|
|
1426
|
-
const columnRowSpanMap =
|
|
1996
|
+
const columnRowSpanMap = useMemo3(
|
|
1427
1997
|
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
1428
1998
|
[tableData, rowSpanColumnKeys]
|
|
1429
1999
|
);
|
|
@@ -1432,7 +2002,7 @@ function useGlideTable(options) {
|
|
|
1432
2002
|
const rows = table.getRowModel().rows;
|
|
1433
2003
|
const columnCount = table.getAllLeafColumns().length || 1;
|
|
1434
2004
|
const visibleLeafColumns = table.getVisibleLeafColumns();
|
|
1435
|
-
const columnFreezeOffsets =
|
|
2005
|
+
const columnFreezeOffsets = useMemo3(() => {
|
|
1436
2006
|
if (!enableColumnFreeze) return EMPTY_COLUMN_FREEZE_OFFSETS;
|
|
1437
2007
|
return buildColumnFreezeOffsets(
|
|
1438
2008
|
visibleLeafColumns.map((column) => ({
|
|
@@ -1452,13 +2022,46 @@ function useGlideTable(options) {
|
|
|
1452
2022
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
1453
2023
|
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
1454
2024
|
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
1455
|
-
const selectedRowIndices =
|
|
2025
|
+
const selectedRowIndices = useMemo3(() => {
|
|
1456
2026
|
const indices = /* @__PURE__ */ new Set();
|
|
1457
2027
|
for (const selectedRow of selectedRows) {
|
|
1458
2028
|
indices.add(selectedRow.index);
|
|
1459
2029
|
}
|
|
1460
2030
|
return indices;
|
|
1461
2031
|
}, [selectedRows]);
|
|
2032
|
+
const scrollCellIntoView = useCallback4(
|
|
2033
|
+
(rowIndex, colIndex, options2) => {
|
|
2034
|
+
const align = options2?.align ?? "nearest";
|
|
2035
|
+
const blockAlign = align === "center" ? "center" : "nearest";
|
|
2036
|
+
if (shouldVirtualize) {
|
|
2037
|
+
rowVirtualizer.scrollToIndex(rowIndex, {
|
|
2038
|
+
align: align === "nearest" ? "auto" : align
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
const scrollElement = scrollRef.current;
|
|
2042
|
+
if (!scrollElement) return;
|
|
2043
|
+
const scrollToMatchedCell = () => {
|
|
2044
|
+
const cell = scrollElement.querySelector(
|
|
2045
|
+
`[data-row-index="${rowIndex}"][data-col-index="${colIndex}"]`
|
|
2046
|
+
);
|
|
2047
|
+
if (cell instanceof HTMLElement) {
|
|
2048
|
+
cell.scrollIntoView({ block: blockAlign, inline: "nearest" });
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
if (shouldVirtualize) {
|
|
2052
|
+
requestAnimationFrame(scrollToMatchedCell);
|
|
2053
|
+
return;
|
|
2054
|
+
}
|
|
2055
|
+
scrollToMatchedCell();
|
|
2056
|
+
},
|
|
2057
|
+
[rowVirtualizer, shouldVirtualize]
|
|
2058
|
+
);
|
|
2059
|
+
const handleCellNavigate = useCallback4(
|
|
2060
|
+
(position) => {
|
|
2061
|
+
scrollCellIntoView(position.row, position.col, { align: "nearest" });
|
|
2062
|
+
},
|
|
2063
|
+
[scrollCellIntoView]
|
|
2064
|
+
);
|
|
1462
2065
|
const {
|
|
1463
2066
|
dragState,
|
|
1464
2067
|
activeSelectionBounds,
|
|
@@ -1470,11 +2073,13 @@ function useGlideTable(options) {
|
|
|
1470
2073
|
data: tableData,
|
|
1471
2074
|
rows,
|
|
1472
2075
|
enabled: enableCellSelection,
|
|
2076
|
+
columnCount: visibleLeafColumns.length,
|
|
1473
2077
|
enableSubtreeCopy: resolvedEnableSubtreeCopy,
|
|
1474
2078
|
enableInsertPaste: enableInsertPaste ?? true,
|
|
1475
2079
|
onDataChange,
|
|
1476
2080
|
onBatchChange,
|
|
1477
|
-
onRowsPaste
|
|
2081
|
+
onRowsPaste,
|
|
2082
|
+
onCellNavigate: handleCellNavigate
|
|
1478
2083
|
});
|
|
1479
2084
|
const {
|
|
1480
2085
|
editingCell,
|
|
@@ -1484,23 +2089,193 @@ function useGlideTable(options) {
|
|
|
1484
2089
|
commitEdit,
|
|
1485
2090
|
cancelEdit
|
|
1486
2091
|
} = useCellEdit({ data: tableData, rows, onDataChange, onCellChange });
|
|
1487
|
-
const handleCellMouseDownWithCommit =
|
|
1488
|
-
(rowIndex, colIndex) => {
|
|
2092
|
+
const handleCellMouseDownWithCommit = useCallback4(
|
|
2093
|
+
(rowIndex, colIndex, options2) => {
|
|
1489
2094
|
const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
|
|
1490
2095
|
if (editingCell && !isSameEditingCell && !commitEdit()) {
|
|
1491
2096
|
return;
|
|
1492
2097
|
}
|
|
1493
|
-
handleCellMouseDown(rowIndex, colIndex);
|
|
2098
|
+
handleCellMouseDown(rowIndex, colIndex, options2);
|
|
1494
2099
|
},
|
|
1495
2100
|
[commitEdit, editingCell, handleCellMouseDown]
|
|
1496
2101
|
);
|
|
1497
|
-
const
|
|
2102
|
+
const navigateToSearchResult = useCallback4(
|
|
2103
|
+
(item) => {
|
|
2104
|
+
const [colIndex, rowIndex] = item;
|
|
2105
|
+
handleCellMouseDownWithCommit(rowIndex, colIndex);
|
|
2106
|
+
scrollCellIntoView(rowIndex, colIndex, { align: "center" });
|
|
2107
|
+
},
|
|
2108
|
+
[handleCellMouseDownWithCommit, scrollCellIntoView]
|
|
2109
|
+
);
|
|
2110
|
+
const resolveSearchRowId = useCallback4(
|
|
2111
|
+
(row, index) => {
|
|
2112
|
+
if (getRowId) return getRowId(row, index);
|
|
2113
|
+
if (enableExpand) {
|
|
2114
|
+
const record = row;
|
|
2115
|
+
const idValue = record.id;
|
|
2116
|
+
if (idValue != null && String(idValue).length > 0) {
|
|
2117
|
+
return String(idValue);
|
|
2118
|
+
}
|
|
2119
|
+
const uniqueId = record.uniqueId;
|
|
2120
|
+
if (uniqueId != null && String(uniqueId).length > 0) {
|
|
2121
|
+
return String(uniqueId);
|
|
2122
|
+
}
|
|
2123
|
+
if (toggleField) {
|
|
2124
|
+
const toggleValue = record[toggleField];
|
|
2125
|
+
if (toggleValue != null && String(toggleValue).length > 0) {
|
|
2126
|
+
return String(toggleValue);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
return String(index);
|
|
2131
|
+
},
|
|
2132
|
+
[enableExpand, getRowId, toggleField]
|
|
2133
|
+
);
|
|
2134
|
+
const searchCorpus = useMemo3(() => {
|
|
2135
|
+
if (!enableInlineSearch) return [];
|
|
2136
|
+
if (enableExpand && toggleField) {
|
|
2137
|
+
return buildTreeSearchCorpus(tableData, {
|
|
2138
|
+
toggleField,
|
|
2139
|
+
getRowId: resolveSearchRowId
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
return buildFlatSearchCorpus(tableData, resolveSearchRowId);
|
|
2143
|
+
}, [
|
|
2144
|
+
enableExpand,
|
|
2145
|
+
enableInlineSearch,
|
|
2146
|
+
resolveSearchRowId,
|
|
2147
|
+
tableData,
|
|
2148
|
+
toggleField
|
|
2149
|
+
]);
|
|
2150
|
+
const searchCorpusRef = useRef5(searchCorpus);
|
|
2151
|
+
searchCorpusRef.current = searchCorpus;
|
|
2152
|
+
const visibleRowIndexById = useMemo3(() => {
|
|
2153
|
+
const map = /* @__PURE__ */ new Map();
|
|
2154
|
+
for (const row of rows) {
|
|
2155
|
+
map.set(resolveSearchRowId(row.original, row.index), row.index);
|
|
2156
|
+
}
|
|
2157
|
+
return map;
|
|
2158
|
+
}, [resolveSearchRowId, rows]);
|
|
2159
|
+
const getSearchCellValue = useCallback4(
|
|
2160
|
+
(rowIndex, colIndex) => {
|
|
2161
|
+
const corpusRow = searchCorpusRef.current[rowIndex];
|
|
2162
|
+
const column = visibleLeafColumns[colIndex];
|
|
2163
|
+
if (!corpusRow || !column) return void 0;
|
|
2164
|
+
const visibleIndex = visibleRowIndexById.get(corpusRow.id);
|
|
2165
|
+
if (visibleIndex !== void 0) {
|
|
2166
|
+
const visibleRow = rows[visibleIndex];
|
|
2167
|
+
if (visibleRow) {
|
|
2168
|
+
return visibleRow.getValue(column.id);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
const columnDef = column.columnDef;
|
|
2172
|
+
if ("accessorFn" in columnDef && typeof columnDef.accessorFn === "function") {
|
|
2173
|
+
return columnDef.accessorFn(corpusRow.data, rowIndex);
|
|
2174
|
+
}
|
|
2175
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey != null && columnDef.accessorKey !== "") {
|
|
2176
|
+
return corpusRow.data[String(columnDef.accessorKey)];
|
|
2177
|
+
}
|
|
2178
|
+
return corpusRow.data[column.id];
|
|
2179
|
+
},
|
|
2180
|
+
[rows, visibleLeafColumns, visibleRowIndexById]
|
|
2181
|
+
);
|
|
2182
|
+
const pendingSearchNavRef = useRef5(null);
|
|
2183
|
+
const focusSearchResult = useCallback4(
|
|
2184
|
+
(colIndex, visibleRowIndex) => {
|
|
2185
|
+
navigateToSearchResult([colIndex, visibleRowIndex]);
|
|
2186
|
+
},
|
|
2187
|
+
[navigateToSearchResult]
|
|
2188
|
+
);
|
|
2189
|
+
const navigateToCorpusSearchResult = useCallback4(
|
|
2190
|
+
(item) => {
|
|
2191
|
+
const [colIndex, corpusRowIndex] = item;
|
|
2192
|
+
const corpusRow = searchCorpusRef.current[corpusRowIndex];
|
|
2193
|
+
if (!corpusRow) return;
|
|
2194
|
+
const missingKeys = collectAncestorKeysToExpand(corpusRow, expandedRows);
|
|
2195
|
+
if (missingKeys.length > 0) {
|
|
2196
|
+
pendingSearchNavRef.current = {
|
|
2197
|
+
colIndex,
|
|
2198
|
+
rowId: corpusRow.id
|
|
2199
|
+
};
|
|
2200
|
+
const next = new Set(expandedRows);
|
|
2201
|
+
for (const key of corpusRow.ancestorToggleKeys) {
|
|
2202
|
+
next.add(key);
|
|
2203
|
+
}
|
|
2204
|
+
handleExpandedRowsChange(next);
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
const visibleItem = mapSearchResultToVisibleItem(
|
|
2208
|
+
item,
|
|
2209
|
+
searchCorpusRef.current,
|
|
2210
|
+
visibleRowIndexById
|
|
2211
|
+
);
|
|
2212
|
+
if (!visibleItem) return;
|
|
2213
|
+
focusSearchResult(visibleItem[0], visibleItem[1]);
|
|
2214
|
+
},
|
|
2215
|
+
[
|
|
2216
|
+
expandedRows,
|
|
2217
|
+
focusSearchResult,
|
|
2218
|
+
handleExpandedRowsChange,
|
|
2219
|
+
visibleRowIndexById
|
|
2220
|
+
]
|
|
2221
|
+
);
|
|
2222
|
+
useEffect5(() => {
|
|
2223
|
+
const pending = pendingSearchNavRef.current;
|
|
2224
|
+
if (!pending) return;
|
|
2225
|
+
const visibleRowIndex = visibleRowIndexById.get(pending.rowId);
|
|
2226
|
+
if (visibleRowIndex === void 0) return;
|
|
2227
|
+
pendingSearchNavRef.current = null;
|
|
2228
|
+
focusSearchResult(pending.colIndex, visibleRowIndex);
|
|
2229
|
+
}, [focusSearchResult, rows, visibleRowIndexById]);
|
|
2230
|
+
const initialSearchStartRow = virtualRows[0]?.index ?? 0;
|
|
2231
|
+
const inlineSearch = useInlineSearch({
|
|
2232
|
+
enabled: enableInlineSearch,
|
|
2233
|
+
rowCount: searchCorpus.length,
|
|
2234
|
+
columnCount: visibleLeafColumns.length,
|
|
2235
|
+
getCellValue: getSearchCellValue,
|
|
2236
|
+
initialStartRow: initialSearchStartRow,
|
|
2237
|
+
showSearch,
|
|
2238
|
+
searchValue,
|
|
2239
|
+
searchResults,
|
|
2240
|
+
onSearchValueChange,
|
|
2241
|
+
onSearchClose,
|
|
2242
|
+
onSearchResultsChanged,
|
|
2243
|
+
onNavigateToResult: navigateToCorpusSearchResult,
|
|
2244
|
+
rootRef
|
|
2245
|
+
});
|
|
2246
|
+
const visibleSearchMatchKeys = useMemo3(() => {
|
|
2247
|
+
if (!enableInlineSearch) return EMPTY_SEARCH_MATCH_KEYS;
|
|
2248
|
+
return mapSearchResultsToVisibleKeys(
|
|
2249
|
+
inlineSearch.searchResults,
|
|
2250
|
+
searchCorpus,
|
|
2251
|
+
visibleRowIndexById
|
|
2252
|
+
);
|
|
2253
|
+
}, [
|
|
2254
|
+
enableInlineSearch,
|
|
2255
|
+
inlineSearch.searchResults,
|
|
2256
|
+
searchCorpus,
|
|
2257
|
+
visibleRowIndexById
|
|
2258
|
+
]);
|
|
2259
|
+
const visibleActiveMatch = useMemo3(() => {
|
|
2260
|
+
if (!enableInlineSearch || !inlineSearch.activeMatch) return null;
|
|
2261
|
+
return mapSearchResultToVisibleItem(
|
|
2262
|
+
inlineSearch.activeMatch,
|
|
2263
|
+
searchCorpus,
|
|
2264
|
+
visibleRowIndexById
|
|
2265
|
+
);
|
|
2266
|
+
}, [
|
|
2267
|
+
enableInlineSearch,
|
|
2268
|
+
inlineSearch.activeMatch,
|
|
2269
|
+
searchCorpus,
|
|
2270
|
+
visibleRowIndexById
|
|
2271
|
+
]);
|
|
2272
|
+
const clearHover = useCallback4(() => {
|
|
1498
2273
|
setHoveredRowIndex(null);
|
|
1499
2274
|
}, []);
|
|
1500
|
-
const handleRowHover =
|
|
2275
|
+
const handleRowHover = useCallback4((rowIndex, _rowData) => {
|
|
1501
2276
|
setHoveredRowIndex(rowIndex);
|
|
1502
2277
|
}, []);
|
|
1503
|
-
const handleToggleSelect =
|
|
2278
|
+
const handleToggleSelect = useCallback4(
|
|
1504
2279
|
(row) => {
|
|
1505
2280
|
if (!row.getCanSelect()) return;
|
|
1506
2281
|
if (preserveRowSelection && row.getIsSelected()) {
|
|
@@ -1510,14 +2285,14 @@ function useGlideTable(options) {
|
|
|
1510
2285
|
},
|
|
1511
2286
|
[preserveRowSelection]
|
|
1512
2287
|
);
|
|
1513
|
-
const handleToggleExpand =
|
|
2288
|
+
const handleToggleExpand = useCallback4(
|
|
1514
2289
|
(rowKey) => {
|
|
1515
2290
|
if (preventExpand) return;
|
|
1516
2291
|
handleExpandedRowsChange(toggleExpandedRowId(rowKey, expandedRows));
|
|
1517
2292
|
},
|
|
1518
2293
|
[preventExpand, handleExpandedRowsChange, expandedRows]
|
|
1519
2294
|
);
|
|
1520
|
-
const rowContextValue =
|
|
2295
|
+
const rowContextValue = useMemo3(() => {
|
|
1521
2296
|
return {
|
|
1522
2297
|
rowSpan: {
|
|
1523
2298
|
enableRowSpan,
|
|
@@ -1565,6 +2340,11 @@ function useGlideTable(options) {
|
|
|
1565
2340
|
columnFreeze: {
|
|
1566
2341
|
enableColumnFreeze,
|
|
1567
2342
|
offsets: columnFreezeOffsets
|
|
2343
|
+
},
|
|
2344
|
+
inlineSearch: {
|
|
2345
|
+
enabled: enableInlineSearch,
|
|
2346
|
+
matchKeys: visibleSearchMatchKeys,
|
|
2347
|
+
activeMatch: visibleActiveMatch
|
|
1568
2348
|
}
|
|
1569
2349
|
};
|
|
1570
2350
|
}, [
|
|
@@ -1600,14 +2380,17 @@ function useGlideTable(options) {
|
|
|
1600
2380
|
labels.collapseRow,
|
|
1601
2381
|
enableColumnResize,
|
|
1602
2382
|
enableColumnFreeze,
|
|
1603
|
-
columnFreezeOffsets
|
|
2383
|
+
columnFreezeOffsets,
|
|
2384
|
+
enableInlineSearch,
|
|
2385
|
+
visibleSearchMatchKeys,
|
|
2386
|
+
visibleActiveMatch
|
|
1604
2387
|
]);
|
|
1605
|
-
const copySelectionRef =
|
|
1606
|
-
|
|
2388
|
+
const copySelectionRef = useRef5(copySelection);
|
|
2389
|
+
useEffect5(() => {
|
|
1607
2390
|
copySelectionRef.current = copySelection;
|
|
1608
2391
|
}, [copySelection]);
|
|
1609
|
-
const stableCopySelection =
|
|
1610
|
-
|
|
2392
|
+
const stableCopySelection = useCallback4((options2) => copySelectionRef.current(options2), []);
|
|
2393
|
+
useEffect5(() => {
|
|
1611
2394
|
onCopyActionsReady?.({ copySelection: stableCopySelection });
|
|
1612
2395
|
}, [onCopyActionsReady, stableCopySelection]);
|
|
1613
2396
|
return {
|
|
@@ -1623,8 +2406,10 @@ function useGlideTable(options) {
|
|
|
1623
2406
|
enableCellSelection,
|
|
1624
2407
|
enableColumnResize,
|
|
1625
2408
|
enableColumnFreeze,
|
|
2409
|
+
enableInlineSearch,
|
|
1626
2410
|
shouldVirtualize,
|
|
1627
2411
|
scrollRef,
|
|
2412
|
+
rootRef,
|
|
1628
2413
|
rowVirtualizer,
|
|
1629
2414
|
virtualRows,
|
|
1630
2415
|
paddingTop,
|
|
@@ -1632,7 +2417,21 @@ function useGlideTable(options) {
|
|
|
1632
2417
|
rowContextValue,
|
|
1633
2418
|
handleToggleSelect,
|
|
1634
2419
|
clearHover,
|
|
1635
|
-
copySelection: stableCopySelection
|
|
2420
|
+
copySelection: stableCopySelection,
|
|
2421
|
+
inlineSearch: {
|
|
2422
|
+
showSearch: inlineSearch.showSearch,
|
|
2423
|
+
searchValue: inlineSearch.searchValue,
|
|
2424
|
+
searchStatus: inlineSearch.searchStatus,
|
|
2425
|
+
searchInputRef: inlineSearch.searchInputRef,
|
|
2426
|
+
searchInputId: inlineSearch.searchInputId,
|
|
2427
|
+
canClose: inlineSearch.canClose,
|
|
2428
|
+
searchRowCount: searchCorpus.length,
|
|
2429
|
+
setSearchValue: inlineSearch.setSearchValue,
|
|
2430
|
+
closeSearch: inlineSearch.closeSearch,
|
|
2431
|
+
goToNext: inlineSearch.goToNext,
|
|
2432
|
+
goToPrevious: inlineSearch.goToPrevious,
|
|
2433
|
+
openSearch: inlineSearch.openSearch
|
|
2434
|
+
}
|
|
1636
2435
|
};
|
|
1637
2436
|
}
|
|
1638
2437
|
|
|
@@ -1655,18 +2454,29 @@ export {
|
|
|
1655
2454
|
DEFAULT_TREE_ID_FIELD,
|
|
1656
2455
|
DEFAULT_TREE_PARENT_ID_FIELD,
|
|
1657
2456
|
DEFAULT_TREE_QTY_FIELD,
|
|
2457
|
+
INLINE_SEARCH_MAX_RESULTS,
|
|
1658
2458
|
applyCellEdit,
|
|
1659
2459
|
applyFillData,
|
|
1660
2460
|
applySelectionUpdater,
|
|
1661
2461
|
buildColumnFreezeOffsets,
|
|
1662
2462
|
buildColumnRowSpanMap,
|
|
2463
|
+
buildFlatSearchCorpus,
|
|
1663
2464
|
buildRowsPastePayload,
|
|
2465
|
+
buildSearchMatchKey,
|
|
2466
|
+
buildSearchMatchKeys,
|
|
2467
|
+
buildTreeSearchCorpus,
|
|
1664
2468
|
canExpandRow,
|
|
2469
|
+
cellValueToSearchText,
|
|
2470
|
+
collectAncestorKeysToExpand,
|
|
1665
2471
|
collectCopyRowEntries,
|
|
1666
2472
|
collectCopyRows,
|
|
1667
2473
|
collectFillChanges,
|
|
1668
2474
|
collectRowSpanColumns,
|
|
2475
|
+
collectSearchMatchesInRange,
|
|
2476
|
+
createSearchRegex,
|
|
2477
|
+
escapeSearchRegex,
|
|
1669
2478
|
flattenSubtreeRows,
|
|
2479
|
+
formatSearchResultLabel,
|
|
1670
2480
|
getCellEditDraftValue,
|
|
1671
2481
|
getCellSelectionEdgeStyle,
|
|
1672
2482
|
getColumnEditType,
|
|
@@ -1678,10 +2488,15 @@ export {
|
|
|
1678
2488
|
isCellInSelection,
|
|
1679
2489
|
isColumnEditable,
|
|
1680
2490
|
isEditablePasteTarget,
|
|
2491
|
+
mapSearchResultToVisibleItem,
|
|
2492
|
+
mapSearchResultsToVisibleKeys,
|
|
1681
2493
|
measureMergedSpanRowHeights,
|
|
2494
|
+
nextSearchIndex,
|
|
2495
|
+
nextSearchStride,
|
|
1682
2496
|
parseCellEditValue,
|
|
1683
2497
|
parseClipboardTSV,
|
|
1684
2498
|
parseClipboardTSVWithDepths,
|
|
2499
|
+
previousSearchIndex,
|
|
1685
2500
|
resolveColumnFreezeSide,
|
|
1686
2501
|
resolveDataTableLabels,
|
|
1687
2502
|
resolvePasteColumnIds,
|
|
@@ -1695,5 +2510,6 @@ export {
|
|
|
1695
2510
|
useCellSelection,
|
|
1696
2511
|
useConvertTreeData,
|
|
1697
2512
|
useGlideTable,
|
|
2513
|
+
useInlineSearch,
|
|
1698
2514
|
writeSelectionToClipboard
|
|
1699
2515
|
};
|