@ornery/ui-grid-react 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +1166 -607
- package/dist/index.mjs +1101 -549
- package/package.json +1 -1
- package/src/UiGrid.tsx +174 -47
- package/src/gridStateMath.test.ts +49 -0
- package/src/gridStateMath.ts +32 -0
- package/src/index.ts +2 -0
- package/src/rustWasmGridEngine.test.ts +56 -0
- package/src/rustWasmGridEngine.ts +21 -0
- package/src/useGridState.ts +637 -328
- package/src/useVirtualScroll.ts +11 -10
- package/src/virtualScrollMath.test.ts +44 -0
- package/src/virtualScrollMath.ts +36 -0
package/src/useGridState.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
buildGridTemplateColumns,
|
|
4
|
+
computeViewportHeightPx,
|
|
5
|
+
computeViewportRows,
|
|
6
|
+
formatPaginationSummary,
|
|
7
|
+
orderVisibleColumns,
|
|
8
|
+
resolveBenchmarkIterations,
|
|
9
|
+
} from './gridStateMath';
|
|
2
10
|
import {
|
|
3
11
|
createGridApi,
|
|
4
12
|
UiGridApi,
|
|
@@ -16,7 +24,7 @@ import {
|
|
|
16
24
|
getCellValue,
|
|
17
25
|
setPathValue,
|
|
18
26
|
SORT_DIRECTIONS,
|
|
19
|
-
|
|
27
|
+
defaultGridEngine,
|
|
20
28
|
resolveGridLabels,
|
|
21
29
|
gridColumnWidth,
|
|
22
30
|
headerLabel as coreHeaderLabel,
|
|
@@ -79,6 +87,7 @@ import {
|
|
|
79
87
|
FEATURE_CSV_EXPORT,
|
|
80
88
|
FEATURE_AUTO_RESIZE,
|
|
81
89
|
FEATURE_SAVE_STATE,
|
|
90
|
+
FEATURE_PINNING,
|
|
82
91
|
} from '@ornery/ui-grid';
|
|
83
92
|
import type {
|
|
84
93
|
DisplayItem,
|
|
@@ -117,7 +126,16 @@ import {
|
|
|
117
126
|
saveGridInfiniteScrollPercentageCommand,
|
|
118
127
|
setGridInfiniteScrollDirectionsCommand,
|
|
119
128
|
restoreGridStateCommand,
|
|
129
|
+
pinGridColumnCommand,
|
|
120
130
|
} from '../../ui-grid/src/lib/grid/ui-grid.commands';
|
|
131
|
+
import {
|
|
132
|
+
buildInitialPinnedState,
|
|
133
|
+
computePinnedOffset,
|
|
134
|
+
isColumnPinnable,
|
|
135
|
+
isPinningEnabled,
|
|
136
|
+
PinDirection,
|
|
137
|
+
PinnedColumnState,
|
|
138
|
+
} from '../../ui-grid/src/lib/grid/grid.core';
|
|
121
139
|
import {
|
|
122
140
|
raiseGridRenderingComplete,
|
|
123
141
|
raiseGridRowsRendered,
|
|
@@ -128,10 +146,54 @@ import {
|
|
|
128
146
|
raiseGridScrollEnd,
|
|
129
147
|
raiseGridBenchmarkComplete,
|
|
130
148
|
} from '../../ui-grid/src/lib/grid/ui-grid.events';
|
|
131
|
-
import {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
import { downloadGridCsvFile, observeGridHostSize } from '../../ui-grid/src/lib/grid/ui-grid.host';
|
|
150
|
+
|
|
151
|
+
function escapeCssSelectorValue(value: string): string {
|
|
152
|
+
const nativeEscape = globalThis.CSS?.escape;
|
|
153
|
+
if (typeof nativeEscape === 'function') {
|
|
154
|
+
return nativeEscape(value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let output = '';
|
|
158
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
159
|
+
const codePoint = value.charCodeAt(index);
|
|
160
|
+
const character = value.charAt(index);
|
|
161
|
+
|
|
162
|
+
if (codePoint === 0x0000) {
|
|
163
|
+
output += '\uFFFD';
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const isControlCharacter = (codePoint >= 0x0001 && codePoint <= 0x001f) || codePoint === 0x007f;
|
|
168
|
+
const startsWithDigit = index === 0 && codePoint >= 0x0030 && codePoint <= 0x0039;
|
|
169
|
+
const secondCharDigitAfterHyphen =
|
|
170
|
+
index === 1 &&
|
|
171
|
+
codePoint >= 0x0030 && codePoint <= 0x0039 &&
|
|
172
|
+
value.charCodeAt(0) === 0x002d;
|
|
173
|
+
|
|
174
|
+
if (isControlCharacter || startsWithDigit || secondCharDigitAfterHyphen) {
|
|
175
|
+
output += `\\${codePoint.toString(16)} `;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (index === 0 && value.length === 1 && codePoint === 0x002d) {
|
|
180
|
+
output += `\\${character}`;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const isSafeCharacter =
|
|
185
|
+
codePoint >= 0x0080 ||
|
|
186
|
+
codePoint === 0x002d ||
|
|
187
|
+
codePoint === 0x005f ||
|
|
188
|
+
(codePoint >= 0x0030 && codePoint <= 0x0039) ||
|
|
189
|
+
(codePoint >= 0x0041 && codePoint <= 0x005a) ||
|
|
190
|
+
(codePoint >= 0x0061 && codePoint <= 0x007a);
|
|
191
|
+
|
|
192
|
+
output += isSafeCharacter ? character : `\\${character}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return output;
|
|
196
|
+
}
|
|
135
197
|
|
|
136
198
|
export interface UseGridStateResult {
|
|
137
199
|
pipeline: PipelineResult;
|
|
@@ -201,9 +263,21 @@ export interface UseGridStateResult {
|
|
|
201
263
|
showPaginationControls: () => boolean;
|
|
202
264
|
paginationSummary: () => string;
|
|
203
265
|
pageSizeOptions: () => number[];
|
|
204
|
-
isCellEditable: (
|
|
266
|
+
isCellEditable: (
|
|
267
|
+
row: GridRow,
|
|
268
|
+
column: GridColumnDef,
|
|
269
|
+
triggerEvent?: Event | KeyboardEvent | null,
|
|
270
|
+
) => boolean;
|
|
205
271
|
shouldEditOnFocus: (column: GridColumnDef) => boolean;
|
|
206
272
|
|
|
273
|
+
// Pinning
|
|
274
|
+
isPinned: (column: GridColumnDef) => boolean;
|
|
275
|
+
pinnedOffset: (column: GridColumnDef) => { side: 'left' | 'right'; offset: string } | null;
|
|
276
|
+
isPinningEnabled: () => boolean;
|
|
277
|
+
isColumnPinnable: (column: GridColumnDef) => boolean;
|
|
278
|
+
togglePin: (column: GridColumnDef) => void;
|
|
279
|
+
pinningFeature: boolean;
|
|
280
|
+
|
|
207
281
|
// Feature flags
|
|
208
282
|
sortingFeature: boolean;
|
|
209
283
|
filteringFeature: boolean;
|
|
@@ -226,7 +300,11 @@ export interface UseGridStateResult {
|
|
|
226
300
|
clearAllFilters: () => void;
|
|
227
301
|
toggleGrouping: (column: GridColumnDef, event?: React.MouseEvent) => void;
|
|
228
302
|
toggleGroup: (item: GroupItem) => void;
|
|
229
|
-
focusCell: (
|
|
303
|
+
focusCell: (
|
|
304
|
+
row: GridRow,
|
|
305
|
+
column: GridColumnDef,
|
|
306
|
+
triggerEvent?: Event | KeyboardEvent | null,
|
|
307
|
+
) => void;
|
|
230
308
|
handleCellKeyDown: (row: GridRow, column: GridColumnDef, event: React.KeyboardEvent) => void;
|
|
231
309
|
handleCellDoubleClick: (row: GridRow, column: GridColumnDef, event: React.MouseEvent) => void;
|
|
232
310
|
updateEditingValue: (value: string) => void;
|
|
@@ -243,13 +321,19 @@ export interface UseGridStateResult {
|
|
|
243
321
|
onViewportScroll: (startIndex: number) => void;
|
|
244
322
|
}
|
|
245
323
|
|
|
246
|
-
export function useGridState(
|
|
324
|
+
export function useGridState(
|
|
325
|
+
options: GridOptions,
|
|
326
|
+
onRegisterApi?: (api: UiGridApi) => void,
|
|
327
|
+
): UseGridStateResult {
|
|
247
328
|
const [activeFilters, setActiveFilters] = useState<Record<string, string>>({});
|
|
248
329
|
const [groupByColumns, setGroupByColumns] = useState<string[]>([]);
|
|
249
330
|
const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>({});
|
|
250
331
|
const [columnOrder, setColumnOrder] = useState<string[]>([]);
|
|
251
332
|
const [hiddenRowReasons, setHiddenRowReasons] = useState<Record<string, string[]>>({});
|
|
252
|
-
const [sortState, setSortState] = useState<SortState>({
|
|
333
|
+
const [sortState, setSortState] = useState<SortState>({
|
|
334
|
+
columnName: null,
|
|
335
|
+
direction: SORT_DIRECTIONS.none,
|
|
336
|
+
});
|
|
253
337
|
const [focusedCell, setFocusedCell] = useState<GridCellPosition | null>(null);
|
|
254
338
|
const [editingCell, setEditingCell] = useState<GridCellPosition | null>(null);
|
|
255
339
|
const [editingValue, setEditingValue] = useState('');
|
|
@@ -265,6 +349,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
265
349
|
previousVisibleRows: 0,
|
|
266
350
|
});
|
|
267
351
|
const [autoViewportHeight, setAutoViewportHeight] = useState<number | null>(null);
|
|
352
|
+
const [pinnedColumns, setPinnedColumns] = useState<PinnedColumnState>({});
|
|
268
353
|
|
|
269
354
|
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
|
270
355
|
const initializedGridIdRef = useRef<string | null>(null);
|
|
@@ -299,6 +384,8 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
299
384
|
expandedRowsRef.current = expandedRows;
|
|
300
385
|
const expandedTreeRowsRef = useRef(expandedTreeRows);
|
|
301
386
|
expandedTreeRowsRef.current = expandedTreeRows;
|
|
387
|
+
const pinnedColumnsRef = useRef(pinnedColumns);
|
|
388
|
+
pinnedColumnsRef.current = pinnedColumns;
|
|
302
389
|
const currentPageRef = useRef(currentPage);
|
|
303
390
|
currentPageRef.current = currentPage;
|
|
304
391
|
const pageSizeRef = useRef(pageSize);
|
|
@@ -311,17 +398,14 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
311
398
|
const rowSize = options.rowHeight ?? 44;
|
|
312
399
|
|
|
313
400
|
const visibleColumns = useMemo(() => {
|
|
314
|
-
|
|
315
|
-
return [...options.columnDefs]
|
|
316
|
-
.filter((column) => column.visible !== false)
|
|
317
|
-
.sort((left, right) => order.indexOf(left.name) - order.indexOf(right.name));
|
|
401
|
+
return orderVisibleColumns(options.columnDefs, columnOrder);
|
|
318
402
|
}, [options.columnDefs, columnOrder]);
|
|
319
403
|
|
|
320
404
|
const visibleColumnsRef = useRef(visibleColumns);
|
|
321
405
|
visibleColumnsRef.current = visibleColumns;
|
|
322
406
|
|
|
323
407
|
const pipeline = useMemo<PipelineResult>(() => {
|
|
324
|
-
return
|
|
408
|
+
return defaultGridEngine.buildPipeline({
|
|
325
409
|
options,
|
|
326
410
|
columns: visibleColumns,
|
|
327
411
|
activeFilters,
|
|
@@ -335,7 +419,20 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
335
419
|
pageSize,
|
|
336
420
|
rowSize,
|
|
337
421
|
});
|
|
338
|
-
}, [
|
|
422
|
+
}, [
|
|
423
|
+
options,
|
|
424
|
+
visibleColumns,
|
|
425
|
+
activeFilters,
|
|
426
|
+
sortState,
|
|
427
|
+
groupByColumns,
|
|
428
|
+
collapsedGroups,
|
|
429
|
+
hiddenRowReasons,
|
|
430
|
+
expandedRows,
|
|
431
|
+
expandedTreeRows,
|
|
432
|
+
currentPage,
|
|
433
|
+
pageSize,
|
|
434
|
+
rowSize,
|
|
435
|
+
]);
|
|
339
436
|
|
|
340
437
|
const pipelineRef = useRef(pipeline);
|
|
341
438
|
pipelineRef.current = pipeline;
|
|
@@ -343,10 +440,26 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
343
440
|
const labels = useMemo(() => resolveGridLabels(options.labels), [options.labels]);
|
|
344
441
|
|
|
345
442
|
const gridTemplateColumns = useMemo(
|
|
346
|
-
() => visibleColumns
|
|
347
|
-
[visibleColumns]
|
|
443
|
+
() => buildGridTemplateColumns(visibleColumns),
|
|
444
|
+
[visibleColumns],
|
|
348
445
|
);
|
|
349
446
|
|
|
447
|
+
const isPinningEnabledFn = useCallback((): boolean => {
|
|
448
|
+
return isPinningEnabled(optionsRef.current);
|
|
449
|
+
}, []);
|
|
450
|
+
|
|
451
|
+
const isColumnPinnableFn = useCallback((column: GridColumnDef): boolean => {
|
|
452
|
+
return isColumnPinnable(optionsRef.current, column);
|
|
453
|
+
}, []);
|
|
454
|
+
|
|
455
|
+
const isPinnedFn = useCallback((column: GridColumnDef): boolean => {
|
|
456
|
+
return pinnedColumnsRef.current[column.name] !== undefined;
|
|
457
|
+
}, []);
|
|
458
|
+
|
|
459
|
+
const pinnedOffsetFn = useCallback((column: GridColumnDef) => {
|
|
460
|
+
return computePinnedOffset(visibleColumnsRef.current, pinnedColumnsRef.current, column);
|
|
461
|
+
}, []);
|
|
462
|
+
|
|
350
463
|
// --- Helper functions (all pure, no state closures needed beyond refs) ---
|
|
351
464
|
|
|
352
465
|
const resolveRowId = useCallback((row: GridRow | GridRecord | string): string => {
|
|
@@ -358,13 +471,16 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
358
471
|
{ ...optionsRef.current, data },
|
|
359
472
|
optionsRef.current.rowHeight ?? 44,
|
|
360
473
|
hiddenRowReasonsRef.current,
|
|
361
|
-
expandedRowsRef.current
|
|
474
|
+
expandedRowsRef.current,
|
|
362
475
|
);
|
|
363
476
|
}, []);
|
|
364
477
|
|
|
365
|
-
const findRowById = useCallback(
|
|
366
|
-
|
|
367
|
-
|
|
478
|
+
const findRowById = useCallback(
|
|
479
|
+
(rowId: string): GridRow | null => {
|
|
480
|
+
return coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId);
|
|
481
|
+
},
|
|
482
|
+
[buildRowsFromData],
|
|
483
|
+
);
|
|
368
484
|
|
|
369
485
|
const canExpandRowsFn = useCallback((): boolean => {
|
|
370
486
|
return FEATURE_EXPANDABLE && canGridExpandRows(optionsRef.current);
|
|
@@ -376,7 +492,12 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
376
492
|
|
|
377
493
|
const getCurrentPageValueFn = useCallback((totalItems?: number): number => {
|
|
378
494
|
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
379
|
-
return coreGetCurrentPageValue(
|
|
495
|
+
return coreGetCurrentPageValue(
|
|
496
|
+
optionsRef.current,
|
|
497
|
+
currentPageRef.current,
|
|
498
|
+
ti,
|
|
499
|
+
pageSizeRef.current,
|
|
500
|
+
);
|
|
380
501
|
}, []);
|
|
381
502
|
|
|
382
503
|
const getTotalPagesValueFn = useCallback((totalItems?: number): number => {
|
|
@@ -386,30 +507,44 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
386
507
|
|
|
387
508
|
const getFirstRowIndexValueFn = useCallback((totalItems?: number): number => {
|
|
388
509
|
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
389
|
-
return coreGetFirstRowIndexValue(
|
|
510
|
+
return coreGetFirstRowIndexValue(
|
|
511
|
+
optionsRef.current,
|
|
512
|
+
currentPageRef.current,
|
|
513
|
+
ti,
|
|
514
|
+
pageSizeRef.current,
|
|
515
|
+
);
|
|
390
516
|
}, []);
|
|
391
517
|
|
|
392
518
|
const getLastRowIndexValueFn = useCallback((totalItems?: number): number => {
|
|
393
519
|
const ti = totalItems ?? pipelineRef.current.totalItems;
|
|
394
|
-
return coreGetLastRowIndexValue(
|
|
520
|
+
return coreGetLastRowIndexValue(
|
|
521
|
+
optionsRef.current,
|
|
522
|
+
currentPageRef.current,
|
|
523
|
+
ti,
|
|
524
|
+
pageSizeRef.current,
|
|
525
|
+
);
|
|
395
526
|
}, []);
|
|
396
527
|
|
|
397
|
-
const isCellEditable = useCallback(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
528
|
+
const isCellEditable = useCallback(
|
|
529
|
+
(row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null): boolean => {
|
|
530
|
+
if (!FEATURE_CELL_EDIT) return false;
|
|
531
|
+
const editable = column.enableCellEdit ?? optionsRef.current.enableCellEdit ?? false;
|
|
532
|
+
if (!editable) return false;
|
|
533
|
+
|
|
534
|
+
const condition =
|
|
535
|
+
column.cellEditableCondition ?? optionsRef.current.cellEditableCondition ?? true;
|
|
536
|
+
if (typeof condition === 'boolean') return condition;
|
|
537
|
+
|
|
538
|
+
const context: GridCellEditableContext = {
|
|
539
|
+
row: row.entity,
|
|
540
|
+
column,
|
|
541
|
+
rowIndex: row.index,
|
|
542
|
+
triggerEvent,
|
|
543
|
+
};
|
|
544
|
+
return condition(context);
|
|
545
|
+
},
|
|
546
|
+
[],
|
|
547
|
+
);
|
|
413
548
|
|
|
414
549
|
const shouldEditOnFocusFn = useCallback((column: GridColumnDef): boolean => {
|
|
415
550
|
return column.enableCellEditOnFocus ?? optionsRef.current.enableCellEditOnFocus ?? false;
|
|
@@ -419,7 +554,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
419
554
|
|
|
420
555
|
const focusRenderedCell = useCallback((position: GridCellPosition): void => {
|
|
421
556
|
const focusToken = ++renderedCellFocusTokenRef.current;
|
|
422
|
-
const selector = `.body-cell[data-row-id="${position.rowId}"][data-col-name="${position.columnName}"]`;
|
|
557
|
+
const selector = `.body-cell[data-row-id="${escapeCssSelectorValue(position.rowId)}"][data-col-name="${escapeCssSelectorValue(position.columnName)}"]`;
|
|
423
558
|
|
|
424
559
|
const doFocus = (retry = true): void => {
|
|
425
560
|
if (focusToken !== renderedCellFocusTokenRef.current) return;
|
|
@@ -444,12 +579,13 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
444
579
|
const ec = editingCellRef.current;
|
|
445
580
|
if (!ec) return;
|
|
446
581
|
|
|
447
|
-
const selector = `.cell-editor[data-row-id="${ec.rowId}"][data-col-name="${ec.columnName}"]`;
|
|
582
|
+
const selector = `.cell-editor[data-row-id="${escapeCssSelectorValue(ec.rowId)}"][data-col-name="${escapeCssSelectorValue(ec.columnName)}"]`;
|
|
448
583
|
|
|
449
584
|
const doFocus = (retry = true): void => {
|
|
450
585
|
if (focusToken !== editorFocusTokenRef.current) return;
|
|
451
586
|
const currentEc = editingCellRef.current;
|
|
452
|
-
if (!currentEc || currentEc.rowId !== ec.rowId || currentEc.columnName !== ec.columnName)
|
|
587
|
+
if (!currentEc || currentEc.rowId !== ec.rowId || currentEc.columnName !== ec.columnName)
|
|
588
|
+
return;
|
|
453
589
|
|
|
454
590
|
const container = gridContainerRef.current;
|
|
455
591
|
if (!container) return;
|
|
@@ -500,10 +636,10 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
500
636
|
moveColumn: (fromIndex, toIndex) => {
|
|
501
637
|
moveGridColumnCommand(
|
|
502
638
|
gridApiRef.current!,
|
|
503
|
-
FEATURE_COLUMN_MOVING &&
|
|
639
|
+
FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
|
|
504
640
|
(updater) => setColumnOrder((current) => updater(current)),
|
|
505
641
|
fromIndex,
|
|
506
|
-
toIndex
|
|
642
|
+
toIndex,
|
|
507
643
|
);
|
|
508
644
|
},
|
|
509
645
|
toggleGrouping: (columnName) => {
|
|
@@ -517,7 +653,11 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
517
653
|
gridApiRef.current!.core.raise.groupingChanged(next);
|
|
518
654
|
},
|
|
519
655
|
clearGrouping: () => {
|
|
520
|
-
clearGridGroupingCommand(
|
|
656
|
+
clearGridGroupingCommand(
|
|
657
|
+
gridApiRef.current!,
|
|
658
|
+
(grouping) => setGroupByColumns(grouping),
|
|
659
|
+
false,
|
|
660
|
+
);
|
|
521
661
|
},
|
|
522
662
|
benchmark: (iterations) => {
|
|
523
663
|
return runBenchmarkFn(iterations);
|
|
@@ -543,7 +683,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
543
683
|
expandAllGridTreeRowsCommand(
|
|
544
684
|
(data) => buildRowsFromData(data),
|
|
545
685
|
optionsRef.current.data,
|
|
546
|
-
(e) => setExpandedTreeRows(e)
|
|
686
|
+
(e) => setExpandedTreeRows(e),
|
|
547
687
|
);
|
|
548
688
|
},
|
|
549
689
|
treeCollapseAllRows: () => {
|
|
@@ -563,35 +703,35 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
563
703
|
infiniteScrollStateRef.current,
|
|
564
704
|
(s) => setInfiniteScrollState(s),
|
|
565
705
|
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
566
|
-
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
706
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown,
|
|
567
707
|
);
|
|
568
708
|
},
|
|
569
709
|
infiniteScrollReset: (scrollUp, scrollDown) => {
|
|
570
710
|
resetGridInfiniteScrollCommand(
|
|
571
711
|
(s) => setInfiniteScrollState(s),
|
|
572
712
|
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
573
|
-
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
713
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown,
|
|
574
714
|
);
|
|
575
715
|
},
|
|
576
716
|
infiniteScrollSaveScrollPercentage: () => {
|
|
577
717
|
saveGridInfiniteScrollPercentageCommand(
|
|
578
718
|
infiniteScrollStateRef.current,
|
|
579
719
|
pipelineRef.current.visibleRows.length,
|
|
580
|
-
(s) => setInfiniteScrollState(s)
|
|
720
|
+
(s) => setInfiniteScrollState(s),
|
|
581
721
|
);
|
|
582
722
|
},
|
|
583
723
|
infiniteScrollDataRemovedTop: (scrollUp, scrollDown) => {
|
|
584
724
|
resetGridInfiniteScrollCommand(
|
|
585
725
|
(s) => setInfiniteScrollState(s),
|
|
586
726
|
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
587
|
-
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
727
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown,
|
|
588
728
|
);
|
|
589
729
|
},
|
|
590
730
|
infiniteScrollDataRemovedBottom: (scrollUp, scrollDown) => {
|
|
591
731
|
resetGridInfiniteScrollCommand(
|
|
592
732
|
(s) => setInfiniteScrollState(s),
|
|
593
733
|
scrollUp ?? infiniteScrollStateRef.current.scrollUp,
|
|
594
|
-
scrollDown ?? infiniteScrollStateRef.current.scrollDown
|
|
734
|
+
scrollDown ?? infiniteScrollStateRef.current.scrollDown,
|
|
595
735
|
);
|
|
596
736
|
},
|
|
597
737
|
infiniteScrollSetDirections: (scrollUp, scrollDown) => {
|
|
@@ -599,7 +739,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
599
739
|
infiniteScrollStateRef.current,
|
|
600
740
|
(s) => setInfiniteScrollState(s),
|
|
601
741
|
scrollUp,
|
|
602
|
-
scrollDown
|
|
742
|
+
scrollDown,
|
|
603
743
|
);
|
|
604
744
|
},
|
|
605
745
|
saveState: () => {
|
|
@@ -613,6 +753,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
613
753
|
totalItems: pipelineRef.current.totalItems,
|
|
614
754
|
expandedRows: expandedRowsRef.current,
|
|
615
755
|
expandedTreeRows: expandedTreeRowsRef.current,
|
|
756
|
+
pinnedColumns: pinnedColumnsRef.current,
|
|
616
757
|
});
|
|
617
758
|
},
|
|
618
759
|
restoreState: (state) => {
|
|
@@ -625,6 +766,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
625
766
|
setPageSize: (ps) => setPageSize(ps),
|
|
626
767
|
setExpandedRows: (e) => setExpandedRows(e),
|
|
627
768
|
setExpandedTreeRows: (e) => setExpandedTreeRows(e),
|
|
769
|
+
setPinnedColumns: (p) => setPinnedColumns(p),
|
|
628
770
|
getEffectivePageSize: () => effectivePageSizeFn(pipelineRef.current.totalItems),
|
|
629
771
|
});
|
|
630
772
|
},
|
|
@@ -638,6 +780,16 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
638
780
|
endCellEdit: () => commitCellEditFn(),
|
|
639
781
|
cancelCellEdit: () => cancelCellEditFn(),
|
|
640
782
|
getEditingCell: () => editingCellRef.current,
|
|
783
|
+
pinColumn: (columnName: string, direction: PinDirection) => {
|
|
784
|
+
pinGridColumnCommand(
|
|
785
|
+
gridApiRef.current!,
|
|
786
|
+
isPinningEnabledFn(),
|
|
787
|
+
(v) => setPinnedColumns(v),
|
|
788
|
+
() => pinnedColumnsRef.current,
|
|
789
|
+
columnName,
|
|
790
|
+
direction,
|
|
791
|
+
);
|
|
792
|
+
},
|
|
641
793
|
};
|
|
642
794
|
|
|
643
795
|
gridApiRef.current = createGridApi(bindings);
|
|
@@ -647,48 +799,71 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
647
799
|
|
|
648
800
|
// --- Memoized action functions ---
|
|
649
801
|
|
|
650
|
-
const seekPageFn = useCallback(
|
|
651
|
-
|
|
802
|
+
const seekPageFn = useCallback(
|
|
803
|
+
(page: number): void => {
|
|
804
|
+
seekGridPaginationCommand(
|
|
805
|
+
gridApiRef.current!,
|
|
806
|
+
(nextPage) => setCurrentPage(nextPage),
|
|
807
|
+
() => getTotalPagesValueFn(),
|
|
808
|
+
() => effectivePageSizeFn(pipelineRef.current.totalItems),
|
|
809
|
+
page,
|
|
810
|
+
);
|
|
811
|
+
},
|
|
812
|
+
[getTotalPagesValueFn, effectivePageSizeFn],
|
|
813
|
+
);
|
|
814
|
+
|
|
815
|
+
const togglePinFn = useCallback((column: GridColumnDef): void => {
|
|
816
|
+
const current = pinnedColumnsRef.current[column.name];
|
|
817
|
+
const next: PinDirection = current === 'left' ? 'right' : current === 'right' ? 'none' : 'left';
|
|
818
|
+
pinGridColumnCommand(
|
|
652
819
|
gridApiRef.current!,
|
|
653
|
-
(
|
|
654
|
-
() =>
|
|
655
|
-
() =>
|
|
656
|
-
|
|
820
|
+
isPinningEnabledFn(),
|
|
821
|
+
(v) => setPinnedColumns(v),
|
|
822
|
+
() => pinnedColumnsRef.current,
|
|
823
|
+
column.name,
|
|
824
|
+
next,
|
|
657
825
|
);
|
|
658
|
-
}, [
|
|
826
|
+
}, []);
|
|
659
827
|
|
|
660
828
|
const setPaginationPageSizeFn = useCallback((ps: number): void => {
|
|
661
829
|
setGridPaginationPageSizeCommand(
|
|
662
830
|
gridApiRef.current!,
|
|
663
831
|
(nextPageSize) => setPageSize(nextPageSize),
|
|
664
832
|
(nextPage) => setCurrentPage(nextPage),
|
|
665
|
-
ps
|
|
833
|
+
ps,
|
|
666
834
|
);
|
|
667
835
|
}, []);
|
|
668
836
|
|
|
669
|
-
const toggleRowExpansionByRefFn = useCallback(
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
837
|
+
const toggleRowExpansionByRefFn = useCallback(
|
|
838
|
+
(row: GridRow | GridRecord | string): void => {
|
|
839
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
840
|
+
toggleGridRowExpansionCommand(
|
|
841
|
+
gridApiRef.current!,
|
|
842
|
+
FEATURE_EXPANDABLE && canGridExpandRows(optionsRef.current),
|
|
843
|
+
expandedRowsRef.current,
|
|
844
|
+
rowId,
|
|
845
|
+
(e) => setExpandedRows(e),
|
|
846
|
+
(resolvedRowId) =>
|
|
847
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId),
|
|
848
|
+
);
|
|
849
|
+
},
|
|
850
|
+
[buildRowsFromData],
|
|
851
|
+
);
|
|
680
852
|
|
|
681
853
|
const expandAllRowsFn = useCallback((): void => {
|
|
682
854
|
if (!canGridExpandRows(optionsRef.current)) return;
|
|
683
855
|
expandAllGridRowsCommand(
|
|
684
856
|
(data) => buildRowsFromData(data),
|
|
685
857
|
optionsRef.current.data,
|
|
686
|
-
(e) => setExpandedRows(e)
|
|
858
|
+
(e) => setExpandedRows(e),
|
|
687
859
|
);
|
|
688
860
|
}, [buildRowsFromData]);
|
|
689
861
|
|
|
690
862
|
const toggleAllRowsFn = useCallback((): void => {
|
|
691
|
-
const allExpanded = areAllGridRowsExpanded(
|
|
863
|
+
const allExpanded = areAllGridRowsExpanded(
|
|
864
|
+
buildRowsFromData(optionsRef.current.data),
|
|
865
|
+
expandedRowsRef.current,
|
|
866
|
+
);
|
|
692
867
|
if (allExpanded) {
|
|
693
868
|
collapseAllGridRowsCommand((e) => setExpandedRows(e));
|
|
694
869
|
} else {
|
|
@@ -696,89 +871,115 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
696
871
|
}
|
|
697
872
|
}, [buildRowsFromData, expandAllRowsFn]);
|
|
698
873
|
|
|
699
|
-
const toggleTreeRowByRefFn = useCallback(
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
gridApiRef.current!,
|
|
714
|
-
expandedTreeRowsRef.current,
|
|
715
|
-
rowId,
|
|
716
|
-
true,
|
|
717
|
-
(e) => setExpandedTreeRows(e),
|
|
718
|
-
(resolvedRowId) => coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId)
|
|
719
|
-
);
|
|
720
|
-
}, [buildRowsFromData]);
|
|
874
|
+
const toggleTreeRowByRefFn = useCallback(
|
|
875
|
+
(row: GridRow | GridRecord | string): void => {
|
|
876
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
877
|
+
toggleGridTreeRowCommand(
|
|
878
|
+
gridApiRef.current!,
|
|
879
|
+
expandedTreeRowsRef.current,
|
|
880
|
+
rowId,
|
|
881
|
+
(e) => setExpandedTreeRows(e),
|
|
882
|
+
(resolvedRowId) =>
|
|
883
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId),
|
|
884
|
+
);
|
|
885
|
+
},
|
|
886
|
+
[buildRowsFromData],
|
|
887
|
+
);
|
|
721
888
|
|
|
722
|
-
const
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
889
|
+
const expandTreeRowByRefFn = useCallback(
|
|
890
|
+
(row: GridRow | GridRecord | string): void => {
|
|
891
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
892
|
+
setGridTreeRowExpandedCommand(
|
|
893
|
+
gridApiRef.current!,
|
|
894
|
+
expandedTreeRowsRef.current,
|
|
895
|
+
rowId,
|
|
896
|
+
true,
|
|
897
|
+
(e) => setExpandedTreeRows(e),
|
|
898
|
+
(resolvedRowId) =>
|
|
899
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId),
|
|
900
|
+
);
|
|
901
|
+
},
|
|
902
|
+
[buildRowsFromData],
|
|
903
|
+
);
|
|
733
904
|
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
);
|
|
905
|
+
const collapseTreeRowByRefFn = useCallback(
|
|
906
|
+
(row: GridRow | GridRecord | string): void => {
|
|
907
|
+
const rowId = coreResolveGridRowId(optionsRef.current, row);
|
|
908
|
+
setGridTreeRowExpandedCommand(
|
|
909
|
+
gridApiRef.current!,
|
|
910
|
+
expandedTreeRowsRef.current,
|
|
911
|
+
rowId,
|
|
912
|
+
false,
|
|
913
|
+
(e) => setExpandedTreeRows(e),
|
|
914
|
+
(resolvedRowId) =>
|
|
915
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), resolvedRowId),
|
|
916
|
+
);
|
|
917
|
+
},
|
|
918
|
+
[buildRowsFromData],
|
|
919
|
+
);
|
|
750
920
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
921
|
+
const startCellEditFn = useCallback(
|
|
922
|
+
(
|
|
923
|
+
row: GridRow,
|
|
924
|
+
column: GridColumnDef,
|
|
925
|
+
triggerEvent?: Event | KeyboardEvent | null,
|
|
926
|
+
initialValue?: string,
|
|
927
|
+
): void => {
|
|
928
|
+
const currentValue = getCellValue(row.entity, column);
|
|
929
|
+
const focusToken = ++editorFocusTokenRef.current;
|
|
930
|
+
const ec = beginGridCellEditCommand(
|
|
931
|
+
gridApiRef.current!,
|
|
932
|
+
{
|
|
933
|
+
setFocusedCell: (fc) => setFocusedCell(fc),
|
|
934
|
+
setEditingCell: (ec2) => setEditingCell(ec2),
|
|
935
|
+
setEditingValue: (ev) => setEditingValue(ev),
|
|
936
|
+
},
|
|
937
|
+
row,
|
|
938
|
+
column,
|
|
939
|
+
currentValue,
|
|
940
|
+
triggerEvent,
|
|
941
|
+
initialValue,
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
if (ec) {
|
|
945
|
+
queueMicrotask(() => focusEditorInput(focusToken));
|
|
946
|
+
}
|
|
947
|
+
},
|
|
948
|
+
[focusEditorInput],
|
|
949
|
+
);
|
|
755
950
|
|
|
756
|
-
const commitCellEditFn = useCallback(
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
951
|
+
const commitCellEditFn = useCallback(
|
|
952
|
+
(direction?: GridMoveDirection, restoreFocus = true): void => {
|
|
953
|
+
const result = commitGridCellEditCommand(gridApiRef.current!, {
|
|
954
|
+
getEditingCell: () => editingCellRef.current,
|
|
955
|
+
getEditingValue: () => editingValueRef.current,
|
|
956
|
+
setEditingCell: (ec) => setEditingCell(ec),
|
|
957
|
+
setEditingValue: (ev) => setEditingValue(ev),
|
|
958
|
+
findRowById: (rowId) =>
|
|
959
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId),
|
|
960
|
+
findColumnByName: (columnName) =>
|
|
961
|
+
visibleColumnsRef.current.find((c) => c.name === columnName),
|
|
962
|
+
parseEditedValue: (column, value, oldValue) =>
|
|
963
|
+
parseGridEditedValue(column, value, oldValue),
|
|
964
|
+
setCellValue: (rowEntity, column, value) => {
|
|
965
|
+
const fieldPath = column.editModelField ?? column.field ?? column.name;
|
|
966
|
+
setPathValue(rowEntity, fieldPath, value);
|
|
967
|
+
},
|
|
968
|
+
});
|
|
770
969
|
|
|
771
|
-
|
|
970
|
+
if (!result.committed || !result.row || !result.column || !result.focusTarget) return;
|
|
772
971
|
|
|
773
|
-
|
|
972
|
+
editorFocusTokenRef.current += 1;
|
|
774
973
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
974
|
+
if (direction) {
|
|
975
|
+
const moved = moveFocusFn(result.row, result.column, direction);
|
|
976
|
+
if (!moved) focusRenderedCell(result.focusTarget);
|
|
977
|
+
} else if (restoreFocus) {
|
|
978
|
+
focusRenderedCell(result.focusTarget);
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
[buildRowsFromData, focusRenderedCell],
|
|
982
|
+
);
|
|
782
983
|
|
|
783
984
|
const cancelCellEditFn = useCallback((): void => {
|
|
784
985
|
const hadEditingCell = editingCellRef.current !== null;
|
|
@@ -786,8 +987,10 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
786
987
|
getEditingCell: () => editingCellRef.current,
|
|
787
988
|
setEditingCell: (ec) => setEditingCell(ec),
|
|
788
989
|
setEditingValue: (ev) => setEditingValue(ev),
|
|
789
|
-
findRowById: (rowId) =>
|
|
790
|
-
|
|
990
|
+
findRowById: (rowId) =>
|
|
991
|
+
coreFindGridRowById(buildRowsFromData(optionsRef.current.data), rowId),
|
|
992
|
+
findColumnByName: (columnName) =>
|
|
993
|
+
visibleColumnsRef.current.find((c) => c.name === columnName),
|
|
791
994
|
});
|
|
792
995
|
|
|
793
996
|
if (!hadEditingCell) return;
|
|
@@ -795,30 +998,44 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
795
998
|
if (result.focusTarget) focusRenderedCell(result.focusTarget);
|
|
796
999
|
}, [buildRowsFromData, focusRenderedCell]);
|
|
797
1000
|
|
|
798
|
-
const moveFocusFn = useCallback(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1001
|
+
const moveFocusFn = useCallback(
|
|
1002
|
+
(
|
|
1003
|
+
row: GridRow,
|
|
1004
|
+
column: GridColumnDef,
|
|
1005
|
+
direction: GridMoveDirection,
|
|
1006
|
+
triggerEvent?: Event | KeyboardEvent | null,
|
|
1007
|
+
): boolean => {
|
|
1008
|
+
const nextCell = findNextGridCell({
|
|
1009
|
+
rows: pipelineRef.current.visibleRows,
|
|
1010
|
+
columns: visibleColumnsRef.current,
|
|
1011
|
+
rowId: row.id,
|
|
1012
|
+
columnName: column.name,
|
|
1013
|
+
direction,
|
|
1014
|
+
});
|
|
1015
|
+
if (!nextCell) return false;
|
|
807
1016
|
|
|
808
|
-
|
|
809
|
-
|
|
1017
|
+
setFocusedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
|
|
1018
|
+
focusRenderedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
|
|
810
1019
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1020
|
+
if (
|
|
1021
|
+
shouldEditOnFocusFn(nextCell.column) &&
|
|
1022
|
+
isCellEditable(nextCell.row, nextCell.column, triggerEvent)
|
|
1023
|
+
) {
|
|
1024
|
+
startCellEditFn(nextCell.row, nextCell.column, triggerEvent);
|
|
1025
|
+
}
|
|
814
1026
|
|
|
815
|
-
|
|
816
|
-
|
|
1027
|
+
return true;
|
|
1028
|
+
},
|
|
1029
|
+
[focusRenderedCell, isCellEditable, shouldEditOnFocusFn, startCellEditFn],
|
|
1030
|
+
);
|
|
817
1031
|
|
|
818
1032
|
const runBenchmarkFn = useCallback((iterations?: number): GridBenchmarkResult => {
|
|
819
|
-
const safeIterations =
|
|
1033
|
+
const safeIterations = resolveBenchmarkIterations(
|
|
1034
|
+
iterations,
|
|
1035
|
+
optionsRef.current.benchmark?.iterations,
|
|
1036
|
+
);
|
|
820
1037
|
const startedAt = performance.now();
|
|
821
|
-
let lastResult =
|
|
1038
|
+
let lastResult = defaultGridEngine.buildPipeline({
|
|
822
1039
|
options: optionsRef.current,
|
|
823
1040
|
columns: visibleColumnsRef.current,
|
|
824
1041
|
activeFilters: activeFiltersRef.current,
|
|
@@ -834,7 +1051,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
834
1051
|
});
|
|
835
1052
|
|
|
836
1053
|
for (let i = 1; i < safeIterations; i++) {
|
|
837
|
-
lastResult =
|
|
1054
|
+
lastResult = defaultGridEngine.buildPipeline({
|
|
838
1055
|
options: optionsRef.current,
|
|
839
1056
|
columns: visibleColumnsRef.current,
|
|
840
1057
|
activeFilters: activeFiltersRef.current,
|
|
@@ -887,6 +1104,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
887
1104
|
setExpandedTreeRows({});
|
|
888
1105
|
setColumnOrder(options.columnDefs.map((column) => column.name));
|
|
889
1106
|
setGroupByColumns(options.grouping?.groupBy ?? []);
|
|
1107
|
+
setPinnedColumns(buildInitialPinnedState(options.columnDefs));
|
|
890
1108
|
setCurrentPage(options.paginationCurrentPage ?? 1);
|
|
891
1109
|
setPageSize(coreGetEffectivePageSize(options, 0, options.data.length));
|
|
892
1110
|
|
|
@@ -898,7 +1116,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
898
1116
|
});
|
|
899
1117
|
|
|
900
1118
|
const initialSort = options.columnDefs.find(
|
|
901
|
-
(column) => column.sort?.direction && !column.sort.ignoreSort
|
|
1119
|
+
(column) => column.sort?.direction && !column.sort.ignoreSort,
|
|
902
1120
|
);
|
|
903
1121
|
setSortState({
|
|
904
1122
|
columnName: initialSort?.name ?? null,
|
|
@@ -931,9 +1149,16 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
931
1149
|
if (!container) return;
|
|
932
1150
|
|
|
933
1151
|
const observer = observeGridHostSize(container, ({ height: nextHeight, width: nextWidth }) => {
|
|
934
|
-
if (nextHeight === lastGridHeightRef.current && nextWidth === lastGridWidthRef.current)
|
|
1152
|
+
if (nextHeight === lastGridHeightRef.current && nextWidth === lastGridWidthRef.current)
|
|
1153
|
+
return;
|
|
935
1154
|
|
|
936
|
-
raiseGridDimensionChanged(
|
|
1155
|
+
raiseGridDimensionChanged(
|
|
1156
|
+
gridApi,
|
|
1157
|
+
lastGridHeightRef.current,
|
|
1158
|
+
lastGridWidthRef.current,
|
|
1159
|
+
nextHeight,
|
|
1160
|
+
nextWidth,
|
|
1161
|
+
);
|
|
937
1162
|
lastGridHeightRef.current = nextHeight;
|
|
938
1163
|
lastGridWidthRef.current = nextWidth;
|
|
939
1164
|
|
|
@@ -956,55 +1181,90 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
956
1181
|
const paginationCurrentPage = getCurrentPageValueFn();
|
|
957
1182
|
const paginationTotalPages = getTotalPagesValueFn();
|
|
958
1183
|
const paginationSelectedPageSize = effectivePageSizeFn(pipeline.totalItems);
|
|
959
|
-
const viewportHeightPx =
|
|
1184
|
+
const viewportHeightPx = computeViewportHeightPx(options.viewportHeight, autoViewportHeight);
|
|
960
1185
|
|
|
961
1186
|
// --- Display helper functions ---
|
|
962
1187
|
|
|
963
1188
|
const headerLabelFn = useCallback((column: GridColumnDef): string => coreHeaderLabel(column), []);
|
|
964
|
-
const isGroupItemFn = useCallback(
|
|
965
|
-
|
|
1189
|
+
const isGroupItemFn = useCallback(
|
|
1190
|
+
(item: DisplayItem): item is GroupItem => item.kind === 'group',
|
|
1191
|
+
[],
|
|
1192
|
+
);
|
|
1193
|
+
const isExpandableItemFn = useCallback(
|
|
1194
|
+
(item: DisplayItem): item is ExpandableItem => item.kind === 'expandable',
|
|
1195
|
+
[],
|
|
1196
|
+
);
|
|
966
1197
|
const isRowItemFn = useCallback((item: DisplayItem): item is RowItem => item.kind === 'row', []);
|
|
967
|
-
const isOddStripedRowFn = useCallback(
|
|
1198
|
+
const isOddStripedRowFn = useCallback(
|
|
1199
|
+
(item: DisplayItem): boolean => item.kind === 'row' && item.visibleIndex % 2 === 0,
|
|
1200
|
+
[],
|
|
1201
|
+
);
|
|
968
1202
|
|
|
969
1203
|
const sortDirectionFn = useCallback((column: GridColumnDef): string => {
|
|
970
|
-
return sortStateRef.current.columnName === column.name
|
|
1204
|
+
return sortStateRef.current.columnName === column.name
|
|
1205
|
+
? sortStateRef.current.direction
|
|
1206
|
+
: SORT_DIRECTIONS.none;
|
|
971
1207
|
}, []);
|
|
972
1208
|
|
|
973
|
-
const sortButtonLabelFn = useCallback(
|
|
974
|
-
|
|
975
|
-
|
|
1209
|
+
const sortButtonLabelFn = useCallback(
|
|
1210
|
+
(column: GridColumnDef): string => {
|
|
1211
|
+
return gridSortButtonLabel(sortDirectionFn(column) as any, labels);
|
|
1212
|
+
},
|
|
1213
|
+
[labels, sortDirectionFn],
|
|
1214
|
+
);
|
|
976
1215
|
|
|
977
|
-
const sortAriaSortFn = useCallback(
|
|
978
|
-
|
|
979
|
-
|
|
1216
|
+
const sortAriaSortFn = useCallback(
|
|
1217
|
+
(column: GridColumnDef): string => {
|
|
1218
|
+
return gridSortAriaSort(sortDirectionFn(column) as any);
|
|
1219
|
+
},
|
|
1220
|
+
[sortDirectionFn],
|
|
1221
|
+
);
|
|
980
1222
|
|
|
981
|
-
const groupingButtonLabelFn = useCallback(
|
|
982
|
-
|
|
983
|
-
|
|
1223
|
+
const groupingButtonLabelFn = useCallback(
|
|
1224
|
+
(column: GridColumnDef): string => {
|
|
1225
|
+
return gridGroupingButtonLabel(
|
|
1226
|
+
isGridColumnGrouped(groupByColumnsRef.current, column),
|
|
1227
|
+
labels,
|
|
1228
|
+
);
|
|
1229
|
+
},
|
|
1230
|
+
[labels],
|
|
1231
|
+
);
|
|
984
1232
|
|
|
985
1233
|
const filterValueFn = useCallback((columnName: string): string => {
|
|
986
1234
|
return activeFiltersRef.current[columnName] ?? '';
|
|
987
1235
|
}, []);
|
|
988
1236
|
|
|
989
|
-
const filterPlaceholderFn = useCallback(
|
|
990
|
-
|
|
991
|
-
|
|
1237
|
+
const filterPlaceholderFn = useCallback(
|
|
1238
|
+
(column: GridColumnDef): string => {
|
|
1239
|
+
return gridFilterPlaceholder(isGridColumnFilterable(optionsRef.current, column), labels);
|
|
1240
|
+
},
|
|
1241
|
+
[labels],
|
|
1242
|
+
);
|
|
992
1243
|
|
|
993
1244
|
const isFilterInputDisabledFn = useCallback((column: GridColumnDef): boolean => {
|
|
994
1245
|
return !isGridColumnFilterable(optionsRef.current, column);
|
|
995
1246
|
}, []);
|
|
996
1247
|
|
|
997
|
-
const groupDisclosureLabelFn = useCallback(
|
|
998
|
-
|
|
999
|
-
|
|
1248
|
+
const groupDisclosureLabelFn = useCallback(
|
|
1249
|
+
(item: GroupItem): string => {
|
|
1250
|
+
return gridGroupDisclosureLabel(item.collapsed, labels);
|
|
1251
|
+
},
|
|
1252
|
+
[labels],
|
|
1253
|
+
);
|
|
1000
1254
|
|
|
1001
|
-
const cellContextFn = useCallback(
|
|
1002
|
-
|
|
1003
|
-
|
|
1255
|
+
const cellContextFn = useCallback(
|
|
1256
|
+
(row: GridRow, column: GridColumnDef): GridCellTemplateContext => {
|
|
1257
|
+
return buildGridCellContext(row, column);
|
|
1258
|
+
},
|
|
1259
|
+
[],
|
|
1260
|
+
);
|
|
1004
1261
|
|
|
1005
|
-
const displayValueFn = useCallback(
|
|
1006
|
-
|
|
1007
|
-
|
|
1262
|
+
const displayValueFn = useCallback(
|
|
1263
|
+
(row: GridRow, column: GridColumnDef): string => {
|
|
1264
|
+
return formatGridCellDisplayValue(cellContextFn(row, column));
|
|
1265
|
+
},
|
|
1266
|
+
[cellContextFn],
|
|
1267
|
+
);
|
|
1008
1268
|
|
|
1009
1269
|
const isFocusedCellFn = useCallback((row: GridRow, column: GridColumnDef): boolean => {
|
|
1010
1270
|
return isGridCellPosition(focusedCellRef.current, row.id, column.name);
|
|
@@ -1018,15 +1278,18 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1018
1278
|
return gridEditorInputType(column);
|
|
1019
1279
|
}, []);
|
|
1020
1280
|
|
|
1021
|
-
const expandedContextFn = useCallback(
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1281
|
+
const expandedContextFn = useCallback(
|
|
1282
|
+
(row: GridRow): GridExpandableTemplateContext & Record<string, unknown> => {
|
|
1283
|
+
return {
|
|
1284
|
+
$implicit: row.entity,
|
|
1285
|
+
row: row.entity,
|
|
1286
|
+
rowIndex: row.index,
|
|
1287
|
+
expanded: true,
|
|
1288
|
+
...(optionsRef.current.expandableRowScope ?? {}),
|
|
1289
|
+
};
|
|
1290
|
+
},
|
|
1291
|
+
[],
|
|
1292
|
+
);
|
|
1030
1293
|
|
|
1031
1294
|
const columnWidthFn = useCallback((column: GridColumnDef): string => gridColumnWidth(column), []);
|
|
1032
1295
|
|
|
@@ -1042,17 +1305,23 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1042
1305
|
return gridCellIndent(optionsRef.current, visibleColumnsRef.current, row, column);
|
|
1043
1306
|
}, []);
|
|
1044
1307
|
|
|
1045
|
-
const treeToggleLabelFn = useCallback(
|
|
1046
|
-
|
|
1047
|
-
|
|
1308
|
+
const treeToggleLabelFn = useCallback(
|
|
1309
|
+
(row: GridRow): string => {
|
|
1310
|
+
return gridTreeToggleLabelForRow(expandedTreeRowsRef.current, row, labels);
|
|
1311
|
+
},
|
|
1312
|
+
[labels],
|
|
1313
|
+
);
|
|
1048
1314
|
|
|
1049
1315
|
const isTreeRowExpandedFn = useCallback((row: GridRow): boolean => {
|
|
1050
1316
|
return isGridTreeRowExpanded(expandedTreeRowsRef.current, row);
|
|
1051
1317
|
}, []);
|
|
1052
1318
|
|
|
1053
|
-
const expandToggleLabelFn = useCallback(
|
|
1054
|
-
|
|
1055
|
-
|
|
1319
|
+
const expandToggleLabelFn = useCallback(
|
|
1320
|
+
(row: GridRow): string => {
|
|
1321
|
+
return gridExpandToggleLabelForRow(row, labels);
|
|
1322
|
+
},
|
|
1323
|
+
[labels],
|
|
1324
|
+
);
|
|
1056
1325
|
|
|
1057
1326
|
const isGroupedFn = useCallback((column: GridColumnDef): boolean => {
|
|
1058
1327
|
return isGridColumnGrouped(groupByColumnsRef.current, column);
|
|
@@ -1072,8 +1341,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1072
1341
|
|
|
1073
1342
|
const paginationSummaryFn = useCallback((): string => {
|
|
1074
1343
|
const ti = pipelineRef.current.totalItems;
|
|
1075
|
-
|
|
1076
|
-
return `${getFirstRowIndexValueFn(ti) + 1}-${getLastRowIndexValueFn(ti) + 1} of ${ti}`;
|
|
1344
|
+
return formatPaginationSummary(ti, getFirstRowIndexValueFn(ti), getLastRowIndexValueFn(ti));
|
|
1077
1345
|
}, [getFirstRowIndexValueFn, getLastRowIndexValueFn]);
|
|
1078
1346
|
|
|
1079
1347
|
const pageSizeOptionsFn = useCallback((): number[] => {
|
|
@@ -1093,7 +1361,10 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1093
1361
|
const toggleSortFn = useCallback((column: GridColumnDef): void => {
|
|
1094
1362
|
if (!FEATURE_SORTING || !isGridColumnSortable(optionsRef.current, column)) return;
|
|
1095
1363
|
|
|
1096
|
-
const currentDirection =
|
|
1364
|
+
const currentDirection =
|
|
1365
|
+
sortStateRef.current.columnName === column.name
|
|
1366
|
+
? sortStateRef.current.direction
|
|
1367
|
+
: SORT_DIRECTIONS.none;
|
|
1097
1368
|
const nextDirection =
|
|
1098
1369
|
currentDirection === SORT_DIRECTIONS.none
|
|
1099
1370
|
? SORT_DIRECTIONS.asc
|
|
@@ -1113,7 +1384,7 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1113
1384
|
(updater) => setActiveFilters((current) => updater(current)),
|
|
1114
1385
|
() => activeFiltersRef.current,
|
|
1115
1386
|
columnName,
|
|
1116
|
-
value
|
|
1387
|
+
value,
|
|
1117
1388
|
);
|
|
1118
1389
|
}, []);
|
|
1119
1390
|
|
|
@@ -1140,126 +1411,151 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1140
1411
|
}));
|
|
1141
1412
|
}, []);
|
|
1142
1413
|
|
|
1143
|
-
const focusCellFn = useCallback(
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1414
|
+
const focusCellFn = useCallback(
|
|
1415
|
+
(row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null): void => {
|
|
1416
|
+
const nextFocusResult = buildGridFocusCellResult({
|
|
1417
|
+
currentFocusedCell: focusedCellRef.current,
|
|
1418
|
+
currentEditingCell: editingCellRef.current,
|
|
1419
|
+
rowId: row.id,
|
|
1420
|
+
columnName: column.name,
|
|
1421
|
+
shouldEditOnFocus: shouldEditOnFocusFn(column),
|
|
1422
|
+
isCellEditable: isCellEditable(row, column, triggerEvent),
|
|
1423
|
+
});
|
|
1424
|
+
setFocusedCell(nextFocusResult.focusedCell);
|
|
1153
1425
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1426
|
+
if (nextFocusResult.shouldBeginEdit) {
|
|
1427
|
+
startCellEditFn(row, column, triggerEvent);
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
[isCellEditable, shouldEditOnFocusFn, startCellEditFn],
|
|
1431
|
+
);
|
|
1158
1432
|
|
|
1159
|
-
const handleCellKeyDownFn = useCallback(
|
|
1160
|
-
|
|
1433
|
+
const handleCellKeyDownFn = useCallback(
|
|
1434
|
+
(row: GridRow, column: GridColumnDef, event: React.KeyboardEvent): void => {
|
|
1435
|
+
focusCellFn(row, column, event.nativeEvent);
|
|
1161
1436
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
event.preventDefault();
|
|
1165
|
-
moveFocusFn(row, column, 'left', event.nativeEvent);
|
|
1166
|
-
return;
|
|
1167
|
-
case 'ArrowRight':
|
|
1168
|
-
event.preventDefault();
|
|
1169
|
-
moveFocusFn(row, column, 'right', event.nativeEvent);
|
|
1170
|
-
return;
|
|
1171
|
-
case 'ArrowUp':
|
|
1172
|
-
event.preventDefault();
|
|
1173
|
-
moveFocusFn(row, column, 'up', event.nativeEvent);
|
|
1174
|
-
return;
|
|
1175
|
-
case 'ArrowDown':
|
|
1176
|
-
event.preventDefault();
|
|
1177
|
-
moveFocusFn(row, column, 'down', event.nativeEvent);
|
|
1178
|
-
return;
|
|
1179
|
-
case 'Tab':
|
|
1180
|
-
event.preventDefault();
|
|
1181
|
-
moveFocusFn(row, column, event.shiftKey ? 'left' : 'right', event.nativeEvent);
|
|
1182
|
-
return;
|
|
1183
|
-
case 'Enter':
|
|
1184
|
-
event.preventDefault();
|
|
1185
|
-
moveFocusFn(row, column, event.shiftKey ? 'up' : 'down', event.nativeEvent);
|
|
1186
|
-
return;
|
|
1187
|
-
case 'F2':
|
|
1188
|
-
event.preventDefault();
|
|
1189
|
-
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1190
|
-
startCellEditFn(row, column, event.nativeEvent);
|
|
1191
|
-
}
|
|
1192
|
-
return;
|
|
1193
|
-
case 'Backspace':
|
|
1194
|
-
case 'Delete':
|
|
1195
|
-
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1437
|
+
switch (event.key) {
|
|
1438
|
+
case 'ArrowLeft':
|
|
1196
1439
|
event.preventDefault();
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1440
|
+
moveFocusFn(row, column, 'left', event.nativeEvent);
|
|
1441
|
+
return;
|
|
1442
|
+
case 'ArrowRight':
|
|
1443
|
+
event.preventDefault();
|
|
1444
|
+
moveFocusFn(row, column, 'right', event.nativeEvent);
|
|
1445
|
+
return;
|
|
1446
|
+
case 'ArrowUp':
|
|
1447
|
+
event.preventDefault();
|
|
1448
|
+
moveFocusFn(row, column, 'up', event.nativeEvent);
|
|
1449
|
+
return;
|
|
1450
|
+
case 'ArrowDown':
|
|
1451
|
+
event.preventDefault();
|
|
1452
|
+
moveFocusFn(row, column, 'down', event.nativeEvent);
|
|
1453
|
+
return;
|
|
1454
|
+
case 'Tab':
|
|
1455
|
+
event.preventDefault();
|
|
1456
|
+
moveFocusFn(row, column, event.shiftKey ? 'left' : 'right', event.nativeEvent);
|
|
1457
|
+
return;
|
|
1458
|
+
case 'Enter':
|
|
1459
|
+
event.preventDefault();
|
|
1460
|
+
moveFocusFn(row, column, event.shiftKey ? 'up' : 'down', event.nativeEvent);
|
|
1461
|
+
return;
|
|
1462
|
+
case 'F2':
|
|
1463
|
+
event.preventDefault();
|
|
1464
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1465
|
+
startCellEditFn(row, column, event.nativeEvent);
|
|
1466
|
+
}
|
|
1467
|
+
return;
|
|
1468
|
+
case 'Backspace':
|
|
1469
|
+
case 'Delete':
|
|
1470
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1471
|
+
event.preventDefault();
|
|
1472
|
+
startCellEditFn(row, column, event.nativeEvent, '');
|
|
1473
|
+
}
|
|
1474
|
+
return;
|
|
1475
|
+
default:
|
|
1476
|
+
break;
|
|
1477
|
+
}
|
|
1203
1478
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1479
|
+
if (
|
|
1480
|
+
isPrintableGridKey(event.key, event.ctrlKey, event.metaKey, event.altKey) &&
|
|
1481
|
+
isCellEditable(row, column, event.nativeEvent)
|
|
1482
|
+
) {
|
|
1483
|
+
event.preventDefault();
|
|
1484
|
+
startCellEditFn(row, column, event.nativeEvent, event.key);
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
[focusCellFn, moveFocusFn, isCellEditable, startCellEditFn],
|
|
1488
|
+
);
|
|
1209
1489
|
|
|
1210
|
-
const handleCellDoubleClickFn = useCallback(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1490
|
+
const handleCellDoubleClickFn = useCallback(
|
|
1491
|
+
(row: GridRow, column: GridColumnDef, event: React.MouseEvent): void => {
|
|
1492
|
+
focusCellFn(row, column, event.nativeEvent);
|
|
1493
|
+
if (isCellEditable(row, column, event.nativeEvent)) {
|
|
1494
|
+
startCellEditFn(row, column, event.nativeEvent);
|
|
1495
|
+
}
|
|
1496
|
+
},
|
|
1497
|
+
[focusCellFn, isCellEditable, startCellEditFn],
|
|
1498
|
+
);
|
|
1216
1499
|
|
|
1217
1500
|
const updateEditingValueFn = useCallback((value: string): void => {
|
|
1218
1501
|
setEditingValue(value);
|
|
1219
1502
|
}, []);
|
|
1220
1503
|
|
|
1221
|
-
const handleEditorKeyDownFn = useCallback(
|
|
1222
|
-
|
|
1223
|
-
event.
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
event.
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
event.
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1504
|
+
const handleEditorKeyDownFn = useCallback(
|
|
1505
|
+
(event: React.KeyboardEvent): void => {
|
|
1506
|
+
if (event.key === 'Escape') {
|
|
1507
|
+
event.preventDefault();
|
|
1508
|
+
cancelCellEditFn();
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
if (event.key === 'Enter') {
|
|
1512
|
+
event.preventDefault();
|
|
1513
|
+
commitCellEditFn(event.shiftKey ? 'up' : 'down');
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
if (event.key === 'Tab') {
|
|
1517
|
+
event.preventDefault();
|
|
1518
|
+
commitCellEditFn(event.shiftKey ? 'left' : 'right');
|
|
1519
|
+
}
|
|
1520
|
+
},
|
|
1521
|
+
[cancelCellEditFn, commitCellEditFn],
|
|
1522
|
+
);
|
|
1237
1523
|
|
|
1238
|
-
const handleEditorBlurFn = useCallback(
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1524
|
+
const handleEditorBlurFn = useCallback(
|
|
1525
|
+
(event: React.FocusEvent): void => {
|
|
1526
|
+
const ec = editingCellRef.current;
|
|
1527
|
+
const target = event.target as HTMLElement | null;
|
|
1528
|
+
if (!ec || !target) return;
|
|
1529
|
+
if (target.dataset['rowId'] !== ec.rowId || target.dataset['colName'] !== ec.columnName)
|
|
1530
|
+
return;
|
|
1531
|
+
commitCellEditFn(undefined, false);
|
|
1532
|
+
},
|
|
1533
|
+
[commitCellEditFn],
|
|
1534
|
+
);
|
|
1245
1535
|
|
|
1246
|
-
const toggleRowExpansionFn = useCallback(
|
|
1247
|
-
event
|
|
1248
|
-
|
|
1249
|
-
|
|
1536
|
+
const toggleRowExpansionFn = useCallback(
|
|
1537
|
+
(row: GridRow, event?: React.MouseEvent): void => {
|
|
1538
|
+
event?.stopPropagation();
|
|
1539
|
+
toggleRowExpansionByRefFn(row);
|
|
1540
|
+
},
|
|
1541
|
+
[toggleRowExpansionByRefFn],
|
|
1542
|
+
);
|
|
1250
1543
|
|
|
1251
|
-
const toggleTreeRowFn = useCallback(
|
|
1252
|
-
event
|
|
1253
|
-
|
|
1254
|
-
|
|
1544
|
+
const toggleTreeRowFn = useCallback(
|
|
1545
|
+
(row: GridRow, event?: React.MouseEvent): void => {
|
|
1546
|
+
event?.stopPropagation();
|
|
1547
|
+
toggleTreeRowByRefFn(row);
|
|
1548
|
+
},
|
|
1549
|
+
[toggleTreeRowByRefFn],
|
|
1550
|
+
);
|
|
1255
1551
|
|
|
1256
1552
|
const moveColumnFn = useCallback((fromIndex: number, toIndex: number): void => {
|
|
1257
1553
|
moveGridColumnCommand(
|
|
1258
1554
|
gridApiRef.current!,
|
|
1259
|
-
FEATURE_COLUMN_MOVING &&
|
|
1555
|
+
FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
|
|
1260
1556
|
(updater) => setColumnOrder((current) => updater(current)),
|
|
1261
1557
|
fromIndex,
|
|
1262
|
-
toIndex
|
|
1558
|
+
toIndex,
|
|
1263
1559
|
);
|
|
1264
1560
|
}, []);
|
|
1265
1561
|
|
|
@@ -1271,9 +1567,12 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1271
1567
|
seekPageFn(getCurrentPageValueFn() - 1);
|
|
1272
1568
|
}, [seekPageFn, getCurrentPageValueFn]);
|
|
1273
1569
|
|
|
1274
|
-
const onPageSizeChangeFn = useCallback(
|
|
1275
|
-
|
|
1276
|
-
|
|
1570
|
+
const onPageSizeChangeFn = useCallback(
|
|
1571
|
+
(value: string): void => {
|
|
1572
|
+
setPaginationPageSizeFn(Number(value));
|
|
1573
|
+
},
|
|
1574
|
+
[setPaginationPageSizeFn],
|
|
1575
|
+
);
|
|
1277
1576
|
|
|
1278
1577
|
const onViewportScrollFn = useCallback((startIndex: number): void => {
|
|
1279
1578
|
if (!scrollingRef.current) {
|
|
@@ -1290,11 +1589,11 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1290
1589
|
raiseGridScrollEnd(gridApiRef.current!);
|
|
1291
1590
|
}, 120);
|
|
1292
1591
|
|
|
1293
|
-
const isInfiniteScrollEnabled =
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1592
|
+
const isInfiniteScrollEnabled =
|
|
1593
|
+
FEATURE_INFINITE_SCROLL &&
|
|
1594
|
+
(optionsRef.current.infiniteScrollRowsFromEnd !== undefined ||
|
|
1595
|
+
optionsRef.current.infiniteScrollUp === true ||
|
|
1596
|
+
optionsRef.current.infiniteScrollDown !== undefined);
|
|
1298
1597
|
|
|
1299
1598
|
maybeRequestInfiniteScrollCommand(gridApiRef.current!, {
|
|
1300
1599
|
enabled: isInfiniteScrollEnabled,
|
|
@@ -1302,7 +1601,10 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1302
1601
|
state: infiniteScrollStateRef.current,
|
|
1303
1602
|
startIndex,
|
|
1304
1603
|
visibleRows: pipelineRef.current.visibleRows.length,
|
|
1305
|
-
viewportRows:
|
|
1604
|
+
viewportRows: computeViewportRows(
|
|
1605
|
+
optionsRef.current.viewportHeight,
|
|
1606
|
+
optionsRef.current.rowHeight,
|
|
1607
|
+
),
|
|
1306
1608
|
threshold: optionsRef.current.infiniteScrollRowsFromEnd ?? 20,
|
|
1307
1609
|
setState: (state) => setInfiniteScrollState(state),
|
|
1308
1610
|
});
|
|
@@ -1410,5 +1712,12 @@ export function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridA
|
|
|
1410
1712
|
runBenchmark: runBenchmarkFn,
|
|
1411
1713
|
exportCsv: exportCsvFn,
|
|
1412
1714
|
onViewportScroll: onViewportScrollFn,
|
|
1715
|
+
// Pinning
|
|
1716
|
+
isPinned: isPinnedFn,
|
|
1717
|
+
pinnedOffset: pinnedOffsetFn,
|
|
1718
|
+
isPinningEnabled: isPinningEnabledFn,
|
|
1719
|
+
isColumnPinnable: isColumnPinnableFn,
|
|
1720
|
+
togglePin: togglePinFn,
|
|
1721
|
+
pinningFeature: FEATURE_PINNING,
|
|
1413
1722
|
};
|
|
1414
1723
|
}
|