@ornery/ui-grid-react 0.1.4
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/CLAUDE.md +283 -0
- package/demo/index.html +16 -0
- package/demo/main.tsx +95 -0
- package/demo/vite.config.ts +13 -0
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +2020 -0
- package/dist/index.mjs +2050 -0
- package/package.json +41 -0
- package/src/UiGrid.test.tsx +370 -0
- package/src/UiGrid.tsx +440 -0
- package/src/index.ts +23 -0
- package/src/ui-grid.css +521 -0
- package/src/useGridState.ts +1414 -0
- package/src/useVirtualScroll.ts +44 -0
- package/tsconfig.json +14 -0
- package/vitest.config.ts +14 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2050 @@
|
|
|
1
|
+
// src/useGridState.ts
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
createGridApi,
|
|
5
|
+
getCellValue as getCellValue2,
|
|
6
|
+
setPathValue,
|
|
7
|
+
SORT_DIRECTIONS as SORT_DIRECTIONS2,
|
|
8
|
+
buildGridPipeline,
|
|
9
|
+
resolveGridLabels,
|
|
10
|
+
gridColumnWidth,
|
|
11
|
+
headerLabel as coreHeaderLabel,
|
|
12
|
+
gridSortButtonLabel,
|
|
13
|
+
gridSortAriaSort,
|
|
14
|
+
gridGroupingButtonLabel,
|
|
15
|
+
gridFilterPlaceholder,
|
|
16
|
+
gridGroupDisclosureLabel,
|
|
17
|
+
gridEditorInputType,
|
|
18
|
+
gridCellIndent,
|
|
19
|
+
gridTreeToggleLabelForRow,
|
|
20
|
+
gridExpandToggleLabelForRow,
|
|
21
|
+
isGridTreeRowExpanded,
|
|
22
|
+
isGridColumnSortable,
|
|
23
|
+
isGridColumnFilterable,
|
|
24
|
+
isGridColumnGrouped,
|
|
25
|
+
isGridGroupingEnabled,
|
|
26
|
+
isGridFilteringEnabled,
|
|
27
|
+
shouldShowGridTreeToggle,
|
|
28
|
+
shouldShowGridExpandToggle,
|
|
29
|
+
shouldShowGridPaginationControls,
|
|
30
|
+
buildGridCellContext,
|
|
31
|
+
formatGridCellDisplayValue,
|
|
32
|
+
buildGridFocusCellResult,
|
|
33
|
+
findNextGridCell,
|
|
34
|
+
isPrintableGridKey,
|
|
35
|
+
isGridCellPosition,
|
|
36
|
+
exportCsvRows,
|
|
37
|
+
buildGridRows,
|
|
38
|
+
resolveGridRowId as coreResolveGridRowId,
|
|
39
|
+
findGridRowById as coreFindGridRowById,
|
|
40
|
+
getEffectivePageSize as coreGetEffectivePageSize,
|
|
41
|
+
getCurrentPageValue as coreGetCurrentPageValue,
|
|
42
|
+
getTotalPagesValue as coreGetTotalPagesValue,
|
|
43
|
+
getFirstRowIndexValue as coreGetFirstRowIndexValue,
|
|
44
|
+
getLastRowIndexValue as coreGetLastRowIndexValue,
|
|
45
|
+
buildGridSavedState,
|
|
46
|
+
sanitizeDownloadFilename,
|
|
47
|
+
parseGridEditedValue,
|
|
48
|
+
canGridExpandRows,
|
|
49
|
+
areAllGridRowsExpanded,
|
|
50
|
+
addGridRowInvisibleReason,
|
|
51
|
+
clearGridRowInvisibleReason,
|
|
52
|
+
FEATURE_SORTING,
|
|
53
|
+
FEATURE_FILTERING,
|
|
54
|
+
FEATURE_GROUPING,
|
|
55
|
+
FEATURE_PAGINATION,
|
|
56
|
+
FEATURE_CELL_EDIT,
|
|
57
|
+
FEATURE_EXPANDABLE,
|
|
58
|
+
FEATURE_TREE_VIEW,
|
|
59
|
+
FEATURE_INFINITE_SCROLL,
|
|
60
|
+
FEATURE_COLUMN_MOVING,
|
|
61
|
+
FEATURE_CSV_EXPORT,
|
|
62
|
+
FEATURE_AUTO_RESIZE
|
|
63
|
+
} from "@ornery/ui-grid";
|
|
64
|
+
|
|
65
|
+
// ../ui-grid/src/lib/grid/grid.core.pagination.ts
|
|
66
|
+
function seekGridPage(page, totalPages) {
|
|
67
|
+
return Math.min(Math.max(page, 1), Math.max(totalPages, 1));
|
|
68
|
+
}
|
|
69
|
+
function resolveGridPageSize(pageSize) {
|
|
70
|
+
return Number.isFinite(pageSize) && pageSize > 0 ? pageSize : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ../ui-grid/src/lib/grid/grid.constants.ts
|
|
74
|
+
var SORT_DIRECTIONS = {
|
|
75
|
+
asc: "asc",
|
|
76
|
+
desc: "desc",
|
|
77
|
+
none: "none"
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// ../ui-grid/src/lib/grid/grid.utils.ts
|
|
81
|
+
var PROTECTED_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
82
|
+
function getPathValue(record, path) {
|
|
83
|
+
return path.split(".").reduce((current, part) => {
|
|
84
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
if (PROTECTED_PATH_SEGMENTS.has(part)) {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
if (!Object.prototype.hasOwnProperty.call(current, part)) {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
return current[part];
|
|
94
|
+
}, record);
|
|
95
|
+
}
|
|
96
|
+
function getCellValue(row, column) {
|
|
97
|
+
if (column.valueGetter) {
|
|
98
|
+
return column.valueGetter(row);
|
|
99
|
+
}
|
|
100
|
+
if (column.field) {
|
|
101
|
+
return getPathValue(row, column.field);
|
|
102
|
+
}
|
|
103
|
+
return row[column.name];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ../ui-grid/src/lib/grid/grid.core.identity.ts
|
|
107
|
+
function buildGridSortState(columnName, direction) {
|
|
108
|
+
return {
|
|
109
|
+
columnName,
|
|
110
|
+
direction: direction ?? SORT_DIRECTIONS.asc
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ../ui-grid/src/lib/grid/grid.core.edit.ts
|
|
115
|
+
function beginGridEditSession(rowId, columnName, editingValue) {
|
|
116
|
+
const position = { rowId, columnName };
|
|
117
|
+
return {
|
|
118
|
+
focusedCell: position,
|
|
119
|
+
editingCell: position,
|
|
120
|
+
editingValue
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function clearGridEditSession() {
|
|
124
|
+
return {
|
|
125
|
+
editingCell: null,
|
|
126
|
+
editingValue: ""
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function stringifyGridEditorValue(value) {
|
|
130
|
+
if (value instanceof Date) {
|
|
131
|
+
return value.toISOString().slice(0, 10);
|
|
132
|
+
}
|
|
133
|
+
return value === null || value === void 0 ? "" : String(value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ../ui-grid/src/lib/grid/grid.core.infinite-scroll.ts
|
|
137
|
+
function maybeRequestInfiniteScrollData(context) {
|
|
138
|
+
if (context.state.dataLoading) {
|
|
139
|
+
return { request: null, nextState: context.state };
|
|
140
|
+
}
|
|
141
|
+
if (context.state.scrollUp && context.startIndex <= context.threshold) {
|
|
142
|
+
return {
|
|
143
|
+
request: "top",
|
|
144
|
+
nextState: {
|
|
145
|
+
...context.state,
|
|
146
|
+
dataLoading: true,
|
|
147
|
+
previousVisibleRows: context.visibleRows
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (context.state.scrollDown && context.startIndex + context.viewportRows >= Math.max(context.visibleRows - context.threshold, 0)) {
|
|
152
|
+
return {
|
|
153
|
+
request: "bottom",
|
|
154
|
+
nextState: {
|
|
155
|
+
...context.state,
|
|
156
|
+
dataLoading: true,
|
|
157
|
+
previousVisibleRows: context.visibleRows
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return { request: null, nextState: context.state };
|
|
162
|
+
}
|
|
163
|
+
function completeInfiniteScrollDataLoad(state, scrollUp, scrollDown) {
|
|
164
|
+
return {
|
|
165
|
+
...state,
|
|
166
|
+
scrollUp,
|
|
167
|
+
scrollDown,
|
|
168
|
+
dataLoading: false
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function resetInfiniteScrollState(scrollUp, scrollDown) {
|
|
172
|
+
return {
|
|
173
|
+
scrollUp,
|
|
174
|
+
scrollDown,
|
|
175
|
+
dataLoading: false,
|
|
176
|
+
previousVisibleRows: 0
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function saveInfiniteScrollPercentage(state, visibleRows) {
|
|
180
|
+
return {
|
|
181
|
+
...state,
|
|
182
|
+
previousVisibleRows: visibleRows
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function setInfiniteScrollDirectionsState(state, scrollUp, scrollDown) {
|
|
186
|
+
return {
|
|
187
|
+
...state,
|
|
188
|
+
scrollUp,
|
|
189
|
+
scrollDown
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ../ui-grid/src/lib/grid/grid.core.row-state.ts
|
|
194
|
+
function toggleGridRowExpanded(expandedRows, rowId) {
|
|
195
|
+
const expanded = !expandedRows[rowId];
|
|
196
|
+
return {
|
|
197
|
+
expanded,
|
|
198
|
+
nextExpandedRows: {
|
|
199
|
+
...expandedRows,
|
|
200
|
+
[rowId]: expanded
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function expandAllGridRows(rows) {
|
|
205
|
+
const nextExpandedRows = {};
|
|
206
|
+
for (const row of rows) {
|
|
207
|
+
nextExpandedRows[row.id] = true;
|
|
208
|
+
}
|
|
209
|
+
return nextExpandedRows;
|
|
210
|
+
}
|
|
211
|
+
function setGridTreeRowExpanded(expandedTreeRows, rowId, expanded) {
|
|
212
|
+
return {
|
|
213
|
+
...expandedTreeRows,
|
|
214
|
+
[rowId]: expanded
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function toggleGridTreeRowExpanded(expandedTreeRows, rowId) {
|
|
218
|
+
const expanded = !expandedTreeRows[rowId];
|
|
219
|
+
return {
|
|
220
|
+
expanded,
|
|
221
|
+
nextExpandedTreeRows: setGridTreeRowExpanded(expandedTreeRows, rowId, expanded)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function expandAllGridTreeRows(rows) {
|
|
225
|
+
const nextExpandedTreeRows = {};
|
|
226
|
+
for (const row of rows) {
|
|
227
|
+
if (row.hasChildren) {
|
|
228
|
+
nextExpandedTreeRows[row.id] = true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return nextExpandedTreeRows;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ../ui-grid/src/lib/grid/grid.core.state.ts
|
|
235
|
+
function normalizeGridSavedState(state) {
|
|
236
|
+
const normalized = {};
|
|
237
|
+
if (Array.isArray(state.columnOrder)) {
|
|
238
|
+
normalized.columnOrder = state.columnOrder.filter(
|
|
239
|
+
(columnName) => typeof columnName === "string" && isSafeStateKey(columnName)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
if (state.filters && typeof state.filters === "object") {
|
|
243
|
+
normalized.filters = Object.entries(state.filters).reduce((accumulator, [key, value]) => {
|
|
244
|
+
if (typeof key === "string" && isSafeStateKey(key) && typeof value === "string") {
|
|
245
|
+
accumulator[key] = value;
|
|
246
|
+
}
|
|
247
|
+
return accumulator;
|
|
248
|
+
}, {});
|
|
249
|
+
}
|
|
250
|
+
if (state.sort && typeof state.sort === "object") {
|
|
251
|
+
normalized.sort = {
|
|
252
|
+
columnName: typeof state.sort.columnName === "string" && isSafeStateKey(state.sort.columnName) ? state.sort.columnName : null,
|
|
253
|
+
direction: state.sort.direction === SORT_DIRECTIONS.asc || state.sort.direction === SORT_DIRECTIONS.desc ? state.sort.direction : SORT_DIRECTIONS.none
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (Array.isArray(state.grouping)) {
|
|
257
|
+
normalized.grouping = state.grouping.filter(
|
|
258
|
+
(columnName) => typeof columnName === "string" && isSafeStateKey(columnName)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
if (state.pagination && typeof state.pagination === "object") {
|
|
262
|
+
const paginationCurrentPage = Number(state.pagination.paginationCurrentPage);
|
|
263
|
+
const paginationPageSize = Number(state.pagination.paginationPageSize);
|
|
264
|
+
normalized.pagination = {
|
|
265
|
+
paginationCurrentPage: Number.isFinite(paginationCurrentPage) && paginationCurrentPage > 0 ? Math.floor(paginationCurrentPage) : 1,
|
|
266
|
+
paginationPageSize: Number.isFinite(paginationPageSize) && paginationPageSize >= 0 ? Math.floor(paginationPageSize) : 0
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (state.expandable && typeof state.expandable === "object") {
|
|
270
|
+
normalized.expandable = normalizeBooleanMap(state.expandable);
|
|
271
|
+
}
|
|
272
|
+
if (state.treeView && typeof state.treeView === "object") {
|
|
273
|
+
normalized.treeView = normalizeBooleanMap(state.treeView);
|
|
274
|
+
}
|
|
275
|
+
return normalized;
|
|
276
|
+
}
|
|
277
|
+
function normalizeBooleanMap(value) {
|
|
278
|
+
return Object.entries(value).reduce((accumulator, [key, entry]) => {
|
|
279
|
+
if (typeof key === "string" && isSafeStateKey(key) && typeof entry === "boolean") {
|
|
280
|
+
accumulator[key] = entry;
|
|
281
|
+
}
|
|
282
|
+
return accumulator;
|
|
283
|
+
}, {});
|
|
284
|
+
}
|
|
285
|
+
function isSafeStateKey(value) {
|
|
286
|
+
return value !== "__proto__" && value !== "constructor" && value !== "prototype";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ../ui-grid/src/lib/grid/ui-grid.events.ts
|
|
290
|
+
function raiseGridRenderingComplete(gridApi) {
|
|
291
|
+
gridApi.core.raise.renderingComplete(gridApi);
|
|
292
|
+
}
|
|
293
|
+
function raiseGridRowsRendered(gridApi, rows) {
|
|
294
|
+
gridApi.core.raise.rowsRendered(rows);
|
|
295
|
+
}
|
|
296
|
+
function raiseGridRowsVisibleChanged(gridApi, rows) {
|
|
297
|
+
gridApi.core.raise.rowsVisibleChanged(rows);
|
|
298
|
+
}
|
|
299
|
+
function raiseGridCanvasHeightChanged(gridApi, oldHeight, newHeight) {
|
|
300
|
+
gridApi.core.raise.canvasHeightChanged(oldHeight, newHeight);
|
|
301
|
+
}
|
|
302
|
+
function raiseGridDimensionChanged(gridApi, oldHeight, oldWidth, newHeight, newWidth) {
|
|
303
|
+
gridApi.core.raise.gridDimensionChanged(oldHeight, oldWidth, newHeight, newWidth);
|
|
304
|
+
}
|
|
305
|
+
function raiseGridScrollBegin(gridApi) {
|
|
306
|
+
gridApi.core.raise.scrollBegin();
|
|
307
|
+
}
|
|
308
|
+
function raiseGridScrollEnd(gridApi) {
|
|
309
|
+
gridApi.core.raise.scrollEnd();
|
|
310
|
+
}
|
|
311
|
+
function raiseGridSortChanged(gridApi, sortState) {
|
|
312
|
+
gridApi.core.raise.sortChanged(sortState.columnName, sortState.direction);
|
|
313
|
+
}
|
|
314
|
+
function raiseGridFilterChanged(gridApi, filters) {
|
|
315
|
+
gridApi.core.raise.filterChanged(filters);
|
|
316
|
+
}
|
|
317
|
+
function raiseGridGroupingChanged(gridApi, groupByColumns) {
|
|
318
|
+
gridApi.core.raise.groupingChanged(groupByColumns);
|
|
319
|
+
}
|
|
320
|
+
function raiseGridColumnOrderChanged(gridApi, order) {
|
|
321
|
+
gridApi.core.raise.columnOrderChanged(order);
|
|
322
|
+
}
|
|
323
|
+
function raiseGridBenchmarkComplete(gridApi, result) {
|
|
324
|
+
gridApi.core.raise.benchmarkComplete(result);
|
|
325
|
+
}
|
|
326
|
+
function raiseGridPaginationChanged(gridApi, currentPage, pageSize) {
|
|
327
|
+
gridApi.pagination.raise.paginationChanged(currentPage, pageSize);
|
|
328
|
+
}
|
|
329
|
+
function raiseGridExpandableRowStateChanged(gridApi, row, expanded) {
|
|
330
|
+
gridApi.expandable.raise.rowExpandedStateChanged(row, expanded);
|
|
331
|
+
}
|
|
332
|
+
function raiseGridTreeRowStateChanged(gridApi, row, expanded) {
|
|
333
|
+
if (expanded) {
|
|
334
|
+
gridApi.treeBase.raise.rowExpanded(row);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
gridApi.treeBase.raise.rowCollapsed(row);
|
|
338
|
+
}
|
|
339
|
+
function raiseGridNeedMoreData(gridApi, request) {
|
|
340
|
+
if (request === "top") {
|
|
341
|
+
gridApi.infiniteScroll.raise.needLoadMoreDataTop();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
gridApi.infiniteScroll.raise.needLoadMoreData();
|
|
345
|
+
}
|
|
346
|
+
function raiseGridBeginCellEdit(gridApi, rowEntity, column, triggerEvent) {
|
|
347
|
+
gridApi.edit.raise.beginCellEdit(rowEntity, column, triggerEvent);
|
|
348
|
+
}
|
|
349
|
+
function raiseGridAfterCellEdit(gridApi, rowEntity, column, newValue, oldValue) {
|
|
350
|
+
gridApi.edit.raise.afterCellEdit(rowEntity, column, newValue, oldValue);
|
|
351
|
+
}
|
|
352
|
+
function raiseGridCancelCellEdit(gridApi, rowEntity, column) {
|
|
353
|
+
gridApi.edit.raise.cancelCellEdit(rowEntity, column);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ../ui-grid/src/lib/grid/ui-grid.state.ts
|
|
357
|
+
function moveArrayItem(items, fromIndex, toIndex) {
|
|
358
|
+
const next = [...items];
|
|
359
|
+
const [item] = next.splice(fromIndex, 1);
|
|
360
|
+
if (item === void 0) {
|
|
361
|
+
return next;
|
|
362
|
+
}
|
|
363
|
+
next.splice(toIndex, 0, item);
|
|
364
|
+
return next;
|
|
365
|
+
}
|
|
366
|
+
function moveGridColumnOrderState(current, fromIndex, toIndex) {
|
|
367
|
+
return moveArrayItem(current, fromIndex, toIndex);
|
|
368
|
+
}
|
|
369
|
+
function createGridRestoreMutationPlan(state) {
|
|
370
|
+
const normalizedState = normalizeGridSavedState(state);
|
|
371
|
+
const plan = {};
|
|
372
|
+
if (normalizedState.columnOrder) {
|
|
373
|
+
plan.columnOrder = normalizedState.columnOrder;
|
|
374
|
+
}
|
|
375
|
+
if (normalizedState.filters) {
|
|
376
|
+
plan.filters = normalizedState.filters;
|
|
377
|
+
}
|
|
378
|
+
if (normalizedState.sort) {
|
|
379
|
+
plan.sort = normalizedState.sort;
|
|
380
|
+
}
|
|
381
|
+
if (normalizedState.grouping) {
|
|
382
|
+
plan.grouping = normalizedState.grouping;
|
|
383
|
+
}
|
|
384
|
+
if (normalizedState.pagination) {
|
|
385
|
+
plan.pagination = {
|
|
386
|
+
currentPage: normalizedState.pagination.paginationCurrentPage,
|
|
387
|
+
pageSize: normalizedState.pagination.paginationPageSize
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
if (normalizedState.expandable) {
|
|
391
|
+
plan.expandable = normalizedState.expandable;
|
|
392
|
+
}
|
|
393
|
+
if (normalizedState.treeView) {
|
|
394
|
+
plan.treeView = normalizedState.treeView;
|
|
395
|
+
}
|
|
396
|
+
return plan;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ../ui-grid/src/lib/grid/ui-grid.commands.ts
|
|
400
|
+
function applyGridSortStateCommand(gridApi, setSortState, sortState) {
|
|
401
|
+
setSortState(sortState);
|
|
402
|
+
raiseGridSortChanged(gridApi, sortState);
|
|
403
|
+
}
|
|
404
|
+
function sortGridColumnCommand(gridApi, setSortState, columnName, direction) {
|
|
405
|
+
applyGridSortStateCommand(gridApi, setSortState, buildGridSortState(columnName, direction));
|
|
406
|
+
}
|
|
407
|
+
function updateGridFilterCommand(gridApi, updateFilters, getFilters, columnName, value) {
|
|
408
|
+
updateFilters((current) => ({
|
|
409
|
+
...current,
|
|
410
|
+
[columnName]: value
|
|
411
|
+
}));
|
|
412
|
+
raiseGridFilterChanged(gridApi, getFilters());
|
|
413
|
+
}
|
|
414
|
+
function clearGridFiltersCommand(gridApi, setFilters) {
|
|
415
|
+
const nextFilters = {};
|
|
416
|
+
setFilters(nextFilters);
|
|
417
|
+
raiseGridFilterChanged(gridApi, nextFilters);
|
|
418
|
+
}
|
|
419
|
+
function clearGridGroupingCommand(gridApi, setGroupByColumns, shouldRaise = true) {
|
|
420
|
+
const nextGrouping = [];
|
|
421
|
+
setGroupByColumns(nextGrouping);
|
|
422
|
+
if (shouldRaise) {
|
|
423
|
+
raiseGridGroupingChanged(gridApi, nextGrouping);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function moveGridColumnCommand(gridApi, canMoveColumns, updateColumnOrder, fromIndex, toIndex) {
|
|
427
|
+
if (!canMoveColumns) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
updateColumnOrder((current) => {
|
|
431
|
+
const next = moveGridColumnOrderState(current, fromIndex, toIndex);
|
|
432
|
+
raiseGridColumnOrderChanged(gridApi, next);
|
|
433
|
+
return next;
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
function seekGridPaginationCommand(gridApi, setCurrentPage, getTotalPages, getEffectivePageSize, page) {
|
|
437
|
+
const nextPage = seekGridPage(page, getTotalPages());
|
|
438
|
+
setCurrentPage(nextPage);
|
|
439
|
+
raiseGridPaginationChanged(gridApi, nextPage, getEffectivePageSize());
|
|
440
|
+
}
|
|
441
|
+
function setGridPaginationPageSizeCommand(gridApi, setPageSize, setCurrentPage, pageSize) {
|
|
442
|
+
const nextPageSize = resolveGridPageSize(pageSize);
|
|
443
|
+
if (nextPageSize === null) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
setPageSize(nextPageSize);
|
|
447
|
+
setCurrentPage(1);
|
|
448
|
+
raiseGridPaginationChanged(gridApi, 1, nextPageSize);
|
|
449
|
+
}
|
|
450
|
+
function restoreGridStateCommand(gridApi, state, access) {
|
|
451
|
+
const restorePlan = createGridRestoreMutationPlan(state);
|
|
452
|
+
if (restorePlan.columnOrder) {
|
|
453
|
+
access.setColumnOrder(restorePlan.columnOrder);
|
|
454
|
+
}
|
|
455
|
+
if (restorePlan.filters) {
|
|
456
|
+
access.setActiveFilters(restorePlan.filters);
|
|
457
|
+
raiseGridFilterChanged(gridApi, restorePlan.filters);
|
|
458
|
+
}
|
|
459
|
+
if (restorePlan.sort) {
|
|
460
|
+
access.setSortState(restorePlan.sort);
|
|
461
|
+
}
|
|
462
|
+
if (restorePlan.grouping) {
|
|
463
|
+
access.setGroupByColumns(restorePlan.grouping);
|
|
464
|
+
raiseGridGroupingChanged(gridApi, restorePlan.grouping);
|
|
465
|
+
}
|
|
466
|
+
if (restorePlan.pagination) {
|
|
467
|
+
access.setCurrentPage(restorePlan.pagination.currentPage);
|
|
468
|
+
access.setPageSize(restorePlan.pagination.pageSize);
|
|
469
|
+
raiseGridPaginationChanged(gridApi, restorePlan.pagination.currentPage, access.getEffectivePageSize());
|
|
470
|
+
}
|
|
471
|
+
if (restorePlan.expandable) {
|
|
472
|
+
access.setExpandedRows(restorePlan.expandable);
|
|
473
|
+
}
|
|
474
|
+
if (restorePlan.treeView) {
|
|
475
|
+
access.setExpandedTreeRows(restorePlan.treeView);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function toggleGridRowExpansionCommand(gridApi, canExpandRows, currentExpandedRows, rowId, setExpandedRows, findRowById) {
|
|
479
|
+
if (!canExpandRows) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const { expanded, nextExpandedRows } = toggleGridRowExpanded(currentExpandedRows, rowId);
|
|
483
|
+
setExpandedRows(nextExpandedRows);
|
|
484
|
+
const gridRow = findRowById(rowId);
|
|
485
|
+
if (!gridRow) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
gridRow.expanded = expanded;
|
|
489
|
+
raiseGridExpandableRowStateChanged(gridApi, gridRow, expanded);
|
|
490
|
+
}
|
|
491
|
+
function expandAllGridRowsCommand(buildRows, data, setExpandedRows) {
|
|
492
|
+
setExpandedRows(expandAllGridRows(buildRows(data)));
|
|
493
|
+
}
|
|
494
|
+
function collapseAllGridRowsCommand(setExpandedRows) {
|
|
495
|
+
setExpandedRows({});
|
|
496
|
+
}
|
|
497
|
+
function toggleGridTreeRowCommand(gridApi, currentExpandedTreeRows, rowId, setExpandedTreeRows, findRowById) {
|
|
498
|
+
const { expanded, nextExpandedTreeRows } = toggleGridTreeRowExpanded(currentExpandedTreeRows, rowId);
|
|
499
|
+
setExpandedTreeRows(nextExpandedTreeRows);
|
|
500
|
+
const gridRow = findRowById(rowId);
|
|
501
|
+
if (gridRow) {
|
|
502
|
+
raiseGridTreeRowStateChanged(gridApi, gridRow, expanded);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function setGridTreeRowExpandedCommand(gridApi, currentExpandedTreeRows, rowId, expanded, setExpandedTreeRows, findRowById) {
|
|
506
|
+
setExpandedTreeRows(setGridTreeRowExpanded(currentExpandedTreeRows, rowId, expanded));
|
|
507
|
+
const gridRow = findRowById(rowId);
|
|
508
|
+
if (gridRow) {
|
|
509
|
+
raiseGridTreeRowStateChanged(gridApi, gridRow, expanded);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function expandAllGridTreeRowsCommand(buildRows, data, setExpandedTreeRows) {
|
|
513
|
+
setExpandedTreeRows(expandAllGridTreeRows(buildRows(data)));
|
|
514
|
+
}
|
|
515
|
+
function collapseAllGridTreeRowsCommand(setExpandedTreeRows) {
|
|
516
|
+
setExpandedTreeRows({});
|
|
517
|
+
}
|
|
518
|
+
function beginGridCellEditCommand(gridApi, access, row, column, currentValue, triggerEvent, initialValue) {
|
|
519
|
+
const nextEditSession = beginGridEditSession(
|
|
520
|
+
row.id,
|
|
521
|
+
column.name,
|
|
522
|
+
initialValue ?? stringifyGridEditorValue(currentValue)
|
|
523
|
+
);
|
|
524
|
+
access.setFocusedCell(nextEditSession.focusedCell);
|
|
525
|
+
access.setEditingCell(nextEditSession.editingCell);
|
|
526
|
+
access.setEditingValue(nextEditSession.editingValue);
|
|
527
|
+
raiseGridBeginCellEdit(gridApi, row.entity, column, triggerEvent);
|
|
528
|
+
return nextEditSession.editingCell;
|
|
529
|
+
}
|
|
530
|
+
function commitGridCellEditCommand(gridApi, access) {
|
|
531
|
+
const editingCell = access.getEditingCell();
|
|
532
|
+
if (!editingCell) {
|
|
533
|
+
return { committed: false };
|
|
534
|
+
}
|
|
535
|
+
const row = access.findRowById(editingCell.rowId);
|
|
536
|
+
const column = access.findColumnByName(editingCell.columnName);
|
|
537
|
+
if (!row || !column) {
|
|
538
|
+
access.setEditingCell(null);
|
|
539
|
+
return { committed: false };
|
|
540
|
+
}
|
|
541
|
+
const oldValue = getCellValue(row.entity, column);
|
|
542
|
+
const newValue = access.parseEditedValue(column, access.getEditingValue(), oldValue);
|
|
543
|
+
access.setCellValue(row.entity, column, newValue);
|
|
544
|
+
const clearedEditSession = clearGridEditSession();
|
|
545
|
+
access.setEditingCell(clearedEditSession.editingCell);
|
|
546
|
+
raiseGridAfterCellEdit(gridApi, row.entity, column, newValue, oldValue);
|
|
547
|
+
access.setEditingValue(clearedEditSession.editingValue);
|
|
548
|
+
return {
|
|
549
|
+
committed: true,
|
|
550
|
+
focusTarget: { rowId: row.id, columnName: column.name },
|
|
551
|
+
row,
|
|
552
|
+
column
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function cancelGridCellEditCommand(gridApi, access) {
|
|
556
|
+
const editingCell = access.getEditingCell();
|
|
557
|
+
if (!editingCell) {
|
|
558
|
+
return {};
|
|
559
|
+
}
|
|
560
|
+
const row = access.findRowById(editingCell.rowId);
|
|
561
|
+
const column = access.findColumnByName(editingCell.columnName);
|
|
562
|
+
const clearedEditSession = clearGridEditSession();
|
|
563
|
+
access.setEditingCell(clearedEditSession.editingCell);
|
|
564
|
+
access.setEditingValue(clearedEditSession.editingValue);
|
|
565
|
+
if (!row || !column) {
|
|
566
|
+
return {};
|
|
567
|
+
}
|
|
568
|
+
raiseGridCancelCellEdit(gridApi, row.entity, column);
|
|
569
|
+
return { focusTarget: editingCell };
|
|
570
|
+
}
|
|
571
|
+
function maybeRequestInfiniteScrollCommand(gridApi, access) {
|
|
572
|
+
if (!access.enabled || !access.virtualizationEnabled) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const { request, nextState } = maybeRequestInfiniteScrollData({
|
|
576
|
+
state: access.state,
|
|
577
|
+
startIndex: access.startIndex,
|
|
578
|
+
visibleRows: access.visibleRows,
|
|
579
|
+
viewportRows: access.viewportRows,
|
|
580
|
+
threshold: access.threshold
|
|
581
|
+
});
|
|
582
|
+
if (request === "top" || request === "bottom") {
|
|
583
|
+
access.setState(nextState);
|
|
584
|
+
raiseGridNeedMoreData(gridApi, request);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function completeGridInfiniteScrollDataLoadCommand(currentState, setState, scrollUp, scrollDown) {
|
|
588
|
+
setState(completeInfiniteScrollDataLoad(currentState, scrollUp, scrollDown));
|
|
589
|
+
return Promise.resolve();
|
|
590
|
+
}
|
|
591
|
+
function resetGridInfiniteScrollCommand(setState, scrollUp, scrollDown) {
|
|
592
|
+
setState(resetInfiniteScrollState(scrollUp, scrollDown));
|
|
593
|
+
}
|
|
594
|
+
function saveGridInfiniteScrollPercentageCommand(currentState, visibleRows, setState) {
|
|
595
|
+
setState(saveInfiniteScrollPercentage(currentState, visibleRows));
|
|
596
|
+
}
|
|
597
|
+
function setGridInfiniteScrollDirectionsCommand(currentState, setState, scrollUp, scrollDown) {
|
|
598
|
+
setState(setInfiniteScrollDirectionsState(currentState, scrollUp, scrollDown));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// ../ui-grid/src/lib/grid/ui-grid.host.ts
|
|
602
|
+
function observeGridHostSize(hostElement, onSizeChange) {
|
|
603
|
+
if (typeof ResizeObserver === "undefined") {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
const observer = new ResizeObserver((entries) => {
|
|
607
|
+
const entry = entries[0];
|
|
608
|
+
if (!entry) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
onSizeChange({
|
|
612
|
+
height: Math.round(entry.contentRect.height),
|
|
613
|
+
width: Math.round(entry.contentRect.width)
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
observer.observe(hostElement);
|
|
617
|
+
return observer;
|
|
618
|
+
}
|
|
619
|
+
function downloadGridCsvFile(csv, filename) {
|
|
620
|
+
if (typeof Blob === "undefined" || typeof URL === "undefined" || typeof document === "undefined") {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
|
|
624
|
+
const url = URL.createObjectURL(blob);
|
|
625
|
+
const link = document.createElement("a");
|
|
626
|
+
link.href = url;
|
|
627
|
+
link.download = filename;
|
|
628
|
+
link.click();
|
|
629
|
+
URL.revokeObjectURL(url);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// src/useGridState.ts
|
|
633
|
+
function useGridState(options, onRegisterApi) {
|
|
634
|
+
const [activeFilters, setActiveFilters] = useState({});
|
|
635
|
+
const [groupByColumns, setGroupByColumns] = useState([]);
|
|
636
|
+
const [collapsedGroups, setCollapsedGroups] = useState({});
|
|
637
|
+
const [columnOrder, setColumnOrder] = useState([]);
|
|
638
|
+
const [hiddenRowReasons, setHiddenRowReasons] = useState({});
|
|
639
|
+
const [sortState, setSortState] = useState({ columnName: null, direction: SORT_DIRECTIONS2.none });
|
|
640
|
+
const [focusedCell, setFocusedCell] = useState(null);
|
|
641
|
+
const [editingCell, setEditingCell] = useState(null);
|
|
642
|
+
const [editingValue, setEditingValue] = useState("");
|
|
643
|
+
const [expandedRows, setExpandedRows] = useState({});
|
|
644
|
+
const [expandedTreeRows, setExpandedTreeRows] = useState({});
|
|
645
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
646
|
+
const [pageSize, setPageSize] = useState(0);
|
|
647
|
+
const [benchmarkResult, setBenchmarkResult] = useState(null);
|
|
648
|
+
const [infiniteScrollState, setInfiniteScrollState] = useState({
|
|
649
|
+
scrollUp: false,
|
|
650
|
+
scrollDown: true,
|
|
651
|
+
dataLoading: false,
|
|
652
|
+
previousVisibleRows: 0
|
|
653
|
+
});
|
|
654
|
+
const [autoViewportHeight, setAutoViewportHeight] = useState(null);
|
|
655
|
+
const gridContainerRef = useRef(null);
|
|
656
|
+
const initializedGridIdRef = useRef(null);
|
|
657
|
+
const lastCanvasHeightRef = useRef(0);
|
|
658
|
+
const lastGridHeightRef = useRef(0);
|
|
659
|
+
const lastGridWidthRef = useRef(0);
|
|
660
|
+
const scrollEndHandleRef = useRef(void 0);
|
|
661
|
+
const scrollingRef = useRef(false);
|
|
662
|
+
const editorFocusTokenRef = useRef(0);
|
|
663
|
+
const renderedCellFocusTokenRef = useRef(0);
|
|
664
|
+
const activeFiltersRef = useRef(activeFilters);
|
|
665
|
+
activeFiltersRef.current = activeFilters;
|
|
666
|
+
const groupByColumnsRef = useRef(groupByColumns);
|
|
667
|
+
groupByColumnsRef.current = groupByColumns;
|
|
668
|
+
const collapsedGroupsRef = useRef(collapsedGroups);
|
|
669
|
+
collapsedGroupsRef.current = collapsedGroups;
|
|
670
|
+
const columnOrderRef = useRef(columnOrder);
|
|
671
|
+
columnOrderRef.current = columnOrder;
|
|
672
|
+
const hiddenRowReasonsRef = useRef(hiddenRowReasons);
|
|
673
|
+
hiddenRowReasonsRef.current = hiddenRowReasons;
|
|
674
|
+
const sortStateRef = useRef(sortState);
|
|
675
|
+
sortStateRef.current = sortState;
|
|
676
|
+
const focusedCellRef = useRef(focusedCell);
|
|
677
|
+
focusedCellRef.current = focusedCell;
|
|
678
|
+
const editingCellRef = useRef(editingCell);
|
|
679
|
+
editingCellRef.current = editingCell;
|
|
680
|
+
const editingValueRef = useRef(editingValue);
|
|
681
|
+
editingValueRef.current = editingValue;
|
|
682
|
+
const expandedRowsRef = useRef(expandedRows);
|
|
683
|
+
expandedRowsRef.current = expandedRows;
|
|
684
|
+
const expandedTreeRowsRef = useRef(expandedTreeRows);
|
|
685
|
+
expandedTreeRowsRef.current = expandedTreeRows;
|
|
686
|
+
const currentPageRef = useRef(currentPage);
|
|
687
|
+
currentPageRef.current = currentPage;
|
|
688
|
+
const pageSizeRef = useRef(pageSize);
|
|
689
|
+
pageSizeRef.current = pageSize;
|
|
690
|
+
const infiniteScrollStateRef = useRef(infiniteScrollState);
|
|
691
|
+
infiniteScrollStateRef.current = infiniteScrollState;
|
|
692
|
+
const optionsRef = useRef(options);
|
|
693
|
+
optionsRef.current = options;
|
|
694
|
+
const rowSize = options.rowHeight ?? 44;
|
|
695
|
+
const visibleColumns = useMemo(() => {
|
|
696
|
+
const order = columnOrder;
|
|
697
|
+
return [...options.columnDefs].filter((column) => column.visible !== false).sort((left, right) => order.indexOf(left.name) - order.indexOf(right.name));
|
|
698
|
+
}, [options.columnDefs, columnOrder]);
|
|
699
|
+
const visibleColumnsRef = useRef(visibleColumns);
|
|
700
|
+
visibleColumnsRef.current = visibleColumns;
|
|
701
|
+
const pipeline = useMemo(() => {
|
|
702
|
+
return buildGridPipeline({
|
|
703
|
+
options,
|
|
704
|
+
columns: visibleColumns,
|
|
705
|
+
activeFilters,
|
|
706
|
+
sortState,
|
|
707
|
+
groupByColumns,
|
|
708
|
+
collapsedGroups,
|
|
709
|
+
hiddenRowReasons,
|
|
710
|
+
expandedRows,
|
|
711
|
+
expandedTreeRows,
|
|
712
|
+
currentPage,
|
|
713
|
+
pageSize,
|
|
714
|
+
rowSize
|
|
715
|
+
});
|
|
716
|
+
}, [options, visibleColumns, activeFilters, sortState, groupByColumns, collapsedGroups, hiddenRowReasons, expandedRows, expandedTreeRows, currentPage, pageSize, rowSize]);
|
|
717
|
+
const pipelineRef = useRef(pipeline);
|
|
718
|
+
pipelineRef.current = pipeline;
|
|
719
|
+
const labels = useMemo(() => resolveGridLabels(options.labels), [options.labels]);
|
|
720
|
+
const gridTemplateColumns = useMemo(
|
|
721
|
+
() => visibleColumns.map((column) => gridColumnWidth(column)).join(" "),
|
|
722
|
+
[visibleColumns]
|
|
723
|
+
);
|
|
724
|
+
const resolveRowId = useCallback((row) => {
|
|
725
|
+
return coreResolveGridRowId(optionsRef.current, row);
|
|
726
|
+
}, []);
|
|
727
|
+
const buildRowsFromData = useCallback((data) => {
|
|
728
|
+
return buildGridRows(
|
|
729
|
+
{ ...optionsRef.current, data },
|
|
730
|
+
optionsRef.current.rowHeight ?? 44,
|
|
731
|
+
hiddenRowReasonsRef.current,
|
|
732
|
+
expandedRowsRef.current
|
|
733
|
+
);
|
|
734
|
+
}, []);
|
|
735
|
+
const findRowById = useCallback((rowId) => {
|
|
736
|
+
return coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId);
|
|
737
|
+
}, [buildRowsFromData]);
|
|
738
|
+
const canExpandRowsFn = useCallback(() => {
|
|
739
|
+
return FEATURE_EXPANDABLE && canGridExpandRows(optionsRef.current);
|
|
740
|
+
}, []);
|
|
741
|
+
const effectivePageSizeFn = useCallback((totalItems) => {
|
|
742
|
+
return coreGetEffectivePageSize(optionsRef.current, pageSizeRef.current, totalItems);
|
|
743
|
+
}, []);
|
|
744
|
+
const getCurrentPageValueFn = useCallback((totalItems) => {
|
|
745
|
+
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
746
|
+
return coreGetCurrentPageValue(optionsRef.current, currentPageRef.current, ti, pageSizeRef.current);
|
|
747
|
+
}, []);
|
|
748
|
+
const getTotalPagesValueFn = useCallback((totalItems) => {
|
|
749
|
+
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
750
|
+
return coreGetTotalPagesValue(optionsRef.current, ti, pageSizeRef.current);
|
|
751
|
+
}, []);
|
|
752
|
+
const getFirstRowIndexValueFn = useCallback((totalItems) => {
|
|
753
|
+
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
754
|
+
return coreGetFirstRowIndexValue(optionsRef.current, currentPageRef.current, ti, pageSizeRef.current);
|
|
755
|
+
}, []);
|
|
756
|
+
const getLastRowIndexValueFn = useCallback((totalItems) => {
|
|
757
|
+
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
758
|
+
return coreGetLastRowIndexValue(optionsRef.current, currentPageRef.current, ti, pageSizeRef.current);
|
|
759
|
+
}, []);
|
|
760
|
+
const isCellEditable = useCallback((row, column, triggerEvent) => {
|
|
761
|
+
if (!FEATURE_CELL_EDIT) return false;
|
|
762
|
+
const editable = column.enableCellEdit ?? optionsRef.current.enableCellEdit ?? false;
|
|
763
|
+
if (!editable) return false;
|
|
764
|
+
const condition = column.cellEditableCondition ?? optionsRef.current.cellEditableCondition ?? true;
|
|
765
|
+
if (typeof condition === "boolean") return condition;
|
|
766
|
+
const context = {
|
|
767
|
+
row: row.entity,
|
|
768
|
+
column,
|
|
769
|
+
rowIndex: row.index,
|
|
770
|
+
triggerEvent
|
|
771
|
+
};
|
|
772
|
+
return condition(context);
|
|
773
|
+
}, []);
|
|
774
|
+
const shouldEditOnFocusFn = useCallback((column) => {
|
|
775
|
+
return column.enableCellEditOnFocus ?? optionsRef.current.enableCellEditOnFocus ?? false;
|
|
776
|
+
}, []);
|
|
777
|
+
const focusRenderedCell = useCallback((position) => {
|
|
778
|
+
const focusToken = ++renderedCellFocusTokenRef.current;
|
|
779
|
+
const selector = `.body-cell[data-row-id="${position.rowId}"][data-col-name="${position.columnName}"]`;
|
|
780
|
+
const doFocus = (retry = true) => {
|
|
781
|
+
if (focusToken !== renderedCellFocusTokenRef.current) return;
|
|
782
|
+
const container = gridContainerRef.current;
|
|
783
|
+
if (!container) return;
|
|
784
|
+
const target = container.querySelector(selector);
|
|
785
|
+
if (!target) {
|
|
786
|
+
if (retry) requestAnimationFrame(() => doFocus(false));
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
target.focus();
|
|
790
|
+
if (retry && container.ownerDocument.activeElement !== target) {
|
|
791
|
+
requestAnimationFrame(() => doFocus(false));
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
queueMicrotask(() => doFocus(true));
|
|
795
|
+
}, []);
|
|
796
|
+
const focusEditorInput = useCallback((focusToken) => {
|
|
797
|
+
if (focusToken !== editorFocusTokenRef.current) return;
|
|
798
|
+
const ec = editingCellRef.current;
|
|
799
|
+
if (!ec) return;
|
|
800
|
+
const selector = `.cell-editor[data-row-id="${ec.rowId}"][data-col-name="${ec.columnName}"]`;
|
|
801
|
+
const doFocus = (retry = true) => {
|
|
802
|
+
if (focusToken !== editorFocusTokenRef.current) return;
|
|
803
|
+
const currentEc = editingCellRef.current;
|
|
804
|
+
if (!currentEc || currentEc.rowId !== ec.rowId || currentEc.columnName !== ec.columnName) return;
|
|
805
|
+
const container = gridContainerRef.current;
|
|
806
|
+
if (!container) return;
|
|
807
|
+
const input = container.querySelector(selector);
|
|
808
|
+
if (!input) {
|
|
809
|
+
if (retry) requestAnimationFrame(() => doFocus(false));
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
input.focus();
|
|
813
|
+
input.select();
|
|
814
|
+
};
|
|
815
|
+
doFocus(true);
|
|
816
|
+
}, []);
|
|
817
|
+
const gridApiRef = useRef(null);
|
|
818
|
+
if (!gridApiRef.current) {
|
|
819
|
+
const bindings = {
|
|
820
|
+
refresh: () => setActiveFilters((current) => ({ ...current })),
|
|
821
|
+
getVisibleRows: () => pipelineRef.current.visibleRows,
|
|
822
|
+
setRowInvisible: (row, reason = "user") => {
|
|
823
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
824
|
+
setHiddenRowReasons((current) => addGridRowInvisibleReason(current, rowId, reason));
|
|
825
|
+
},
|
|
826
|
+
clearRowInvisible: (row, reason = "user") => {
|
|
827
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
828
|
+
setHiddenRowReasons((current) => clearGridRowInvisibleReason(current, rowId, reason));
|
|
829
|
+
},
|
|
830
|
+
setFilter: (columnName, value) => {
|
|
831
|
+
setActiveFilters((current) => {
|
|
832
|
+
const next = { ...current, [columnName]: value };
|
|
833
|
+
activeFiltersRef.current = next;
|
|
834
|
+
queueMicrotask(() => gridApiRef.current.core.raise.filterChanged(next));
|
|
835
|
+
return next;
|
|
836
|
+
});
|
|
837
|
+
},
|
|
838
|
+
clearAllFilters: () => {
|
|
839
|
+
const nextFilters = {};
|
|
840
|
+
activeFiltersRef.current = nextFilters;
|
|
841
|
+
setActiveFilters(nextFilters);
|
|
842
|
+
queueMicrotask(() => gridApiRef.current.core.raise.filterChanged(nextFilters));
|
|
843
|
+
},
|
|
844
|
+
sortColumn: (columnName, direction) => {
|
|
845
|
+
sortGridColumnCommand(gridApiRef.current, (s) => setSortState(s), columnName, direction);
|
|
846
|
+
},
|
|
847
|
+
moveColumn: (fromIndex, toIndex) => {
|
|
848
|
+
moveGridColumnCommand(
|
|
849
|
+
gridApiRef.current,
|
|
850
|
+
FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
|
|
851
|
+
(updater) => setColumnOrder((current) => updater(current)),
|
|
852
|
+
fromIndex,
|
|
853
|
+
toIndex
|
|
854
|
+
);
|
|
855
|
+
},
|
|
856
|
+
toggleGrouping: (columnName) => {
|
|
857
|
+
if (!(FEATURE_GROUPING && isGridGroupingEnabled(optionsRef.current))) return;
|
|
858
|
+
const current = groupByColumnsRef.current;
|
|
859
|
+
const next = current.includes(columnName) ? current.filter((n) => n !== columnName) : [...current, columnName];
|
|
860
|
+
groupByColumnsRef.current = next;
|
|
861
|
+
setGroupByColumns(next);
|
|
862
|
+
gridApiRef.current.core.raise.groupingChanged(next);
|
|
863
|
+
},
|
|
864
|
+
clearGrouping: () => {
|
|
865
|
+
clearGridGroupingCommand(gridApiRef.current, (grouping) => setGroupByColumns(grouping), false);
|
|
866
|
+
},
|
|
867
|
+
benchmark: (iterations) => {
|
|
868
|
+
return runBenchmarkFn(iterations);
|
|
869
|
+
},
|
|
870
|
+
exportCsv: () => {
|
|
871
|
+
exportCsvFn();
|
|
872
|
+
},
|
|
873
|
+
paginationGetPage: () => getCurrentPageValueFn(),
|
|
874
|
+
paginationGetTotalPages: () => getTotalPagesValueFn(),
|
|
875
|
+
paginationGetFirstRowIndex: () => getFirstRowIndexValueFn(),
|
|
876
|
+
paginationGetLastRowIndex: () => getLastRowIndexValueFn(),
|
|
877
|
+
paginationNextPage: () => seekPageFn(getCurrentPageValueFn() + 1),
|
|
878
|
+
paginationPreviousPage: () => seekPageFn(getCurrentPageValueFn() - 1),
|
|
879
|
+
paginationSeek: (page) => seekPageFn(page),
|
|
880
|
+
paginationSetPageSize: (ps) => setPaginationPageSizeFn(ps),
|
|
881
|
+
toggleRowExpansion: (row) => toggleRowExpansionByRefFn(row),
|
|
882
|
+
expandAllRows: () => expandAllRowsFn(),
|
|
883
|
+
collapseAllRows: () => {
|
|
884
|
+
collapseAllGridRowsCommand((e) => setExpandedRows(e));
|
|
885
|
+
},
|
|
886
|
+
toggleAllRows: () => toggleAllRowsFn(),
|
|
887
|
+
treeExpandAllRows: () => {
|
|
888
|
+
expandAllGridTreeRowsCommand(
|
|
889
|
+
(data) => buildRowsFromData(data),
|
|
890
|
+
optionsRef.current.data,
|
|
891
|
+
(e) => setExpandedTreeRows(e)
|
|
892
|
+
);
|
|
893
|
+
},
|
|
894
|
+
treeCollapseAllRows: () => {
|
|
895
|
+
collapseAllGridTreeRowsCommand((e) => setExpandedTreeRows(e));
|
|
896
|
+
},
|
|
897
|
+
treeToggleRow: (row) => toggleTreeRowByRefFn(row),
|
|
898
|
+
treeExpandRow: (row) => expandTreeRowByRefFn(row),
|
|
899
|
+
treeCollapseRow: (row) => collapseTreeRowByRefFn(row),
|
|
900
|
+
treeGetRowChildren: (row) => {
|
|
901
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
902
|
+
return buildRowsFromData(optionsRef.current.data).filter((r) => r.parentId === rowId);
|
|
903
|
+
},
|
|
904
|
+
treeGetState: () => expandedTreeRowsRef.current,
|
|
905
|
+
treeSetState: (state) => setExpandedTreeRows({ ...state }),
|
|
906
|
+
infiniteScrollDataLoaded: (scrollUp, scrollDown) => {
|
|
907
|
+
return completeGridInfiniteScrollDataLoadCommand(
|
|
908
|
+
infiniteScrollStateRef.current,
|
|
909
|
+
(s) => setInfiniteScrollState(s),
|
|
910
|
+
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
911
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
912
|
+
);
|
|
913
|
+
},
|
|
914
|
+
infiniteScrollReset: (scrollUp, scrollDown) => {
|
|
915
|
+
resetGridInfiniteScrollCommand(
|
|
916
|
+
(s) => setInfiniteScrollState(s),
|
|
917
|
+
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
918
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
919
|
+
);
|
|
920
|
+
},
|
|
921
|
+
infiniteScrollSaveScrollPercentage: () => {
|
|
922
|
+
saveGridInfiniteScrollPercentageCommand(
|
|
923
|
+
infiniteScrollStateRef.current,
|
|
924
|
+
pipelineRef.current.visibleRows.length,
|
|
925
|
+
(s) => setInfiniteScrollState(s)
|
|
926
|
+
);
|
|
927
|
+
},
|
|
928
|
+
infiniteScrollDataRemovedTop: (scrollUp, scrollDown) => {
|
|
929
|
+
resetGridInfiniteScrollCommand(
|
|
930
|
+
(s) => setInfiniteScrollState(s),
|
|
931
|
+
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
932
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
933
|
+
);
|
|
934
|
+
},
|
|
935
|
+
infiniteScrollDataRemovedBottom: (scrollUp, scrollDown) => {
|
|
936
|
+
resetGridInfiniteScrollCommand(
|
|
937
|
+
(s) => setInfiniteScrollState(s),
|
|
938
|
+
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
939
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
940
|
+
);
|
|
941
|
+
},
|
|
942
|
+
infiniteScrollSetDirections: (scrollUp, scrollDown) => {
|
|
943
|
+
setGridInfiniteScrollDirectionsCommand(
|
|
944
|
+
infiniteScrollStateRef.current,
|
|
945
|
+
(s) => setInfiniteScrollState(s),
|
|
946
|
+
scrollUp,
|
|
947
|
+
scrollDown
|
|
948
|
+
);
|
|
949
|
+
},
|
|
950
|
+
saveState: () => {
|
|
951
|
+
return buildGridSavedState({
|
|
952
|
+
columnOrder: columnOrderRef.current,
|
|
953
|
+
activeFilters: activeFiltersRef.current,
|
|
954
|
+
sortState: sortStateRef.current,
|
|
955
|
+
groupByColumns: groupByColumnsRef.current,
|
|
956
|
+
currentPage: currentPageRef.current,
|
|
957
|
+
pageSize: pageSizeRef.current,
|
|
958
|
+
totalItems: pipelineRef.current.totalItems,
|
|
959
|
+
expandedRows: expandedRowsRef.current,
|
|
960
|
+
expandedTreeRows: expandedTreeRowsRef.current
|
|
961
|
+
});
|
|
962
|
+
},
|
|
963
|
+
restoreState: (state) => {
|
|
964
|
+
restoreGridStateCommand(gridApiRef.current, state, {
|
|
965
|
+
setColumnOrder: (order) => setColumnOrder(order),
|
|
966
|
+
setActiveFilters: (filters) => setActiveFilters(filters),
|
|
967
|
+
setSortState: (s) => setSortState(s),
|
|
968
|
+
setGroupByColumns: (grouping) => setGroupByColumns(grouping),
|
|
969
|
+
setCurrentPage: (page) => setCurrentPage(page),
|
|
970
|
+
setPageSize: (ps) => setPageSize(ps),
|
|
971
|
+
setExpandedRows: (e) => setExpandedRows(e),
|
|
972
|
+
setExpandedTreeRows: (e) => setExpandedTreeRows(e),
|
|
973
|
+
getEffectivePageSize: () => effectivePageSizeFn(pipelineRef.current.totalItems)
|
|
974
|
+
});
|
|
975
|
+
},
|
|
976
|
+
beginCellEdit: (row, columnName, triggerEvent) => {
|
|
977
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
978
|
+
const gridRow = coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId);
|
|
979
|
+
const column = visibleColumnsRef.current.find((c) => c.name === columnName);
|
|
980
|
+
if (!gridRow || !column || !isCellEditable(gridRow, column, triggerEvent)) return;
|
|
981
|
+
startCellEditFn(gridRow, column, triggerEvent);
|
|
982
|
+
},
|
|
983
|
+
endCellEdit: () => commitCellEditFn(),
|
|
984
|
+
cancelCellEdit: () => cancelCellEditFn(),
|
|
985
|
+
getEditingCell: () => editingCellRef.current
|
|
986
|
+
};
|
|
987
|
+
gridApiRef.current = createGridApi(bindings);
|
|
988
|
+
}
|
|
989
|
+
const gridApi = gridApiRef.current;
|
|
990
|
+
const seekPageFn = useCallback((page) => {
|
|
991
|
+
seekGridPaginationCommand(
|
|
992
|
+
gridApiRef.current,
|
|
993
|
+
(nextPage) => setCurrentPage(nextPage),
|
|
994
|
+
() => getTotalPagesValueFn(),
|
|
995
|
+
() => effectivePageSizeFn(pipelineRef.current.totalItems),
|
|
996
|
+
page
|
|
997
|
+
);
|
|
998
|
+
}, [getTotalPagesValueFn, effectivePageSizeFn]);
|
|
999
|
+
const setPaginationPageSizeFn = useCallback((ps) => {
|
|
1000
|
+
setGridPaginationPageSizeCommand(
|
|
1001
|
+
gridApiRef.current,
|
|
1002
|
+
(nextPageSize) => setPageSize(nextPageSize),
|
|
1003
|
+
(nextPage) => setCurrentPage(nextPage),
|
|
1004
|
+
ps
|
|
1005
|
+
);
|
|
1006
|
+
}, []);
|
|
1007
|
+
const toggleRowExpansionByRefFn = useCallback((row) => {
|
|
1008
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
1009
|
+
toggleGridRowExpansionCommand(
|
|
1010
|
+
gridApiRef.current,
|
|
1011
|
+
FEATURE_EXPANDABLE && canGridExpandRows(optionsRef.current),
|
|
1012
|
+
expandedRowsRef.current,
|
|
1013
|
+
rowId,
|
|
1014
|
+
(e) => setExpandedRows(e),
|
|
1015
|
+
(resolvedRowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId)
|
|
1016
|
+
);
|
|
1017
|
+
}, [buildRowsFromData]);
|
|
1018
|
+
const expandAllRowsFn = useCallback(() => {
|
|
1019
|
+
if (!canGridExpandRows(optionsRef.current)) return;
|
|
1020
|
+
expandAllGridRowsCommand(
|
|
1021
|
+
(data) => buildRowsFromData(data),
|
|
1022
|
+
optionsRef.current.data,
|
|
1023
|
+
(e) => setExpandedRows(e)
|
|
1024
|
+
);
|
|
1025
|
+
}, [buildRowsFromData]);
|
|
1026
|
+
const toggleAllRowsFn = useCallback(() => {
|
|
1027
|
+
const allExpanded = areAllGridRowsExpanded(buildRowsFromData(optionsRef.current.data), expandedRowsRef.current);
|
|
1028
|
+
if (allExpanded) {
|
|
1029
|
+
collapseAllGridRowsCommand((e) => setExpandedRows(e));
|
|
1030
|
+
} else {
|
|
1031
|
+
expandAllRowsFn();
|
|
1032
|
+
}
|
|
1033
|
+
}, [buildRowsFromData, expandAllRowsFn]);
|
|
1034
|
+
const toggleTreeRowByRefFn = useCallback((row) => {
|
|
1035
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
1036
|
+
toggleGridTreeRowCommand(
|
|
1037
|
+
gridApiRef.current,
|
|
1038
|
+
expandedTreeRowsRef.current,
|
|
1039
|
+
rowId,
|
|
1040
|
+
(e) => setExpandedTreeRows(e),
|
|
1041
|
+
(resolvedRowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId)
|
|
1042
|
+
);
|
|
1043
|
+
}, [buildRowsFromData]);
|
|
1044
|
+
const expandTreeRowByRefFn = useCallback((row) => {
|
|
1045
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
1046
|
+
setGridTreeRowExpandedCommand(
|
|
1047
|
+
gridApiRef.current,
|
|
1048
|
+
expandedTreeRowsRef.current,
|
|
1049
|
+
rowId,
|
|
1050
|
+
true,
|
|
1051
|
+
(e) => setExpandedTreeRows(e),
|
|
1052
|
+
(resolvedRowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId)
|
|
1053
|
+
);
|
|
1054
|
+
}, [buildRowsFromData]);
|
|
1055
|
+
const collapseTreeRowByRefFn = useCallback((row) => {
|
|
1056
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
1057
|
+
setGridTreeRowExpandedCommand(
|
|
1058
|
+
gridApiRef.current,
|
|
1059
|
+
expandedTreeRowsRef.current,
|
|
1060
|
+
rowId,
|
|
1061
|
+
false,
|
|
1062
|
+
(e) => setExpandedTreeRows(e),
|
|
1063
|
+
(resolvedRowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId)
|
|
1064
|
+
);
|
|
1065
|
+
}, [buildRowsFromData]);
|
|
1066
|
+
const startCellEditFn = useCallback((row, column, triggerEvent, initialValue) => {
|
|
1067
|
+
const currentValue = getCellValue2(row.entity, column);
|
|
1068
|
+
const focusToken = ++editorFocusTokenRef.current;
|
|
1069
|
+
const ec = beginGridCellEditCommand(
|
|
1070
|
+
gridApiRef.current,
|
|
1071
|
+
{
|
|
1072
|
+
setFocusedCell: (fc) => setFocusedCell(fc),
|
|
1073
|
+
setEditingCell: (ec2) => setEditingCell(ec2),
|
|
1074
|
+
setEditingValue: (ev) => setEditingValue(ev)
|
|
1075
|
+
},
|
|
1076
|
+
row,
|
|
1077
|
+
column,
|
|
1078
|
+
currentValue,
|
|
1079
|
+
triggerEvent,
|
|
1080
|
+
initialValue
|
|
1081
|
+
);
|
|
1082
|
+
if (ec) {
|
|
1083
|
+
queueMicrotask(() => focusEditorInput(focusToken));
|
|
1084
|
+
}
|
|
1085
|
+
}, [focusEditorInput]);
|
|
1086
|
+
const commitCellEditFn = useCallback((direction, restoreFocus = true) => {
|
|
1087
|
+
const result = commitGridCellEditCommand(gridApiRef.current, {
|
|
1088
|
+
getEditingCell: () => editingCellRef.current,
|
|
1089
|
+
getEditingValue: () => editingValueRef.current,
|
|
1090
|
+
setEditingCell: (ec) => setEditingCell(ec),
|
|
1091
|
+
setEditingValue: (ev) => setEditingValue(ev),
|
|
1092
|
+
findRowById: (rowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId),
|
|
1093
|
+
findColumnByName: (columnName) => visibleColumnsRef.current.find((c) => c.name === columnName),
|
|
1094
|
+
parseEditedValue: (column, value, oldValue) => parseGridEditedValue(column, value, oldValue),
|
|
1095
|
+
setCellValue: (rowEntity, column, value) => {
|
|
1096
|
+
const fieldPath = column.editModelField ?? column.field ?? column.name;
|
|
1097
|
+
setPathValue(rowEntity, fieldPath, value);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
if (!result.committed || !result.row || !result.column || !result.focusTarget) return;
|
|
1101
|
+
editorFocusTokenRef.current += 1;
|
|
1102
|
+
if (direction) {
|
|
1103
|
+
const moved = moveFocusFn(result.row, result.column, direction);
|
|
1104
|
+
if (!moved) focusRenderedCell(result.focusTarget);
|
|
1105
|
+
} else if (restoreFocus) {
|
|
1106
|
+
focusRenderedCell(result.focusTarget);
|
|
1107
|
+
}
|
|
1108
|
+
}, [buildRowsFromData, focusRenderedCell]);
|
|
1109
|
+
const cancelCellEditFn = useCallback(() => {
|
|
1110
|
+
const hadEditingCell = editingCellRef.current !== null;
|
|
1111
|
+
const result = cancelGridCellEditCommand(gridApiRef.current, {
|
|
1112
|
+
getEditingCell: () => editingCellRef.current,
|
|
1113
|
+
setEditingCell: (ec) => setEditingCell(ec),
|
|
1114
|
+
setEditingValue: (ev) => setEditingValue(ev),
|
|
1115
|
+
findRowById: (rowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId),
|
|
1116
|
+
findColumnByName: (columnName) => visibleColumnsRef.current.find((c) => c.name === columnName)
|
|
1117
|
+
});
|
|
1118
|
+
if (!hadEditingCell) return;
|
|
1119
|
+
editorFocusTokenRef.current += 1;
|
|
1120
|
+
if (result.focusTarget) focusRenderedCell(result.focusTarget);
|
|
1121
|
+
}, [buildRowsFromData, focusRenderedCell]);
|
|
1122
|
+
const moveFocusFn = useCallback((row, column, direction, triggerEvent) => {
|
|
1123
|
+
const nextCell = findNextGridCell({
|
|
1124
|
+
rows: pipelineRef.current.visibleRows,
|
|
1125
|
+
columns: visibleColumnsRef.current,
|
|
1126
|
+
rowId: row.id,
|
|
1127
|
+
columnName: column.name,
|
|
1128
|
+
direction
|
|
1129
|
+
});
|
|
1130
|
+
if (!nextCell) return false;
|
|
1131
|
+
setFocusedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
|
|
1132
|
+
focusRenderedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
|
|
1133
|
+
if (shouldEditOnFocusFn(nextCell.column) && isCellEditable(nextCell.row, nextCell.column, triggerEvent)) {
|
|
1134
|
+
startCellEditFn(nextCell.row, nextCell.column, triggerEvent);
|
|
1135
|
+
}
|
|
1136
|
+
return true;
|
|
1137
|
+
}, [focusRenderedCell, isCellEditable, shouldEditOnFocusFn, startCellEditFn]);
|
|
1138
|
+
const runBenchmarkFn = useCallback((iterations) => {
|
|
1139
|
+
const safeIterations = Math.max(1, iterations ?? optionsRef.current.benchmark?.iterations ?? 25);
|
|
1140
|
+
const startedAt = performance.now();
|
|
1141
|
+
let lastResult = buildGridPipeline({
|
|
1142
|
+
options: optionsRef.current,
|
|
1143
|
+
columns: visibleColumnsRef.current,
|
|
1144
|
+
activeFilters: activeFiltersRef.current,
|
|
1145
|
+
sortState: sortStateRef.current,
|
|
1146
|
+
groupByColumns: groupByColumnsRef.current,
|
|
1147
|
+
collapsedGroups: collapsedGroupsRef.current,
|
|
1148
|
+
hiddenRowReasons: hiddenRowReasonsRef.current,
|
|
1149
|
+
expandedRows: expandedRowsRef.current,
|
|
1150
|
+
expandedTreeRows: expandedTreeRowsRef.current,
|
|
1151
|
+
currentPage: currentPageRef.current,
|
|
1152
|
+
pageSize: pageSizeRef.current,
|
|
1153
|
+
rowSize: optionsRef.current.rowHeight ?? 44
|
|
1154
|
+
});
|
|
1155
|
+
for (let i = 1; i < safeIterations; i++) {
|
|
1156
|
+
lastResult = buildGridPipeline({
|
|
1157
|
+
options: optionsRef.current,
|
|
1158
|
+
columns: visibleColumnsRef.current,
|
|
1159
|
+
activeFilters: activeFiltersRef.current,
|
|
1160
|
+
sortState: sortStateRef.current,
|
|
1161
|
+
groupByColumns: groupByColumnsRef.current,
|
|
1162
|
+
collapsedGroups: collapsedGroupsRef.current,
|
|
1163
|
+
hiddenRowReasons: hiddenRowReasonsRef.current,
|
|
1164
|
+
expandedRows: expandedRowsRef.current,
|
|
1165
|
+
expandedTreeRows: expandedTreeRowsRef.current,
|
|
1166
|
+
currentPage: currentPageRef.current,
|
|
1167
|
+
pageSize: pageSizeRef.current,
|
|
1168
|
+
rowSize: optionsRef.current.rowHeight ?? 44
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
const totalMs = performance.now() - startedAt;
|
|
1172
|
+
const result = {
|
|
1173
|
+
iterations: safeIterations,
|
|
1174
|
+
totalMs,
|
|
1175
|
+
averageMs: totalMs / safeIterations,
|
|
1176
|
+
visibleRows: lastResult.visibleRows.length,
|
|
1177
|
+
renderedItems: lastResult.displayItems.length
|
|
1178
|
+
};
|
|
1179
|
+
setBenchmarkResult(result);
|
|
1180
|
+
raiseGridBenchmarkComplete(gridApiRef.current, result);
|
|
1181
|
+
return result;
|
|
1182
|
+
}, []);
|
|
1183
|
+
const exportCsvFn = useCallback(() => {
|
|
1184
|
+
if (!FEATURE_CSV_EXPORT) return;
|
|
1185
|
+
const columns = visibleColumnsRef.current;
|
|
1186
|
+
const csv = exportCsvRows(columns, pipelineRef.current.visibleRows);
|
|
1187
|
+
downloadGridCsvFile(csv, `${sanitizeDownloadFilename(optionsRef.current.id)}.csv`);
|
|
1188
|
+
}, []);
|
|
1189
|
+
useEffect(() => {
|
|
1190
|
+
if (initializedGridIdRef.current === options.id) return;
|
|
1191
|
+
initializedGridIdRef.current = options.id;
|
|
1192
|
+
setActiveFilters({});
|
|
1193
|
+
setHiddenRowReasons({});
|
|
1194
|
+
setCollapsedGroups({});
|
|
1195
|
+
setFocusedCell(null);
|
|
1196
|
+
setEditingCell(null);
|
|
1197
|
+
setEditingValue("");
|
|
1198
|
+
setExpandedRows({});
|
|
1199
|
+
setExpandedTreeRows({});
|
|
1200
|
+
setColumnOrder(options.columnDefs.map((column) => column.name));
|
|
1201
|
+
setGroupByColumns(options.grouping?.groupBy ?? []);
|
|
1202
|
+
setCurrentPage(options.paginationCurrentPage ?? 1);
|
|
1203
|
+
setPageSize(coreGetEffectivePageSize(options, 0, options.data.length));
|
|
1204
|
+
setInfiniteScrollState({
|
|
1205
|
+
scrollUp: options.infiniteScrollUp === true,
|
|
1206
|
+
scrollDown: options.infiniteScrollDown !== false,
|
|
1207
|
+
dataLoading: false,
|
|
1208
|
+
previousVisibleRows: 0
|
|
1209
|
+
});
|
|
1210
|
+
const initialSort = options.columnDefs.find(
|
|
1211
|
+
(column) => column.sort?.direction && !column.sort.ignoreSort
|
|
1212
|
+
);
|
|
1213
|
+
setSortState({
|
|
1214
|
+
columnName: initialSort?.name ?? null,
|
|
1215
|
+
direction: initialSort?.sort?.direction ?? SORT_DIRECTIONS2.none
|
|
1216
|
+
});
|
|
1217
|
+
onRegisterApi?.(gridApi);
|
|
1218
|
+
raiseGridRenderingComplete(gridApi);
|
|
1219
|
+
}, [options.id]);
|
|
1220
|
+
useEffect(() => {
|
|
1221
|
+
raiseGridRowsRendered(gridApi, pipeline.visibleRows);
|
|
1222
|
+
raiseGridRowsVisibleChanged(gridApi, pipeline.visibleRows);
|
|
1223
|
+
const newHeight = pipeline.displayItems.length * rowSize;
|
|
1224
|
+
if (newHeight !== lastCanvasHeightRef.current) {
|
|
1225
|
+
raiseGridCanvasHeightChanged(gridApi, lastCanvasHeightRef.current, newHeight);
|
|
1226
|
+
lastCanvasHeightRef.current = newHeight;
|
|
1227
|
+
}
|
|
1228
|
+
}, [pipeline, gridApi, rowSize]);
|
|
1229
|
+
useEffect(() => {
|
|
1230
|
+
if (!FEATURE_AUTO_RESIZE || !options.enableAutoResize) return;
|
|
1231
|
+
const container = gridContainerRef.current;
|
|
1232
|
+
if (!container) return;
|
|
1233
|
+
const observer = observeGridHostSize(container, ({ height: nextHeight, width: nextWidth }) => {
|
|
1234
|
+
if (nextHeight === lastGridHeightRef.current && nextWidth === lastGridWidthRef.current) return;
|
|
1235
|
+
raiseGridDimensionChanged(gridApi, lastGridHeightRef.current, lastGridWidthRef.current, nextHeight, nextWidth);
|
|
1236
|
+
lastGridHeightRef.current = nextHeight;
|
|
1237
|
+
lastGridWidthRef.current = nextWidth;
|
|
1238
|
+
if (!options.viewportHeight && nextHeight > 0) {
|
|
1239
|
+
setAutoViewportHeight(nextHeight);
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
if (!observer) return;
|
|
1243
|
+
return () => observer.disconnect();
|
|
1244
|
+
}, [options.enableAutoResize, options.viewportHeight, gridApi]);
|
|
1245
|
+
const totalRows = pipeline.totalItems;
|
|
1246
|
+
const visibleRowCount = pipeline.visibleRows.length;
|
|
1247
|
+
const displayItems = pipeline.displayItems;
|
|
1248
|
+
const virtualizationEnabled = pipeline.virtualizationEnabled;
|
|
1249
|
+
const pipelineMsVal = pipeline.pipelineMs;
|
|
1250
|
+
const paginationCurrentPage = getCurrentPageValueFn();
|
|
1251
|
+
const paginationTotalPages = getTotalPagesValueFn();
|
|
1252
|
+
const paginationSelectedPageSize = effectivePageSizeFn(pipeline.totalItems);
|
|
1253
|
+
const viewportHeightPx = `${options.viewportHeight ?? autoViewportHeight ?? 560}px`;
|
|
1254
|
+
const headerLabelFn = useCallback((column) => coreHeaderLabel(column), []);
|
|
1255
|
+
const isGroupItemFn = useCallback((item) => item.kind === "group", []);
|
|
1256
|
+
const isExpandableItemFn = useCallback((item) => item.kind === "expandable", []);
|
|
1257
|
+
const isRowItemFn = useCallback((item) => item.kind === "row", []);
|
|
1258
|
+
const isOddStripedRowFn = useCallback((item) => item.kind === "row" && item.visibleIndex % 2 === 0, []);
|
|
1259
|
+
const sortDirectionFn = useCallback((column) => {
|
|
1260
|
+
return sortStateRef.current.columnName === column.name ? sortStateRef.current.direction : SORT_DIRECTIONS2.none;
|
|
1261
|
+
}, []);
|
|
1262
|
+
const sortButtonLabelFn = useCallback((column) => {
|
|
1263
|
+
return gridSortButtonLabel(sortDirectionFn(column), labels);
|
|
1264
|
+
}, [labels, sortDirectionFn]);
|
|
1265
|
+
const sortAriaSortFn = useCallback((column) => {
|
|
1266
|
+
return gridSortAriaSort(sortDirectionFn(column));
|
|
1267
|
+
}, [sortDirectionFn]);
|
|
1268
|
+
const groupingButtonLabelFn = useCallback((column) => {
|
|
1269
|
+
return gridGroupingButtonLabel(isGridColumnGrouped(groupByColumnsRef.current, column), labels);
|
|
1270
|
+
}, [labels]);
|
|
1271
|
+
const filterValueFn = useCallback((columnName) => {
|
|
1272
|
+
return activeFiltersRef.current[columnName] ?? "";
|
|
1273
|
+
}, []);
|
|
1274
|
+
const filterPlaceholderFn = useCallback((column) => {
|
|
1275
|
+
return gridFilterPlaceholder(isGridColumnFilterable(optionsRef.current, column), labels);
|
|
1276
|
+
}, [labels]);
|
|
1277
|
+
const isFilterInputDisabledFn = useCallback((column) => {
|
|
1278
|
+
return !isGridColumnFilterable(optionsRef.current, column);
|
|
1279
|
+
}, []);
|
|
1280
|
+
const groupDisclosureLabelFn = useCallback((item) => {
|
|
1281
|
+
return gridGroupDisclosureLabel(item.collapsed, labels);
|
|
1282
|
+
}, [labels]);
|
|
1283
|
+
const cellContextFn = useCallback((row, column) => {
|
|
1284
|
+
return buildGridCellContext(row, column);
|
|
1285
|
+
}, []);
|
|
1286
|
+
const displayValueFn = useCallback((row, column) => {
|
|
1287
|
+
return formatGridCellDisplayValue(cellContextFn(row, column));
|
|
1288
|
+
}, [cellContextFn]);
|
|
1289
|
+
const isFocusedCellFn = useCallback((row, column) => {
|
|
1290
|
+
return isGridCellPosition(focusedCellRef.current, row.id, column.name);
|
|
1291
|
+
}, []);
|
|
1292
|
+
const isEditingCellFn = useCallback((row, column) => {
|
|
1293
|
+
return isGridCellPosition(editingCellRef.current, row.id, column.name);
|
|
1294
|
+
}, []);
|
|
1295
|
+
const editorInputTypeFn = useCallback((column) => {
|
|
1296
|
+
return gridEditorInputType(column);
|
|
1297
|
+
}, []);
|
|
1298
|
+
const expandedContextFn = useCallback((row) => {
|
|
1299
|
+
return {
|
|
1300
|
+
$implicit: row.entity,
|
|
1301
|
+
row: row.entity,
|
|
1302
|
+
rowIndex: row.index,
|
|
1303
|
+
expanded: true,
|
|
1304
|
+
...optionsRef.current.expandableRowScope ?? {}
|
|
1305
|
+
};
|
|
1306
|
+
}, []);
|
|
1307
|
+
const columnWidthFn = useCallback((column) => gridColumnWidth(column), []);
|
|
1308
|
+
const isColumnSortableFn = useCallback((column) => {
|
|
1309
|
+
return isGridColumnSortable(optionsRef.current, column);
|
|
1310
|
+
}, []);
|
|
1311
|
+
const isColumnFilterableFn = useCallback((column) => {
|
|
1312
|
+
return isGridColumnFilterable(optionsRef.current, column);
|
|
1313
|
+
}, []);
|
|
1314
|
+
const cellIndentFn = useCallback((row, column) => {
|
|
1315
|
+
return gridCellIndent(optionsRef.current, visibleColumnsRef.current, row, column);
|
|
1316
|
+
}, []);
|
|
1317
|
+
const treeToggleLabelFn = useCallback((row) => {
|
|
1318
|
+
return gridTreeToggleLabelForRow(expandedTreeRowsRef.current, row, labels);
|
|
1319
|
+
}, [labels]);
|
|
1320
|
+
const isTreeRowExpandedFn = useCallback((row) => {
|
|
1321
|
+
return isGridTreeRowExpanded(expandedTreeRowsRef.current, row);
|
|
1322
|
+
}, []);
|
|
1323
|
+
const expandToggleLabelFn = useCallback((row) => {
|
|
1324
|
+
return gridExpandToggleLabelForRow(row, labels);
|
|
1325
|
+
}, [labels]);
|
|
1326
|
+
const isGroupedFn = useCallback((column) => {
|
|
1327
|
+
return isGridColumnGrouped(groupByColumnsRef.current, column);
|
|
1328
|
+
}, []);
|
|
1329
|
+
const showTreeToggleFn = useCallback((row, column) => {
|
|
1330
|
+
return shouldShowGridTreeToggle(optionsRef.current, visibleColumnsRef.current, row, column);
|
|
1331
|
+
}, []);
|
|
1332
|
+
const showExpandToggleFn = useCallback((row, column) => {
|
|
1333
|
+
return shouldShowGridExpandToggle(optionsRef.current, visibleColumnsRef.current, column);
|
|
1334
|
+
}, []);
|
|
1335
|
+
const showPaginationControlsFn = useCallback(() => {
|
|
1336
|
+
return FEATURE_PAGINATION && shouldShowGridPaginationControls(optionsRef.current);
|
|
1337
|
+
}, []);
|
|
1338
|
+
const paginationSummaryFn = useCallback(() => {
|
|
1339
|
+
const ti = pipelineRef.current.totalItems;
|
|
1340
|
+
if (ti === 0) return "0-0 of 0";
|
|
1341
|
+
return `${getFirstRowIndexValueFn(ti) + 1}-${getLastRowIndexValueFn(ti) + 1} of ${ti}`;
|
|
1342
|
+
}, [getFirstRowIndexValueFn, getLastRowIndexValueFn]);
|
|
1343
|
+
const pageSizeOptionsFn = useCallback(() => {
|
|
1344
|
+
return optionsRef.current.paginationPageSizes ?? [];
|
|
1345
|
+
}, []);
|
|
1346
|
+
const isGroupingEnabledFn = useCallback(() => {
|
|
1347
|
+
return FEATURE_GROUPING && isGridGroupingEnabled(optionsRef.current);
|
|
1348
|
+
}, []);
|
|
1349
|
+
const isFilteringEnabledFn = useCallback(() => {
|
|
1350
|
+
return FEATURE_FILTERING && isGridFilteringEnabled(optionsRef.current);
|
|
1351
|
+
}, []);
|
|
1352
|
+
const toggleSortFn = useCallback((column) => {
|
|
1353
|
+
if (!FEATURE_SORTING || !isGridColumnSortable(optionsRef.current, column)) return;
|
|
1354
|
+
const currentDirection = sortStateRef.current.columnName === column.name ? sortStateRef.current.direction : SORT_DIRECTIONS2.none;
|
|
1355
|
+
const nextDirection = currentDirection === SORT_DIRECTIONS2.none ? SORT_DIRECTIONS2.asc : currentDirection === SORT_DIRECTIONS2.asc ? SORT_DIRECTIONS2.desc : SORT_DIRECTIONS2.none;
|
|
1356
|
+
applyGridSortStateCommand(gridApiRef.current, (state) => setSortState(state), {
|
|
1357
|
+
columnName: nextDirection === SORT_DIRECTIONS2.none ? null : column.name,
|
|
1358
|
+
direction: nextDirection
|
|
1359
|
+
});
|
|
1360
|
+
}, []);
|
|
1361
|
+
const updateFilterFn = useCallback((columnName, value) => {
|
|
1362
|
+
updateGridFilterCommand(
|
|
1363
|
+
gridApiRef.current,
|
|
1364
|
+
(updater) => setActiveFilters((current) => updater(current)),
|
|
1365
|
+
() => activeFiltersRef.current,
|
|
1366
|
+
columnName,
|
|
1367
|
+
value
|
|
1368
|
+
);
|
|
1369
|
+
}, []);
|
|
1370
|
+
const clearAllFiltersFn = useCallback(() => {
|
|
1371
|
+
clearGridFiltersCommand(gridApiRef.current, (filters) => setActiveFilters(filters));
|
|
1372
|
+
}, []);
|
|
1373
|
+
const toggleGroupingFn = useCallback((column, event) => {
|
|
1374
|
+
event?.stopPropagation();
|
|
1375
|
+
if (!(FEATURE_GROUPING && isGridGroupingEnabled(optionsRef.current))) return;
|
|
1376
|
+
const current = groupByColumnsRef.current;
|
|
1377
|
+
const next = current.includes(column.name) ? current.filter((n) => n !== column.name) : [...current, column.name];
|
|
1378
|
+
groupByColumnsRef.current = next;
|
|
1379
|
+
setGroupByColumns(next);
|
|
1380
|
+
gridApiRef.current.core.raise.groupingChanged(next);
|
|
1381
|
+
}, []);
|
|
1382
|
+
const toggleGroupFn = useCallback((item) => {
|
|
1383
|
+
setCollapsedGroups((current) => ({
|
|
1384
|
+
...current,
|
|
1385
|
+
[item.id]: !current[item.id]
|
|
1386
|
+
}));
|
|
1387
|
+
}, []);
|
|
1388
|
+
const focusCellFn = useCallback((row, column, triggerEvent) => {
|
|
1389
|
+
const nextFocusResult = buildGridFocusCellResult({
|
|
1390
|
+
currentFocusedCell: focusedCellRef.current,
|
|
1391
|
+
currentEditingCell: editingCellRef.current,
|
|
1392
|
+
rowId: row.id,
|
|
1393
|
+
columnName: column.name,
|
|
1394
|
+
shouldEditOnFocus: shouldEditOnFocusFn(column),
|
|
1395
|
+
isCellEditable: isCellEditable(row, column, triggerEvent)
|
|
1396
|
+
});
|
|
1397
|
+
setFocusedCell(nextFocusResult.focusedCell);
|
|
1398
|
+
if (nextFocusResult.shouldBeginEdit) {
|
|
1399
|
+
startCellEditFn(row, column, triggerEvent);
|
|
1400
|
+
}
|
|
1401
|
+
}, [isCellEditable, shouldEditOnFocusFn, startCellEditFn]);
|
|
1402
|
+
const handleCellKeyDownFn = useCallback((row, column, event) => {
|
|
1403
|
+
focusCellFn(row, column, event.nativeEvent);
|
|
1404
|
+
switch (event.key) {
|
|
1405
|
+
case "ArrowLeft":
|
|
1406
|
+
event.preventDefault();
|
|
1407
|
+
moveFocusFn(row, column, "left", event.nativeEvent);
|
|
1408
|
+
return;
|
|
1409
|
+
case "ArrowRight":
|
|
1410
|
+
event.preventDefault();
|
|
1411
|
+
moveFocusFn(row, column, "right", event.nativeEvent);
|
|
1412
|
+
return;
|
|
1413
|
+
case "ArrowUp":
|
|
1414
|
+
event.preventDefault();
|
|
1415
|
+
moveFocusFn(row, column, "up", event.nativeEvent);
|
|
1416
|
+
return;
|
|
1417
|
+
case "ArrowDown":
|
|
1418
|
+
event.preventDefault();
|
|
1419
|
+
moveFocusFn(row, column, "down", event.nativeEvent);
|
|
1420
|
+
return;
|
|
1421
|
+
case "Tab":
|
|
1422
|
+
event.preventDefault();
|
|
1423
|
+
moveFocusFn(row, column, event.shiftKey ? "left" : "right", event.nativeEvent);
|
|
1424
|
+
return;
|
|
1425
|
+
case "Enter":
|
|
1426
|
+
event.preventDefault();
|
|
1427
|
+
moveFocusFn(row, column, event.shiftKey ? "up" : "down", event.nativeEvent);
|
|
1428
|
+
return;
|
|
1429
|
+
case "F2":
|
|
1430
|
+
event.preventDefault();
|
|
1431
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1432
|
+
startCellEditFn(row, column, event.nativeEvent);
|
|
1433
|
+
}
|
|
1434
|
+
return;
|
|
1435
|
+
case "Backspace":
|
|
1436
|
+
case "Delete":
|
|
1437
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1438
|
+
event.preventDefault();
|
|
1439
|
+
startCellEditFn(row, column, event.nativeEvent, "");
|
|
1440
|
+
}
|
|
1441
|
+
return;
|
|
1442
|
+
default:
|
|
1443
|
+
break;
|
|
1444
|
+
}
|
|
1445
|
+
if (isPrintableGridKey(event.key, event.ctrlKey, event.metaKey, event.altKey) && isCellEditable(row, column, event.nativeEvent)) {
|
|
1446
|
+
event.preventDefault();
|
|
1447
|
+
startCellEditFn(row, column, event.nativeEvent, event.key);
|
|
1448
|
+
}
|
|
1449
|
+
}, [focusCellFn, moveFocusFn, isCellEditable, startCellEditFn]);
|
|
1450
|
+
const handleCellDoubleClickFn = useCallback((row, column, event) => {
|
|
1451
|
+
focusCellFn(row, column, event.nativeEvent);
|
|
1452
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1453
|
+
startCellEditFn(row, column, event.nativeEvent);
|
|
1454
|
+
}
|
|
1455
|
+
}, [focusCellFn, isCellEditable, startCellEditFn]);
|
|
1456
|
+
const updateEditingValueFn = useCallback((value) => {
|
|
1457
|
+
setEditingValue(value);
|
|
1458
|
+
}, []);
|
|
1459
|
+
const handleEditorKeyDownFn = useCallback((event) => {
|
|
1460
|
+
if (event.key === "Escape") {
|
|
1461
|
+
event.preventDefault();
|
|
1462
|
+
cancelCellEditFn();
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
if (event.key === "Enter") {
|
|
1466
|
+
event.preventDefault();
|
|
1467
|
+
commitCellEditFn(event.shiftKey ? "up" : "down");
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
if (event.key === "Tab") {
|
|
1471
|
+
event.preventDefault();
|
|
1472
|
+
commitCellEditFn(event.shiftKey ? "left" : "right");
|
|
1473
|
+
}
|
|
1474
|
+
}, [cancelCellEditFn, commitCellEditFn]);
|
|
1475
|
+
const handleEditorBlurFn = useCallback((event) => {
|
|
1476
|
+
const ec = editingCellRef.current;
|
|
1477
|
+
const target = event.target;
|
|
1478
|
+
if (!ec || !target) return;
|
|
1479
|
+
if (target.dataset["rowId"] !== ec.rowId || target.dataset["colName"] !== ec.columnName) return;
|
|
1480
|
+
commitCellEditFn(void 0, false);
|
|
1481
|
+
}, [commitCellEditFn]);
|
|
1482
|
+
const toggleRowExpansionFn = useCallback((row, event) => {
|
|
1483
|
+
event?.stopPropagation();
|
|
1484
|
+
toggleRowExpansionByRefFn(row);
|
|
1485
|
+
}, [toggleRowExpansionByRefFn]);
|
|
1486
|
+
const toggleTreeRowFn = useCallback((row, event) => {
|
|
1487
|
+
event?.stopPropagation();
|
|
1488
|
+
toggleTreeRowByRefFn(row);
|
|
1489
|
+
}, [toggleTreeRowByRefFn]);
|
|
1490
|
+
const moveColumnFn = useCallback((fromIndex, toIndex) => {
|
|
1491
|
+
moveGridColumnCommand(
|
|
1492
|
+
gridApiRef.current,
|
|
1493
|
+
FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
|
|
1494
|
+
(updater) => setColumnOrder((current) => updater(current)),
|
|
1495
|
+
fromIndex,
|
|
1496
|
+
toIndex
|
|
1497
|
+
);
|
|
1498
|
+
}, []);
|
|
1499
|
+
const nextPageFn = useCallback(() => {
|
|
1500
|
+
seekPageFn(getCurrentPageValueFn() + 1);
|
|
1501
|
+
}, [seekPageFn, getCurrentPageValueFn]);
|
|
1502
|
+
const previousPageFn = useCallback(() => {
|
|
1503
|
+
seekPageFn(getCurrentPageValueFn() - 1);
|
|
1504
|
+
}, [seekPageFn, getCurrentPageValueFn]);
|
|
1505
|
+
const onPageSizeChangeFn = useCallback((value) => {
|
|
1506
|
+
setPaginationPageSizeFn(Number(value));
|
|
1507
|
+
}, [setPaginationPageSizeFn]);
|
|
1508
|
+
const onViewportScrollFn = useCallback((startIndex) => {
|
|
1509
|
+
if (!scrollingRef.current) {
|
|
1510
|
+
scrollingRef.current = true;
|
|
1511
|
+
raiseGridScrollBegin(gridApiRef.current);
|
|
1512
|
+
}
|
|
1513
|
+
if (scrollEndHandleRef.current) {
|
|
1514
|
+
window.clearTimeout(scrollEndHandleRef.current);
|
|
1515
|
+
}
|
|
1516
|
+
scrollEndHandleRef.current = window.setTimeout(() => {
|
|
1517
|
+
scrollingRef.current = false;
|
|
1518
|
+
raiseGridScrollEnd(gridApiRef.current);
|
|
1519
|
+
}, 120);
|
|
1520
|
+
const isInfiniteScrollEnabled = FEATURE_INFINITE_SCROLL && (optionsRef.current.infiniteScrollRowsFromEnd !== void 0 || optionsRef.current.infiniteScrollUp === true || optionsRef.current.infiniteScrollDown !== void 0);
|
|
1521
|
+
maybeRequestInfiniteScrollCommand(gridApiRef.current, {
|
|
1522
|
+
enabled: isInfiniteScrollEnabled,
|
|
1523
|
+
virtualizationEnabled: pipelineRef.current.virtualizationEnabled,
|
|
1524
|
+
state: infiniteScrollStateRef.current,
|
|
1525
|
+
startIndex,
|
|
1526
|
+
visibleRows: pipelineRef.current.visibleRows.length,
|
|
1527
|
+
viewportRows: Math.max(1, Math.ceil((optionsRef.current.viewportHeight ?? 560) / (optionsRef.current.rowHeight ?? 44))),
|
|
1528
|
+
threshold: optionsRef.current.infiniteScrollRowsFromEnd ?? 20,
|
|
1529
|
+
setState: (state) => setInfiniteScrollState(state)
|
|
1530
|
+
});
|
|
1531
|
+
}, []);
|
|
1532
|
+
return {
|
|
1533
|
+
pipeline,
|
|
1534
|
+
visibleColumns,
|
|
1535
|
+
labels,
|
|
1536
|
+
gridTemplateColumns,
|
|
1537
|
+
gridApi,
|
|
1538
|
+
gridContainerRef,
|
|
1539
|
+
activeFilters,
|
|
1540
|
+
groupByColumns,
|
|
1541
|
+
collapsedGroups,
|
|
1542
|
+
sortState,
|
|
1543
|
+
focusedCell,
|
|
1544
|
+
editingCell,
|
|
1545
|
+
editingValue,
|
|
1546
|
+
expandedRows,
|
|
1547
|
+
expandedTreeRows,
|
|
1548
|
+
currentPage,
|
|
1549
|
+
pageSize,
|
|
1550
|
+
benchmarkResult,
|
|
1551
|
+
infiniteScrollState,
|
|
1552
|
+
totalRows,
|
|
1553
|
+
visibleRowCount,
|
|
1554
|
+
displayItems,
|
|
1555
|
+
virtualizationEnabled,
|
|
1556
|
+
pipelineMs: pipelineMsVal,
|
|
1557
|
+
paginationCurrentPage,
|
|
1558
|
+
paginationTotalPages,
|
|
1559
|
+
paginationSelectedPageSize,
|
|
1560
|
+
rowSize,
|
|
1561
|
+
viewportHeightPx,
|
|
1562
|
+
headerLabel: headerLabelFn,
|
|
1563
|
+
isGroupItem: isGroupItemFn,
|
|
1564
|
+
isExpandableItem: isExpandableItemFn,
|
|
1565
|
+
isRowItem: isRowItemFn,
|
|
1566
|
+
isOddStripedRow: isOddStripedRowFn,
|
|
1567
|
+
sortButtonLabel: sortButtonLabelFn,
|
|
1568
|
+
sortAriaSort: sortAriaSortFn,
|
|
1569
|
+
sortDirection: sortDirectionFn,
|
|
1570
|
+
groupingButtonLabel: groupingButtonLabelFn,
|
|
1571
|
+
filterValue: filterValueFn,
|
|
1572
|
+
filterPlaceholder: filterPlaceholderFn,
|
|
1573
|
+
isFilterInputDisabled: isFilterInputDisabledFn,
|
|
1574
|
+
groupDisclosureLabel: groupDisclosureLabelFn,
|
|
1575
|
+
displayValue: displayValueFn,
|
|
1576
|
+
isFocusedCell: isFocusedCellFn,
|
|
1577
|
+
isEditingCell: isEditingCellFn,
|
|
1578
|
+
editorInputType: editorInputTypeFn,
|
|
1579
|
+
cellContext: cellContextFn,
|
|
1580
|
+
expandedContext: expandedContextFn,
|
|
1581
|
+
columnWidth: columnWidthFn,
|
|
1582
|
+
isColumnSortable: isColumnSortableFn,
|
|
1583
|
+
isColumnFilterable: isColumnFilterableFn,
|
|
1584
|
+
cellIndent: cellIndentFn,
|
|
1585
|
+
treeToggleLabel: treeToggleLabelFn,
|
|
1586
|
+
isTreeRowExpanded: isTreeRowExpandedFn,
|
|
1587
|
+
expandToggleLabel: expandToggleLabelFn,
|
|
1588
|
+
isGrouped: isGroupedFn,
|
|
1589
|
+
showTreeToggle: showTreeToggleFn,
|
|
1590
|
+
showExpandToggle: showExpandToggleFn,
|
|
1591
|
+
showPaginationControls: showPaginationControlsFn,
|
|
1592
|
+
paginationSummary: paginationSummaryFn,
|
|
1593
|
+
pageSizeOptions: pageSizeOptionsFn,
|
|
1594
|
+
isCellEditable,
|
|
1595
|
+
shouldEditOnFocus: shouldEditOnFocusFn,
|
|
1596
|
+
sortingFeature: FEATURE_SORTING,
|
|
1597
|
+
filteringFeature: FEATURE_FILTERING,
|
|
1598
|
+
groupingFeature: FEATURE_GROUPING,
|
|
1599
|
+
paginationFeature: FEATURE_PAGINATION,
|
|
1600
|
+
cellEditFeature: FEATURE_CELL_EDIT,
|
|
1601
|
+
expandableFeature: FEATURE_EXPANDABLE,
|
|
1602
|
+
treeViewFeature: FEATURE_TREE_VIEW,
|
|
1603
|
+
infiniteScrollFeature: FEATURE_INFINITE_SCROLL,
|
|
1604
|
+
columnMovingFeature: FEATURE_COLUMN_MOVING,
|
|
1605
|
+
csvExportFeature: FEATURE_CSV_EXPORT,
|
|
1606
|
+
isGroupingEnabled: isGroupingEnabledFn,
|
|
1607
|
+
isFilteringEnabled: isFilteringEnabledFn,
|
|
1608
|
+
toggleSort: toggleSortFn,
|
|
1609
|
+
updateFilter: updateFilterFn,
|
|
1610
|
+
clearAllFilters: clearAllFiltersFn,
|
|
1611
|
+
toggleGrouping: toggleGroupingFn,
|
|
1612
|
+
toggleGroup: toggleGroupFn,
|
|
1613
|
+
focusCell: focusCellFn,
|
|
1614
|
+
handleCellKeyDown: handleCellKeyDownFn,
|
|
1615
|
+
handleCellDoubleClick: handleCellDoubleClickFn,
|
|
1616
|
+
updateEditingValue: updateEditingValueFn,
|
|
1617
|
+
handleEditorKeyDown: handleEditorKeyDownFn,
|
|
1618
|
+
handleEditorBlur: handleEditorBlurFn,
|
|
1619
|
+
toggleRowExpansion: toggleRowExpansionFn,
|
|
1620
|
+
toggleTreeRow: toggleTreeRowFn,
|
|
1621
|
+
moveColumn: moveColumnFn,
|
|
1622
|
+
nextPage: nextPageFn,
|
|
1623
|
+
previousPage: previousPageFn,
|
|
1624
|
+
onPageSizeChange: onPageSizeChangeFn,
|
|
1625
|
+
runBenchmark: runBenchmarkFn,
|
|
1626
|
+
exportCsv: exportCsvFn,
|
|
1627
|
+
onViewportScroll: onViewportScrollFn
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// src/useVirtualScroll.ts
|
|
1632
|
+
import { useCallback as useCallback2, useRef as useRef2, useState as useState2 } from "react";
|
|
1633
|
+
function useVirtualScroll(options) {
|
|
1634
|
+
const { itemCount, itemSize, viewportHeight, overscan = 3 } = options;
|
|
1635
|
+
const [scrollTop, setScrollTop] = useState2(0);
|
|
1636
|
+
const viewportRef = useRef2(null);
|
|
1637
|
+
const rawStart = Math.floor(scrollTop / itemSize) - overscan;
|
|
1638
|
+
const start = Math.max(0, rawStart);
|
|
1639
|
+
const rawEnd = rawStart + Math.ceil(viewportHeight / itemSize) + 2 * overscan;
|
|
1640
|
+
const end = Math.min(itemCount, rawEnd);
|
|
1641
|
+
const totalHeight = itemCount * itemSize;
|
|
1642
|
+
const offsetY = start * itemSize;
|
|
1643
|
+
const onScroll = useCallback2((event) => {
|
|
1644
|
+
setScrollTop(event.currentTarget.scrollTop);
|
|
1645
|
+
}, []);
|
|
1646
|
+
return {
|
|
1647
|
+
visibleRange: { start, end },
|
|
1648
|
+
totalHeight,
|
|
1649
|
+
offsetY,
|
|
1650
|
+
onScroll,
|
|
1651
|
+
viewportRef,
|
|
1652
|
+
scrollTop
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/UiGrid.tsx
|
|
1657
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1658
|
+
function UiGrid({ options, onRegisterApi, cellRenderer, expandableRenderer, className }) {
|
|
1659
|
+
const state = useGridState(options, onRegisterApi);
|
|
1660
|
+
const {
|
|
1661
|
+
pipeline,
|
|
1662
|
+
visibleColumns,
|
|
1663
|
+
labels,
|
|
1664
|
+
gridTemplateColumns,
|
|
1665
|
+
gridContainerRef,
|
|
1666
|
+
displayItems,
|
|
1667
|
+
virtualizationEnabled,
|
|
1668
|
+
pipelineMs,
|
|
1669
|
+
visibleRowCount,
|
|
1670
|
+
totalRows,
|
|
1671
|
+
benchmarkResult,
|
|
1672
|
+
rowSize,
|
|
1673
|
+
viewportHeightPx,
|
|
1674
|
+
editingValue,
|
|
1675
|
+
sortingFeature,
|
|
1676
|
+
filteringFeature,
|
|
1677
|
+
groupingFeature,
|
|
1678
|
+
paginationFeature,
|
|
1679
|
+
cellEditFeature,
|
|
1680
|
+
expandableFeature,
|
|
1681
|
+
treeViewFeature,
|
|
1682
|
+
csvExportFeature,
|
|
1683
|
+
paginationCurrentPage,
|
|
1684
|
+
paginationTotalPages,
|
|
1685
|
+
paginationSelectedPageSize
|
|
1686
|
+
} = state;
|
|
1687
|
+
const virtualScroll = useVirtualScroll({
|
|
1688
|
+
itemCount: displayItems.length,
|
|
1689
|
+
itemSize: rowSize,
|
|
1690
|
+
viewportHeight: options.viewportHeight ?? 560,
|
|
1691
|
+
overscan: 3
|
|
1692
|
+
});
|
|
1693
|
+
const itemsToRender = virtualizationEnabled ? displayItems.slice(virtualScroll.visibleRange.start, virtualScroll.visibleRange.end) : displayItems;
|
|
1694
|
+
const onViewportScroll = (event) => {
|
|
1695
|
+
virtualScroll.onScroll(event);
|
|
1696
|
+
const startIndex = Math.floor(event.currentTarget.scrollTop / rowSize);
|
|
1697
|
+
state.onViewportScroll(startIndex);
|
|
1698
|
+
};
|
|
1699
|
+
function renderDisplayItem(item) {
|
|
1700
|
+
if (groupingFeature && state.isGroupItem(item)) {
|
|
1701
|
+
return /* @__PURE__ */ jsxs(
|
|
1702
|
+
"button",
|
|
1703
|
+
{
|
|
1704
|
+
type: "button",
|
|
1705
|
+
className: "group-row ui-grid-row ui-grid-group-row",
|
|
1706
|
+
"data-part": "group-row",
|
|
1707
|
+
role: "row",
|
|
1708
|
+
"aria-expanded": !item.collapsed,
|
|
1709
|
+
style: { gridColumn: "1 / -1", paddingInlineStart: `${item.depth * 1.25 + 1}rem` },
|
|
1710
|
+
onClick: () => state.toggleGroup(item),
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
1713
|
+
item.field,
|
|
1714
|
+
": ",
|
|
1715
|
+
item.label
|
|
1716
|
+
] }),
|
|
1717
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1718
|
+
item.count,
|
|
1719
|
+
" ",
|
|
1720
|
+
labels.groupRowsSuffix
|
|
1721
|
+
] }),
|
|
1722
|
+
/* @__PURE__ */ jsx("svg", { className: "toggle-icon group-disclosure-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: item.collapsed ? "M10 7l5 5-5 5z" : "M7 10l5 5 5-5z" }) }),
|
|
1723
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only ui-grid-sr-only", children: state.groupDisclosureLabel(item) })
|
|
1724
|
+
]
|
|
1725
|
+
},
|
|
1726
|
+
item.id
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
if (expandableFeature && state.isExpandableItem(item)) {
|
|
1730
|
+
const ctx = state.expandedContext(item.row);
|
|
1731
|
+
return /* @__PURE__ */ jsx(
|
|
1732
|
+
"div",
|
|
1733
|
+
{
|
|
1734
|
+
className: "expandable-row ui-grid-row ui-grid-expandable-row",
|
|
1735
|
+
"data-part": "expandable-row",
|
|
1736
|
+
style: { gridColumn: "1 / -1", minHeight: `${item.row.expandedRowHeight}px` },
|
|
1737
|
+
children: expandableRenderer?.(ctx)
|
|
1738
|
+
},
|
|
1739
|
+
item.id
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
if (item.kind !== "row") return null;
|
|
1743
|
+
const rowItem = item;
|
|
1744
|
+
return visibleColumns.map((column) => /* @__PURE__ */ jsx(
|
|
1745
|
+
"div",
|
|
1746
|
+
{
|
|
1747
|
+
className: cellClassName(rowItem, column),
|
|
1748
|
+
"data-part": "body-cell",
|
|
1749
|
+
role: "gridcell",
|
|
1750
|
+
tabIndex: 0,
|
|
1751
|
+
"data-row-id": rowItem.row.id,
|
|
1752
|
+
"data-col-name": column.name,
|
|
1753
|
+
onFocus: () => state.focusCell(rowItem.row, column),
|
|
1754
|
+
onClick: () => state.focusCell(rowItem.row, column),
|
|
1755
|
+
onDoubleClick: (e) => state.handleCellDoubleClick(rowItem.row, column, e),
|
|
1756
|
+
onKeyDown: (e) => state.handleCellKeyDown(rowItem.row, column, e),
|
|
1757
|
+
children: /* @__PURE__ */ jsxs("div", { className: "cell-shell", style: { paddingInlineStart: state.cellIndent(rowItem.row, column) }, children: [
|
|
1758
|
+
treeViewFeature && state.showTreeToggle(rowItem.row, column) && /* @__PURE__ */ jsx(
|
|
1759
|
+
"button",
|
|
1760
|
+
{
|
|
1761
|
+
type: "button",
|
|
1762
|
+
className: "row-toggle row-toggle-tree",
|
|
1763
|
+
"data-part": "tree-toggle",
|
|
1764
|
+
"aria-label": state.treeToggleLabel(rowItem.row),
|
|
1765
|
+
"aria-expanded": state.isTreeRowExpanded(rowItem.row),
|
|
1766
|
+
onClick: (e) => state.toggleTreeRow(rowItem.row, e),
|
|
1767
|
+
children: /* @__PURE__ */ jsx("svg", { className: "toggle-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: state.isTreeRowExpanded(rowItem.row) ? "M7 10l5 5 5-5z" : "M10 7l5 5-5 5z" }) })
|
|
1768
|
+
}
|
|
1769
|
+
),
|
|
1770
|
+
expandableFeature && state.showExpandToggle(rowItem.row, column) && /* @__PURE__ */ jsx(
|
|
1771
|
+
"button",
|
|
1772
|
+
{
|
|
1773
|
+
type: "button",
|
|
1774
|
+
className: "row-toggle row-toggle-expand",
|
|
1775
|
+
"data-part": "expand-toggle",
|
|
1776
|
+
"aria-label": state.expandToggleLabel(rowItem.row),
|
|
1777
|
+
"aria-expanded": rowItem.row.expanded,
|
|
1778
|
+
onClick: (e) => state.toggleRowExpansion(rowItem.row, e),
|
|
1779
|
+
children: /* @__PURE__ */ jsx("svg", { className: "toggle-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: rowItem.row.expanded ? "M7 10l5 5 5-5z" : "M10 7l5 5-5 5z" }) })
|
|
1780
|
+
}
|
|
1781
|
+
),
|
|
1782
|
+
/* @__PURE__ */ jsx("span", { className: "cell-value", children: cellEditFeature && state.isEditingCell(rowItem.row, column) ? /* @__PURE__ */ jsx(
|
|
1783
|
+
"input",
|
|
1784
|
+
{
|
|
1785
|
+
className: "cell-editor",
|
|
1786
|
+
"data-row-id": rowItem.row.id,
|
|
1787
|
+
"data-col-name": column.name,
|
|
1788
|
+
"aria-label": state.headerLabel(column),
|
|
1789
|
+
type: state.editorInputType(column),
|
|
1790
|
+
defaultValue: editingValue,
|
|
1791
|
+
onChange: (e) => state.updateEditingValue(e.target.value),
|
|
1792
|
+
onKeyDown: (e) => state.handleEditorKeyDown(e),
|
|
1793
|
+
onBlur: (e) => state.handleEditorBlur(e)
|
|
1794
|
+
}
|
|
1795
|
+
) : cellRenderer ? cellRenderer(state.cellContext(rowItem.row, column)) ?? state.displayValue(rowItem.row, column) : state.displayValue(rowItem.row, column) })
|
|
1796
|
+
] })
|
|
1797
|
+
},
|
|
1798
|
+
`${rowItem.row.id}-${column.name}`
|
|
1799
|
+
));
|
|
1800
|
+
}
|
|
1801
|
+
function cellClassName(item, column) {
|
|
1802
|
+
const classes = ["body-cell", "ui-grid-cell"];
|
|
1803
|
+
if (state.isOddStripedRow(item)) classes.push("body-cell-odd");
|
|
1804
|
+
if (column.align === "center") classes.push("align-center");
|
|
1805
|
+
if (column.align === "end") classes.push("align-end");
|
|
1806
|
+
if (state.isFocusedCell(item.row, column)) classes.push("cell-focused");
|
|
1807
|
+
if (cellEditFeature && state.isEditingCell(item.row, column)) classes.push("cell-editing");
|
|
1808
|
+
return classes.join(" ");
|
|
1809
|
+
}
|
|
1810
|
+
function renderSortIcon(column) {
|
|
1811
|
+
const direction = state.sortDirection(column);
|
|
1812
|
+
switch (direction) {
|
|
1813
|
+
case "asc":
|
|
1814
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M12 5l-6 6h4v8h4v-8h4z" }) });
|
|
1815
|
+
case "desc":
|
|
1816
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M12 19l6-6h-4V5h-4v8H6z" }) });
|
|
1817
|
+
default:
|
|
1818
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M7 6h10v2H7V6Zm0 5h7v2H7v-2Zm0 5h4v2H7v-2Z" }) });
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
return /* @__PURE__ */ jsx("div", { className: `ui-grid-host ${className ?? ""}`, ref: gridContainerRef, children: /* @__PURE__ */ jsxs("section", { className: "grid-shell ui-grid-shell", "data-part": "shell", children: [
|
|
1822
|
+
/* @__PURE__ */ jsxs("header", { className: "grid-hero ui-grid-toolbar-shell", "data-part": "hero", children: [
|
|
1823
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1824
|
+
/* @__PURE__ */ jsx("p", { className: "eyebrow", children: "React wrapper for @ornery/ui-grid" }),
|
|
1825
|
+
/* @__PURE__ */ jsx("h1", { children: options.title ?? "UI Grid" }),
|
|
1826
|
+
/* @__PURE__ */ jsx("p", { className: "deck", children: "Familiar `gridOptions` and `onRegisterApi`, built with React hooks, virtualization, grouping, sorting, filtering, and column ordering." })
|
|
1827
|
+
] }),
|
|
1828
|
+
/* @__PURE__ */ jsxs("div", { className: "hero-actions", children: [
|
|
1829
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "action action-secondary", "data-part": "action benchmark-action", onClick: () => state.runBenchmark(), children: "Benchmark" }),
|
|
1830
|
+
csvExportFeature && /* @__PURE__ */ jsx("button", { type: "button", className: "action action-secondary", "data-part": "action export-action", onClick: () => state.exportCsv(), children: "Export CSV" }),
|
|
1831
|
+
/* @__PURE__ */ jsxs("div", { className: "stats-card", "data-part": "stats-card", children: [
|
|
1832
|
+
/* @__PURE__ */ jsx("span", { children: visibleRowCount }),
|
|
1833
|
+
/* @__PURE__ */ jsx("small", { children: labels.statsVisibleRows })
|
|
1834
|
+
] })
|
|
1835
|
+
] })
|
|
1836
|
+
] }),
|
|
1837
|
+
/* @__PURE__ */ jsxs("section", { className: "metrics-strip", "data-part": "metrics", "aria-label": "Grid performance metrics", children: [
|
|
1838
|
+
/* @__PURE__ */ jsxs("article", { "data-part": "metric-card", children: [
|
|
1839
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
1840
|
+
pipelineMs.toFixed(2),
|
|
1841
|
+
" ms"
|
|
1842
|
+
] }),
|
|
1843
|
+
/* @__PURE__ */ jsx("span", { children: "pipeline" })
|
|
1844
|
+
] }),
|
|
1845
|
+
/* @__PURE__ */ jsxs("article", { "data-part": "metric-card", children: [
|
|
1846
|
+
/* @__PURE__ */ jsx("strong", { children: virtualizationEnabled ? "On" : "Off" }),
|
|
1847
|
+
/* @__PURE__ */ jsx("span", { children: "virtualization" })
|
|
1848
|
+
] }),
|
|
1849
|
+
/* @__PURE__ */ jsxs("article", { "data-part": "metric-card", children: [
|
|
1850
|
+
/* @__PURE__ */ jsx("strong", { children: state.groupByColumns.length }),
|
|
1851
|
+
/* @__PURE__ */ jsx("span", { children: "group columns" })
|
|
1852
|
+
] }),
|
|
1853
|
+
/* @__PURE__ */ jsxs("article", { "data-part": "metric-card", children: [
|
|
1854
|
+
/* @__PURE__ */ jsx("strong", { children: benchmarkResult?.averageMs?.toFixed(2) || "\u2014" }),
|
|
1855
|
+
/* @__PURE__ */ jsx("span", { children: "benchmark avg" })
|
|
1856
|
+
] })
|
|
1857
|
+
] }),
|
|
1858
|
+
/* @__PURE__ */ jsxs("section", { className: "grid-frame ui-grid", "data-part": "grid-frame", role: "grid", "aria-label": options.title ?? "Data grid", children: [
|
|
1859
|
+
/* @__PURE__ */ jsxs("div", { className: "grid-toolbar", "data-part": "grid-toolbar", children: [
|
|
1860
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1861
|
+
/* @__PURE__ */ jsx("strong", { children: visibleRowCount }),
|
|
1862
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1863
|
+
labels.toolbarOf,
|
|
1864
|
+
" ",
|
|
1865
|
+
totalRows,
|
|
1866
|
+
" ",
|
|
1867
|
+
labels.toolbarRows
|
|
1868
|
+
] })
|
|
1869
|
+
] }),
|
|
1870
|
+
/* @__PURE__ */ jsx("p", { children: "`gridOptions` compatibility layer: sorting, filtering, grouping, column moving, templating, and virtualized rendering." })
|
|
1871
|
+
] }),
|
|
1872
|
+
/* @__PURE__ */ jsxs("div", { className: "grid-table ui-grid-contents-wrapper", "data-part": "grid-table", children: [
|
|
1873
|
+
/* @__PURE__ */ jsx(
|
|
1874
|
+
"div",
|
|
1875
|
+
{
|
|
1876
|
+
className: "header-grid ui-grid-header ui-grid-header-canvas",
|
|
1877
|
+
"data-part": "header",
|
|
1878
|
+
role: "row",
|
|
1879
|
+
style: { gridTemplateColumns },
|
|
1880
|
+
children: visibleColumns.map((column) => /* @__PURE__ */ jsxs(
|
|
1881
|
+
"div",
|
|
1882
|
+
{
|
|
1883
|
+
className: `header-cell ui-grid-header-cell${sortingFeature && state.sortDirection(column) !== "none" ? " is-active" : ""}`,
|
|
1884
|
+
"data-part": "header-cell",
|
|
1885
|
+
role: "columnheader",
|
|
1886
|
+
"aria-sort": sortingFeature ? state.sortAriaSort(column) : void 0,
|
|
1887
|
+
children: [
|
|
1888
|
+
/* @__PURE__ */ jsx("span", { className: "header-label", children: state.headerLabel(column) }),
|
|
1889
|
+
/* @__PURE__ */ jsxs("div", { className: "header-actions", children: [
|
|
1890
|
+
sortingFeature && /* @__PURE__ */ jsxs(
|
|
1891
|
+
"button",
|
|
1892
|
+
{
|
|
1893
|
+
type: "button",
|
|
1894
|
+
className: `header-action${!state.isColumnSortable(column) ? " header-action-disabled" : ""}`,
|
|
1895
|
+
disabled: !state.isColumnSortable(column),
|
|
1896
|
+
"aria-label": state.sortButtonLabel(column),
|
|
1897
|
+
title: state.sortButtonLabel(column),
|
|
1898
|
+
onClick: () => state.toggleSort(column),
|
|
1899
|
+
children: [
|
|
1900
|
+
renderSortIcon(column),
|
|
1901
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only ui-grid-sr-only", children: state.sortButtonLabel(column) })
|
|
1902
|
+
]
|
|
1903
|
+
}
|
|
1904
|
+
),
|
|
1905
|
+
groupingFeature && state.isGroupingEnabled() && column.enableGrouping !== false && /* @__PURE__ */ jsxs(
|
|
1906
|
+
"button",
|
|
1907
|
+
{
|
|
1908
|
+
type: "button",
|
|
1909
|
+
className: `chip-action${state.isGrouped(column) ? " chip-action-active" : ""}`,
|
|
1910
|
+
"data-part": "group-toggle",
|
|
1911
|
+
"aria-label": state.groupingButtonLabel(column),
|
|
1912
|
+
title: state.groupingButtonLabel(column),
|
|
1913
|
+
onClick: (e) => state.toggleGrouping(column, e),
|
|
1914
|
+
children: [
|
|
1915
|
+
/* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M4 6h8v4H4V6Zm0 8h8v4H4v-4Zm10-8h6v4h-6V6Zm0 8h6v4h-6v-4Z" }) }),
|
|
1916
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only ui-grid-sr-only", children: state.groupingButtonLabel(column) })
|
|
1917
|
+
]
|
|
1918
|
+
}
|
|
1919
|
+
)
|
|
1920
|
+
] })
|
|
1921
|
+
]
|
|
1922
|
+
},
|
|
1923
|
+
column.name
|
|
1924
|
+
))
|
|
1925
|
+
}
|
|
1926
|
+
),
|
|
1927
|
+
filteringFeature && state.isFilteringEnabled() && /* @__PURE__ */ jsx("div", { className: "filter-grid ui-grid-header", "data-part": "filters", style: { gridTemplateColumns }, children: visibleColumns.map((column) => /* @__PURE__ */ jsxs("label", { className: "filter-cell ui-grid-filter-container", "data-part": "filter-cell", children: [
|
|
1928
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only ui-grid-sr-only", children: [
|
|
1929
|
+
labels.filterColumn,
|
|
1930
|
+
" ",
|
|
1931
|
+
state.headerLabel(column)
|
|
1932
|
+
] }),
|
|
1933
|
+
/* @__PURE__ */ jsx(
|
|
1934
|
+
"input",
|
|
1935
|
+
{
|
|
1936
|
+
className: "ui-grid-filter-input",
|
|
1937
|
+
type: "text",
|
|
1938
|
+
defaultValue: state.filterValue(column.name),
|
|
1939
|
+
placeholder: state.filterPlaceholder(column),
|
|
1940
|
+
disabled: state.isFilterInputDisabled(column),
|
|
1941
|
+
onChange: (e) => state.updateFilter(column.name, e.target.value)
|
|
1942
|
+
}
|
|
1943
|
+
)
|
|
1944
|
+
] }, column.name)) }),
|
|
1945
|
+
displayItems.length > 0 ? virtualizationEnabled ? /* @__PURE__ */ jsx(
|
|
1946
|
+
"div",
|
|
1947
|
+
{
|
|
1948
|
+
className: "grid-viewport ui-grid-viewport",
|
|
1949
|
+
"data-part": "viewport",
|
|
1950
|
+
ref: virtualScroll.viewportRef,
|
|
1951
|
+
style: { height: viewportHeightPx, overflow: "auto", position: "relative" },
|
|
1952
|
+
onScroll: onViewportScroll,
|
|
1953
|
+
children: /* @__PURE__ */ jsx("div", { style: { height: `${virtualScroll.totalHeight}px`, position: "relative" }, children: /* @__PURE__ */ jsx(
|
|
1954
|
+
"div",
|
|
1955
|
+
{
|
|
1956
|
+
className: "body-grid ui-grid-canvas",
|
|
1957
|
+
"data-part": "body",
|
|
1958
|
+
role: "rowgroup",
|
|
1959
|
+
style: {
|
|
1960
|
+
gridTemplateColumns,
|
|
1961
|
+
position: "absolute",
|
|
1962
|
+
top: 0,
|
|
1963
|
+
left: 0,
|
|
1964
|
+
right: 0,
|
|
1965
|
+
transform: `translateY(${virtualScroll.offsetY}px)`
|
|
1966
|
+
},
|
|
1967
|
+
children: itemsToRender.map(renderDisplayItem)
|
|
1968
|
+
}
|
|
1969
|
+
) })
|
|
1970
|
+
}
|
|
1971
|
+
) : /* @__PURE__ */ jsx(
|
|
1972
|
+
"div",
|
|
1973
|
+
{
|
|
1974
|
+
className: "body-grid ui-grid-canvas",
|
|
1975
|
+
"data-part": "body",
|
|
1976
|
+
role: "rowgroup",
|
|
1977
|
+
style: { gridTemplateColumns },
|
|
1978
|
+
children: displayItems.map(renderDisplayItem)
|
|
1979
|
+
}
|
|
1980
|
+
) : /* @__PURE__ */ jsxs("div", { className: "empty-state ui-grid-no-row-overlay", "data-part": "empty-state", children: [
|
|
1981
|
+
/* @__PURE__ */ jsx("strong", { children: options.emptyMessage ?? labels.emptyHeading }),
|
|
1982
|
+
/* @__PURE__ */ jsx("p", { children: labels.emptyDescription })
|
|
1983
|
+
] }),
|
|
1984
|
+
paginationFeature && state.showPaginationControls() && /* @__PURE__ */ jsxs("footer", { className: "pagination-bar ui-grid-pagination", "data-part": "pagination", role: "navigation", "aria-label": labels.paginationPage, children: [
|
|
1985
|
+
/* @__PURE__ */ jsx("p", { children: state.paginationSummary() }),
|
|
1986
|
+
/* @__PURE__ */ jsxs("div", { className: "pagination-controls", children: [
|
|
1987
|
+
/* @__PURE__ */ jsxs(
|
|
1988
|
+
"button",
|
|
1989
|
+
{
|
|
1990
|
+
type: "button",
|
|
1991
|
+
className: "action action-secondary pagination-button",
|
|
1992
|
+
"aria-label": labels.paginationPrevious,
|
|
1993
|
+
disabled: paginationCurrentPage <= 1,
|
|
1994
|
+
onClick: () => state.previousPage(),
|
|
1995
|
+
children: [
|
|
1996
|
+
/* @__PURE__ */ jsx("svg", { className: "pagination-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }) }),
|
|
1997
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: labels.paginationPrevious })
|
|
1998
|
+
]
|
|
1999
|
+
}
|
|
2000
|
+
),
|
|
2001
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2002
|
+
labels.paginationPage,
|
|
2003
|
+
" ",
|
|
2004
|
+
paginationCurrentPage,
|
|
2005
|
+
" ",
|
|
2006
|
+
labels.paginationOf,
|
|
2007
|
+
" ",
|
|
2008
|
+
paginationTotalPages
|
|
2009
|
+
] }),
|
|
2010
|
+
/* @__PURE__ */ jsxs(
|
|
2011
|
+
"button",
|
|
2012
|
+
{
|
|
2013
|
+
type: "button",
|
|
2014
|
+
className: "action action-secondary pagination-button",
|
|
2015
|
+
"aria-label": labels.paginationNext,
|
|
2016
|
+
disabled: paginationCurrentPage >= paginationTotalPages,
|
|
2017
|
+
onClick: () => state.nextPage(),
|
|
2018
|
+
children: [
|
|
2019
|
+
/* @__PURE__ */ jsx("svg", { className: "pagination-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ jsx("path", { d: "M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z" }) }),
|
|
2020
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: labels.paginationNext })
|
|
2021
|
+
]
|
|
2022
|
+
}
|
|
2023
|
+
),
|
|
2024
|
+
state.pageSizeOptions().length > 0 && /* @__PURE__ */ jsxs("label", { className: "pagination-size", children: [
|
|
2025
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: labels.paginationRows }),
|
|
2026
|
+
/* @__PURE__ */ jsx(
|
|
2027
|
+
"select",
|
|
2028
|
+
{
|
|
2029
|
+
"aria-label": labels.paginationRows,
|
|
2030
|
+
value: paginationSelectedPageSize,
|
|
2031
|
+
onChange: (e) => state.onPageSizeChange(e.target.value),
|
|
2032
|
+
children: state.pageSizeOptions().map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
|
|
2033
|
+
}
|
|
2034
|
+
)
|
|
2035
|
+
] })
|
|
2036
|
+
] })
|
|
2037
|
+
] })
|
|
2038
|
+
] })
|
|
2039
|
+
] })
|
|
2040
|
+
] }) });
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// src/index.ts
|
|
2044
|
+
import { DEFAULT_GRID_LABELS } from "@ornery/ui-grid";
|
|
2045
|
+
export {
|
|
2046
|
+
DEFAULT_GRID_LABELS,
|
|
2047
|
+
UiGrid,
|
|
2048
|
+
useGridState,
|
|
2049
|
+
useVirtualScroll
|
|
2050
|
+
};
|