@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/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
+ };