@alaarab/ogrid-react-fluent 2.0.11 → 2.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/esm/ColumnChooser/ColumnChooser.js +10 -128
- package/dist/esm/ColumnChooser/ColumnChooser.module.css +45 -10
- package/dist/esm/ColumnHeaderFilter/ColumnHeaderFilter.js +16 -36
- package/dist/esm/ColumnHeaderMenu/ColumnHeaderMenu.js +9 -3
- package/dist/esm/ColumnHeaderMenu/ColumnHeaderMenu.module.css +7 -7
- package/dist/esm/DataGridTable/DataGridTable.js +118 -295
- package/dist/esm/DataGridTable/DataGridTable.module.css +546 -437
- package/dist/esm/DataGridTable/DropIndicator.js +5 -0
- package/dist/esm/DataGridTable/EmptyState.js +5 -0
- package/dist/esm/DataGridTable/GridContextMenu.js +10 -32
- package/dist/esm/DataGridTable/LoadingOverlay.js +6 -0
- package/dist/esm/{FluentDataTable/FluentDataTable.js → OGrid/OGrid.js} +0 -2
- package/dist/esm/OGrid/index.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/types/ColumnChooser/ColumnChooser.d.ts +2 -8
- package/dist/types/ColumnHeaderFilter/ColumnHeaderFilter.d.ts +2 -20
- package/dist/types/DataGridTable/DropIndicator.d.ts +7 -0
- package/dist/types/DataGridTable/EmptyState.d.ts +11 -0
- package/dist/types/DataGridTable/LoadingOverlay.d.ts +6 -0
- package/dist/types/{FluentDataTable/FluentDataTable.d.ts → OGrid/OGrid.d.ts} +0 -2
- package/dist/types/OGrid/index.d.ts +1 -0
- package/dist/types/PaginationControls/PaginationControls.d.ts +2 -10
- package/dist/types/index.d.ts +1 -1
- package/package.json +3 -3
- package/dist/esm/FluentDataTable/index.js +0 -1
- package/dist/types/FluentDataTable/index.d.ts +0 -1
|
@@ -1,325 +1,148 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useMemo } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
|
-
import {
|
|
5
|
+
import { Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell, Checkbox, Popover, PopoverSurface, } from '@fluentui/react-components';
|
|
6
6
|
import { ColumnHeaderFilter } from '../ColumnHeaderFilter';
|
|
7
7
|
import { ColumnHeaderMenu } from '../ColumnHeaderMenu';
|
|
8
8
|
import { InlineCellEditor } from './InlineCellEditor';
|
|
9
9
|
import { StatusBar } from './StatusBar';
|
|
10
10
|
import { GridContextMenu } from './GridContextMenu';
|
|
11
|
-
import {
|
|
11
|
+
import { EmptyState } from './EmptyState';
|
|
12
|
+
import { LoadingOverlay } from './LoadingOverlay';
|
|
13
|
+
import { DropIndicator } from './DropIndicator';
|
|
14
|
+
import { useDataGridTableOrchestration, getHeaderFilterConfig, getCellRenderDescriptor, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, areGridRowPropsEqual, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, GRID_ROOT_STYLE, CURSOR_CELL_STYLE, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, NOOP, } from '@alaarab/ogrid-react';
|
|
12
15
|
import styles from './DataGridTable.module.css';
|
|
13
|
-
// Module-scope stable constants (avoid per-render allocations)
|
|
14
|
-
const gridRootStyle = {
|
|
15
|
-
position: 'relative',
|
|
16
|
-
flex: 1,
|
|
17
|
-
minHeight: 0,
|
|
18
|
-
display: 'flex',
|
|
19
|
-
flexDirection: 'column',
|
|
20
|
-
};
|
|
21
|
-
const CURSOR_CELL_STYLE = { cursor: 'cell' };
|
|
22
|
-
const NUMERIC_STYLE = { justifyContent: 'flex-end', textAlign: 'right' };
|
|
23
|
-
const BOOLEAN_STYLE = { justifyContent: 'center', textAlign: 'center' };
|
|
24
|
-
const EDITABLE_NUMERIC_STYLE = { cursor: 'cell', justifyContent: 'flex-end', textAlign: 'right' };
|
|
25
|
-
const EDITABLE_BOOLEAN_STYLE = { cursor: 'cell', justifyContent: 'center', textAlign: 'center' };
|
|
26
|
-
const POPOVER_ANCHOR_STYLE = { minHeight: '100%', minWidth: 40 };
|
|
27
|
-
const PREVENT_DEFAULT = (e) => { e.preventDefault(); };
|
|
28
|
-
const NOOP = () => { };
|
|
29
16
|
function GridRowInner(props) {
|
|
30
|
-
const { item,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
_jsx(DataGridRow, { className: rowClassName, onClick: () => handleSingleRowClick(rowId), children: ({ renderCell, columnId }) => (_jsx(DataGridCell, { className: cellClassMap[String(columnId)] || undefined, children: renderCell(item) })) }));
|
|
17
|
+
const { item, rowIndex, rowId, isSelected, visibleCols, columnMeta, renderCellContent, handleSingleRowClick, handleRowCheckboxChange, lastMouseShiftRef, hasCheckboxCol, hasRowNumbersCol, rowNumberOffset, } = props;
|
|
18
|
+
return (_jsxs(TableRow, { className: isSelected ? styles.selectedRow : undefined, "data-row-id": rowId, onClick: handleSingleRowClick, children: [hasCheckboxCol && (_jsx(TableCell, { className: styles.selectionCellWrapper, children: _jsx("div", { className: styles.selectionCellInner, "data-row-index": rowIndex, "data-col-index": 0, onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: isSelected, onChange: (e, data) => {
|
|
19
|
+
handleRowCheckboxChange(rowId, !!data.checked, rowIndex, lastMouseShiftRef.current);
|
|
20
|
+
}, "aria-label": `Select row ${rowIndex + 1}` }) }) })), hasRowNumbersCol && (_jsx(TableCell, { className: styles.rowNumberCellWrapper, children: _jsx("div", { className: styles.rowNumberCellInner, children: rowNumberOffset + rowIndex + 1 }) })), visibleCols.map((col, colIdx) => (_jsx(TableCell, { "data-column-id": col.columnId, className: columnMeta.cellClasses[col.columnId] || undefined, style: columnMeta.cellStyles[col.columnId], children: renderCellContent(item, col, rowIndex, colIdx) }, col.columnId)))] }));
|
|
35
21
|
}
|
|
36
22
|
const GridRow = React.memo(GridRowInner, areGridRowPropsEqual);
|
|
37
23
|
function DataGridTableInner(props) {
|
|
38
|
-
const
|
|
39
|
-
const tableContainerRef =
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const handlePasteVoid = useCallback(() => { void handlePaste(); }, [handlePaste]);
|
|
47
|
-
const { menuPosition, handleCellContextMenu, closeContextMenu } = ctxMenu;
|
|
48
|
-
const { headerFilterInput, cellDescriptorInput, statusBarConfig, showEmptyInGrid, onCellError } = viewModels;
|
|
49
|
-
const { items, columns, getRowId, emptyState, layoutMode = 'fill', rowSelection = 'none', freezeRows, freezeCols, suppressHorizontalScroll, isLoading = false, loadingMessage = 'Loading\u2026', 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, visibleColumns, columnOrder, onColumnOrderChange, columnReorder, virtualScroll, density = 'normal', pinnedColumns, currentPage = 1, pageSize: propPageSize = 25, } = props;
|
|
50
|
-
// Calculate row number offset for pagination
|
|
51
|
-
const rowNumberOffset = hasRowNumbersCol ? (currentPage - 1) * propPageSize : 0;
|
|
52
|
-
// Memoize header rows (recursive tree traversal)
|
|
53
|
-
const headerRows = useMemo(() => buildHeaderRows(columns, visibleColumns), [columns, visibleColumns]);
|
|
54
|
-
const hasGroupHeaders = headerRows.length > 1;
|
|
55
|
-
const fitToContent = layoutMode === 'content';
|
|
56
|
-
const { isDragging: isReorderDragging, dropIndicatorX, handleHeaderMouseDown } = useColumnReorder({
|
|
57
|
-
columns: visibleCols,
|
|
58
|
-
columnOrder,
|
|
59
|
-
onColumnOrderChange,
|
|
60
|
-
enabled: columnReorder === true,
|
|
61
|
-
pinnedColumns,
|
|
62
|
-
wrapperRef,
|
|
63
|
-
});
|
|
64
|
-
const virtualScrollEnabled = virtualScroll?.enabled === true;
|
|
65
|
-
const virtualRowHeight = virtualScroll?.rowHeight ?? 36;
|
|
66
|
-
const { visibleRange } = useVirtualScroll({
|
|
67
|
-
totalRows: items.length,
|
|
68
|
-
rowHeight: virtualRowHeight,
|
|
69
|
-
enabled: virtualScrollEnabled,
|
|
70
|
-
overscan: virtualScroll?.overscan,
|
|
71
|
-
containerRef: wrapperRef,
|
|
72
|
-
});
|
|
73
|
-
const columnSizingOptions = useMemo(() => {
|
|
74
|
-
const acc = {};
|
|
75
|
-
if (hasCheckboxCol) {
|
|
76
|
-
acc['__selection__'] = { minWidth: CHECKBOX_COLUMN_WIDTH, defaultWidth: CHECKBOX_COLUMN_WIDTH, idealWidth: CHECKBOX_COLUMN_WIDTH };
|
|
77
|
-
}
|
|
78
|
-
if (hasRowNumbersCol) {
|
|
79
|
-
acc['__row_number__'] = { minWidth: ROW_NUMBER_COLUMN_WIDTH, defaultWidth: ROW_NUMBER_COLUMN_WIDTH, idealWidth: ROW_NUMBER_COLUMN_WIDTH };
|
|
80
|
-
}
|
|
81
|
-
visibleCols.forEach((c) => {
|
|
82
|
-
const minW = c.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
|
|
83
|
-
const defaultW = c.defaultWidth ?? 120;
|
|
84
|
-
const base = c.idealWidth ?? Math.max(minW, defaultW);
|
|
85
|
-
const override = columnSizingOverrides[c.columnId];
|
|
86
|
-
const w = override ? Math.max(minW, override.widthPx) : base;
|
|
87
|
-
acc[c.columnId] = {
|
|
88
|
-
minWidth: minW,
|
|
89
|
-
defaultWidth: w,
|
|
90
|
-
idealWidth: w,
|
|
91
|
-
};
|
|
92
|
-
});
|
|
93
|
-
return acc;
|
|
94
|
-
}, [visibleCols, columnSizingOverrides, hasCheckboxCol, hasRowNumbersCol]);
|
|
95
|
-
const allowOverflowX = !suppressHorizontalScroll && containerWidth > 0 && (minTableWidth > containerWidth || desiredTableWidth > containerWidth);
|
|
96
|
-
// Pre-compute column class maps (avoids per-cell .filter(Boolean).join(' '))
|
|
97
|
-
const { cellClassMap, headerClassMap } = useMemo(() => {
|
|
98
|
-
const cm = {};
|
|
99
|
-
const hm = {};
|
|
24
|
+
const o = useDataGridTableOrchestration({ props });
|
|
25
|
+
const { wrapperRef, tableContainerRef, lastMouseShiftRef, interaction, pinning, handleResizeStart, getColumnWidth, isReorderDragging, dropIndicatorX, handleHeaderMouseDown, virtualScrollEnabled, visibleRange, items, getRowId, emptyState, rowSelection, freezeRows, freezeCols, isLoading, loadingMessage, ariaLabel, ariaLabelledBy, visibleColumns, columnOrder, columnReorder, density, rowNumberOffset, headerRows, allowOverflowX, fitToContent, editCallbacks, interactionHandlers, cellDescriptorInputRef, pendingEditorValueRef, popoverAnchorElRef, handleSingleRowClick, handlePasteVoid, visibleCols, totalColCount, hasCheckboxCol, hasRowNumbersCol, colOffset, containerWidth, minTableWidth, columnSizingOverrides, selectedRowIds, handleRowCheckboxChange, handleSelectAll, allSelected, someSelected, editingCell, setPopoverAnchorEl, cancelPopoverEdit, setActiveCell, selectionRange, hasCellSelection, handleGridKeyDown, handleFillHandleMouseDown, handleCopy, handleCut, cutRange, copyRange, canUndo, canRedo, onUndo, onRedo, isDragging, menuPosition, closeContextMenu, headerFilterInput, statusBarConfig, showEmptyInGrid, onCellError, headerMenu, } = o;
|
|
26
|
+
// Pre-compute column styles and classNames (avoids per-cell object creation in the row loop)
|
|
27
|
+
const columnMeta = useMemo(() => {
|
|
28
|
+
const cellStyles = {};
|
|
29
|
+
const cellClasses = {};
|
|
30
|
+
const hdrStyles = {};
|
|
31
|
+
const hdrClasses = {};
|
|
100
32
|
for (let i = 0; i < visibleCols.length; i++) {
|
|
101
33
|
const col = visibleCols[i];
|
|
34
|
+
const columnWidth = getColumnWidth(col);
|
|
35
|
+
const hasExplicitWidth = !!(columnSizingOverrides[col.columnId] || col.idealWidth != null || col.defaultWidth != null);
|
|
102
36
|
const isFreezeCol = freezeCols != null && freezeCols >= 1 && i < freezeCols;
|
|
103
|
-
const isPinnedLeft = col.
|
|
104
|
-
const isPinnedRight = col.
|
|
37
|
+
const isPinnedLeft = pinning.pinnedColumns[col.columnId] === 'left';
|
|
38
|
+
const isPinnedRight = pinning.pinnedColumns[col.columnId] === 'right';
|
|
39
|
+
const hasResizeOverride = !!columnSizingOverrides[col.columnId];
|
|
40
|
+
const isPinned = isPinnedLeft || isPinnedRight;
|
|
41
|
+
cellStyles[col.columnId] = {
|
|
42
|
+
minWidth: hasResizeOverride ? columnWidth : (col.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH),
|
|
43
|
+
width: hasExplicitWidth ? columnWidth : undefined,
|
|
44
|
+
maxWidth: hasExplicitWidth ? columnWidth : undefined,
|
|
45
|
+
textAlign: col.type === 'numeric' ? 'right' : col.type === 'boolean' ? 'center' : undefined,
|
|
46
|
+
// Fluent UI's TableCell injects atomic CSS `position: relative` which overrides the
|
|
47
|
+
// shared `.pinnedColLeft { position: sticky }` class. Inline style wins over atomic CSS.
|
|
48
|
+
...(isPinned ? { position: 'sticky' } : undefined),
|
|
49
|
+
...(isPinnedLeft && pinning.leftOffsets[col.columnId] != null ? { left: pinning.leftOffsets[col.columnId] } : undefined),
|
|
50
|
+
...(isPinnedRight && pinning.rightOffsets[col.columnId] != null ? { right: pinning.rightOffsets[col.columnId] } : undefined),
|
|
51
|
+
};
|
|
52
|
+
hdrStyles[col.columnId] = {
|
|
53
|
+
minWidth: hasResizeOverride ? columnWidth : (col.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH),
|
|
54
|
+
width: hasExplicitWidth ? columnWidth : undefined,
|
|
55
|
+
maxWidth: hasExplicitWidth ? columnWidth : undefined,
|
|
56
|
+
...(isPinned ? { position: 'sticky' } : undefined),
|
|
57
|
+
...(isPinnedLeft && pinning.leftOffsets[col.columnId] != null ? { left: pinning.leftOffsets[col.columnId] } : undefined),
|
|
58
|
+
...(isPinnedRight && pinning.rightOffsets[col.columnId] != null ? { right: pinning.rightOffsets[col.columnId] } : undefined),
|
|
59
|
+
};
|
|
105
60
|
const parts = [];
|
|
106
61
|
if (isFreezeCol)
|
|
107
62
|
parts.push(styles.freezeCol);
|
|
108
63
|
if (isFreezeCol && i === 0)
|
|
109
64
|
parts.push(styles.freezeColFirst);
|
|
110
|
-
if (isPinnedLeft)
|
|
111
|
-
parts.push(styles.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
65
|
+
if (isPinnedLeft)
|
|
66
|
+
parts.push(styles.pinnedColLeft);
|
|
67
|
+
if (isPinnedRight)
|
|
68
|
+
parts.push(styles.pinnedColRight);
|
|
69
|
+
const cn = parts.join(' ');
|
|
70
|
+
cellClasses[col.columnId] = cn;
|
|
71
|
+
hdrClasses[col.columnId] = cn;
|
|
72
|
+
}
|
|
73
|
+
return { cellStyles, cellClasses, hdrStyles, hdrClasses };
|
|
74
|
+
}, [visibleCols, getColumnWidth, columnSizingOverrides, freezeCols, pinning.pinnedColumns, pinning.leftOffsets, pinning.rightOffsets]);
|
|
75
|
+
// renderCellContent reads volatile state from refs -- keeps function identity stable so
|
|
76
|
+
// GridRow's React.memo comparator can skip rows whose selection state hasn't changed.
|
|
77
|
+
const renderCellContent = useCallback((item, col, rowIndex, colIdx) => {
|
|
78
|
+
const descriptor = getCellRenderDescriptor(item, col, rowIndex, colIdx, cellDescriptorInputRef.current);
|
|
79
|
+
const rowId = getRowId(item);
|
|
80
|
+
let content;
|
|
81
|
+
if (descriptor.mode === 'editing-inline') {
|
|
82
|
+
content = _jsx(InlineCellEditor, { ...buildInlineEditorProps(item, col, descriptor, editCallbacks) });
|
|
120
83
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const selectedRowIdsRef = useLatestRef(selectedRowIds);
|
|
128
|
-
const activeCellRef = useLatestRef(activeCell);
|
|
129
|
-
const pendingEditorValueRef = useLatestRef(pendingEditorValue);
|
|
130
|
-
const popoverAnchorElRef = useLatestRef(popoverAnchorEl);
|
|
131
|
-
const allSelectedRef = useLatestRef(allSelected);
|
|
132
|
-
const someSelectedRef = useLatestRef(someSelected);
|
|
133
|
-
// Callback refs — stabilize fluentColumns memo (these change identity on state updates
|
|
134
|
-
// but the columns structure doesn't need rebuilding for that)
|
|
135
|
-
const headerFilterInputRef = useLatestRef(headerFilterInput);
|
|
136
|
-
const commitCellEditRef = useLatestRef(commitCellEdit);
|
|
137
|
-
const cancelPopoverEditRef = useLatestRef(cancelPopoverEdit);
|
|
138
|
-
const handleCellMouseDownRef = useLatestRef(handleCellMouseDown);
|
|
139
|
-
const handleFillHandleMouseDownRef = useLatestRef(handleFillHandleMouseDown);
|
|
140
|
-
const handleCellContextMenuRef = useLatestRef(handleCellContextMenu);
|
|
141
|
-
const setActiveCellRef = useLatestRef(setActiveCell);
|
|
142
|
-
const setEditingCellRef = useLatestRef(setEditingCell);
|
|
143
|
-
const setPendingEditorValueRef = useLatestRef(setPendingEditorValue);
|
|
144
|
-
const handleSelectAllRef = useLatestRef(handleSelectAll);
|
|
145
|
-
const handleRowCheckboxChangeRef = useLatestRef(handleRowCheckboxChange);
|
|
146
|
-
const rowIndexByRowIdRef = useLatestRef(rowIndexByRowId);
|
|
147
|
-
const handleHeaderMouseDownRef = useLatestRef(handleHeaderMouseDown);
|
|
148
|
-
const isReorderDraggingRef = useLatestRef(isReorderDragging);
|
|
149
|
-
const fluentColumns = useMemo(() => {
|
|
150
|
-
const dataCols = visibleCols.map((col, colIdx) => createTableColumn({
|
|
151
|
-
columnId: col.columnId,
|
|
152
|
-
compare: col.compare ?? (() => 0),
|
|
153
|
-
renderHeaderCell: () => (_jsx("div", { "data-column-id": col.columnId, style: columnReorder ? { cursor: isReorderDraggingRef.current ? 'grabbing' : 'grab' } : undefined, onMouseDown: columnReorder ? (e) => handleHeaderMouseDownRef.current(col.columnId, e) : undefined, children: _jsxs("div", { className: styles.headerCellContent, children: [_jsx(ColumnHeaderFilter, { ...getHeaderFilterConfig(col, headerFilterInputRef.current) }), _jsx("button", { className: styles.headerMenuTrigger, onClick: (e) => {
|
|
154
|
-
e.stopPropagation();
|
|
155
|
-
pinning.headerMenu.open(col.columnId, e.currentTarget);
|
|
156
|
-
}, "aria-label": "Column options", title: "Column options", children: "\u22EE" })] }) })),
|
|
157
|
-
renderCell: (item) => {
|
|
158
|
-
const rowId = getRowId(item);
|
|
159
|
-
const rowIndex = rowIndexByRowIdRef.current.get(rowId) ?? -1;
|
|
160
|
-
const descriptor = getCellRenderDescriptor(item, col, rowIndex, colIdx, cellDescriptorInputRef.current);
|
|
161
|
-
let cellContent;
|
|
162
|
-
if (descriptor.mode === 'editing-inline') {
|
|
163
|
-
cellContent = _jsx(InlineCellEditor, { ...buildInlineEditorProps(item, col, descriptor, { commitCellEdit: commitCellEditRef.current, setEditingCell: setEditingCellRef.current }) });
|
|
164
|
-
}
|
|
165
|
-
else if (descriptor.mode === 'editing-popover' && typeof col.cellEditor === 'function') {
|
|
166
|
-
const editorProps = buildPopoverEditorProps(item, col, descriptor, pendingEditorValueRef.current, { setPendingEditorValue: setPendingEditorValueRef.current, commitCellEdit: commitCellEditRef.current, cancelPopoverEdit: cancelPopoverEditRef.current });
|
|
167
|
-
const CustomEditor = col.cellEditor;
|
|
168
|
-
cellContent = (_jsxs(_Fragment, { children: [_jsx("div", { ref: (el) => { if (el)
|
|
169
|
-
setPopoverAnchorEl(el); }, style: POPOVER_ANCHOR_STYLE, "aria-hidden": true }), _jsx(Popover, { open: !!popoverAnchorElRef.current, onOpenChange: (_, data) => { if (!data.open)
|
|
170
|
-
cancelPopoverEditRef.current(); }, positioning: { target: popoverAnchorElRef.current ?? undefined }, children: _jsx(PopoverSurface, { children: _jsx(CustomEditor, { ...editorProps }) }) })] }));
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
const content = resolveCellDisplayContent(col, item, descriptor.displayValue);
|
|
174
|
-
const cellStyle = resolveCellStyle(col, item);
|
|
175
|
-
const styledContent = cellStyle ? _jsx("span", { style: cellStyle, children: content }) : content;
|
|
176
|
-
const cellClassNames = `${styles.cellContent}${descriptor.isActive && !descriptor.isInRange ? ` ${styles.activeCellContent}` : ''}${descriptor.isInRange ? ` ${styles.cellInRange}` : ''}${descriptor.isInCutRange ? ` ${styles.cellCut}` : ''}${descriptor.isInCopyRange ? ` ${styles.cellCopied}` : ''}`;
|
|
177
|
-
const colType = col.type;
|
|
178
|
-
const interactionProps = getCellInteractionProps(descriptor, col.columnId, { handleCellMouseDown: handleCellMouseDownRef.current, setActiveCell: setActiveCellRef.current, setEditingCell: setEditingCellRef.current, handleCellContextMenu: handleCellContextMenuRef.current });
|
|
179
|
-
// Select stable style constant by type + editability
|
|
180
|
-
const computedStyle = descriptor.canEditAny
|
|
181
|
-
? (colType === 'numeric' ? EDITABLE_NUMERIC_STYLE : colType === 'boolean' ? EDITABLE_BOOLEAN_STYLE : CURSOR_CELL_STYLE)
|
|
182
|
-
: (colType === 'numeric' ? NUMERIC_STYLE : colType === 'boolean' ? BOOLEAN_STYLE : undefined);
|
|
183
|
-
cellContent = (_jsxs("div", { className: cellClassNames, ...interactionProps, style: computedStyle, children: [styledContent, descriptor.canEditAny && descriptor.isSelectionEndCell && (_jsx("div", { className: styles.fillHandle, onMouseDown: (e) => handleFillHandleMouseDownRef.current(e), "aria-label": "Fill handle" }))] }));
|
|
184
|
-
}
|
|
185
|
-
return (_jsx(CellErrorBoundary, { onError: onCellError, children: cellContent }, `${rowId}-${col.columnId}`));
|
|
186
|
-
},
|
|
187
|
-
}));
|
|
188
|
-
if (hasCheckboxCol) {
|
|
189
|
-
const checkboxCol = createTableColumn({
|
|
190
|
-
columnId: '__selection__',
|
|
191
|
-
compare: () => 0,
|
|
192
|
-
renderHeaderCell: () => (_jsx("div", { className: styles.selectionHeaderCell, children: _jsx(Checkbox, { checked: allSelectedRef.current ? true : someSelectedRef.current ? 'mixed' : false, onChange: (_, data) => handleSelectAllRef.current(!!data.checked), "aria-label": "Select all rows" }) })),
|
|
193
|
-
renderCell: (item) => {
|
|
194
|
-
const rowId = getRowId(item);
|
|
195
|
-
const rowIndex = rowIndexByRowIdRef.current.get(rowId) ?? -1;
|
|
196
|
-
const isChecked = selectedRowIdsRef.current.has(rowId);
|
|
197
|
-
const ac = activeCellRef.current;
|
|
198
|
-
const isActive = ac?.rowIndex === rowIndex && ac?.columnIndex === 0;
|
|
199
|
-
return (_jsx("div", { className: `${styles.selectionCell} ${isActive ? styles.activeCellContent : ''}`, "data-row-index": rowIndex, "data-col-index": 0, onClick: (e) => {
|
|
200
|
-
e.stopPropagation();
|
|
201
|
-
setActiveCellRef.current({ rowIndex, columnIndex: 0 });
|
|
202
|
-
}, children: _jsx(Checkbox, { checked: isChecked, onChange: (e, data) => {
|
|
203
|
-
handleRowCheckboxChangeRef.current(rowId, !!data.checked, rowIndex, e.nativeEvent.shiftKey);
|
|
204
|
-
}, "aria-label": `Select row ${rowIndex + 1}` }) }));
|
|
205
|
-
},
|
|
206
|
-
});
|
|
207
|
-
const cols = [checkboxCol];
|
|
208
|
-
if (hasRowNumbersCol) {
|
|
209
|
-
const rowNumberCol = createTableColumn({
|
|
210
|
-
columnId: '__row_number__',
|
|
211
|
-
compare: () => 0,
|
|
212
|
-
renderHeaderCell: () => (_jsx("div", { className: styles.rowNumberHeaderCell, children: "#" })),
|
|
213
|
-
renderCell: (item) => {
|
|
214
|
-
const rowId = getRowId(item);
|
|
215
|
-
const rowIndex = rowIndexByRowIdRef.current.get(rowId) ?? -1;
|
|
216
|
-
return (_jsx("div", { className: styles.rowNumberCell, children: rowNumberOffset + rowIndex + 1 }));
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
cols.push(rowNumberCol);
|
|
220
|
-
}
|
|
221
|
-
return [...cols, ...dataCols];
|
|
84
|
+
else if (descriptor.mode === 'editing-popover' && typeof col.cellEditor === 'function') {
|
|
85
|
+
const editorProps = buildPopoverEditorProps(item, col, descriptor, pendingEditorValueRef.current, editCallbacks);
|
|
86
|
+
const CustomEditor = col.cellEditor;
|
|
87
|
+
content = (_jsxs(_Fragment, { children: [_jsx("div", { ref: (el) => { if (el)
|
|
88
|
+
setPopoverAnchorEl(el); }, style: POPOVER_ANCHOR_STYLE, "aria-hidden": true }), _jsx(Popover, { open: !!popoverAnchorElRef.current, onOpenChange: (_, data) => { if (!data.open)
|
|
89
|
+
cancelPopoverEdit(); }, positioning: { target: popoverAnchorElRef.current ?? undefined }, children: _jsx(PopoverSurface, { children: _jsx(CustomEditor, { ...editorProps }) }) })] }));
|
|
222
90
|
}
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const rowIndex = rowIndexByRowIdRef.current.get(rowId) ?? -1;
|
|
231
|
-
return (_jsx("div", { className: styles.rowNumberCell, children: rowNumberOffset + rowIndex + 1 }));
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
return [rowNumberCol, ...dataCols];
|
|
91
|
+
else {
|
|
92
|
+
const displayContent = resolveCellDisplayContent(col, item, descriptor.displayValue);
|
|
93
|
+
const cellStyle = resolveCellStyle(col, item);
|
|
94
|
+
const styledContent = cellStyle ? _jsx("span", { style: cellStyle, children: displayContent }) : displayContent;
|
|
95
|
+
const cellClassNames = `${styles.cellContent}${descriptor.isActive && !descriptor.isInRange ? ` ${styles.activeCellContent}` : ''}${descriptor.isInRange ? ` ${styles.cellInRange}` : ''}${descriptor.isInCutRange ? ` ${styles.cellCut}` : ''}${descriptor.isInCopyRange ? ` ${styles.cellCopied}` : ''}`;
|
|
96
|
+
const interactionProps = getCellInteractionProps(descriptor, col.columnId, interactionHandlers);
|
|
97
|
+
content = (_jsxs("div", { className: cellClassNames, ...interactionProps, style: descriptor.canEditAny ? CURSOR_CELL_STYLE : undefined, children: [styledContent, descriptor.canEditAny && descriptor.isSelectionEndCell && (_jsx("div", { className: styles.fillHandle, onMouseDown: handleFillHandleMouseDown, "aria-label": "Fill handle" }))] }));
|
|
235
98
|
}
|
|
236
|
-
return
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (rowSelection !== 'single')
|
|
242
|
-
return;
|
|
243
|
-
const ids = selectedRowIdsRef.current;
|
|
244
|
-
updateSelection(ids.has(rowId) ? new Set() : new Set([rowId]));
|
|
245
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- selectedRowIdsRef is a stable ref
|
|
246
|
-
}, [rowSelection, updateSelection]);
|
|
247
|
-
// Stable getRowId wrapper for Fluent DataGrid
|
|
248
|
-
const fluentGetRowId = useCallback((item) => String(getRowId(item)), [getRowId]);
|
|
249
|
-
// Double-click to auto-fit column width
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
const root = wrapperRef.current;
|
|
252
|
-
if (!root)
|
|
253
|
-
return;
|
|
254
|
-
const onDblClick = (e) => {
|
|
255
|
-
const target = e.target;
|
|
256
|
-
if (!target)
|
|
257
|
-
return;
|
|
258
|
-
if (!target.closest('.fui-TableResizeHandle'))
|
|
259
|
-
return;
|
|
260
|
-
const headerCell = target.closest('[role="columnheader"]');
|
|
261
|
-
if (!headerCell)
|
|
262
|
-
return;
|
|
263
|
-
const colId = headerCell.querySelector('[data-column-id]')?.getAttribute('data-column-id');
|
|
264
|
-
if (!colId)
|
|
265
|
-
return;
|
|
266
|
-
const label = headerCell.querySelector('[data-header-label]');
|
|
267
|
-
const labelWidth = label ? label.scrollWidth : 0;
|
|
268
|
-
const EXTRA_PX = 44;
|
|
269
|
-
const MAX_PX = 520;
|
|
270
|
-
const colDef = flatColumns.find((c) => c.columnId === colId);
|
|
271
|
-
const minW = colDef?.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
|
|
272
|
-
const desired = Math.min(MAX_PX, Math.max(minW, Math.ceil(labelWidth + EXTRA_PX)));
|
|
273
|
-
setColumnSizingOverrides((prev) => ({
|
|
274
|
-
...prev,
|
|
275
|
-
[colId]: { widthPx: desired },
|
|
276
|
-
}));
|
|
277
|
-
e.preventDefault();
|
|
278
|
-
e.stopPropagation();
|
|
279
|
-
};
|
|
280
|
-
root.addEventListener('dblclick', onDblClick, true);
|
|
281
|
-
return () => root.removeEventListener('dblclick', onDblClick, true);
|
|
282
|
-
}, [flatColumns, setColumnSizingOverrides]);
|
|
283
|
-
// Sync Fluent's internal resize state back to our React state so that
|
|
284
|
-
// re-renders (e.g. on cell click) don't reset column widths.
|
|
285
|
-
const handleColumnResize = useCallback((_e, data) => {
|
|
286
|
-
setColumnSizingOverrides((prev) => ({
|
|
287
|
-
...prev,
|
|
288
|
-
[String(data.columnId)]: { widthPx: data.width },
|
|
289
|
-
}));
|
|
290
|
-
}, [setColumnSizingOverrides]);
|
|
291
|
-
return (_jsxs("div", { style: gridRootStyle, children: [_jsxs("div", { ref: wrapperRef, tabIndex: 0, className: `${styles.tableWrapper} ${rowSelection !== 'none' ? styles.selectableGrid : ''} ${styles[`density-${density}`] || ''}`, role: "region", "aria-label": ariaLabel ?? (ariaLabelledBy ? undefined : 'Data grid'), "aria-labelledby": ariaLabelledBy, "data-empty": showEmptyInGrid ? 'true' : undefined, "data-auto-fit": layoutMode === 'fill' && !allowOverflowX ? 'true' : undefined, "data-column-count": totalColCount, "data-freeze-rows": freezeRows != null && freezeRows >= 1 ? freezeRows : undefined, "data-freeze-cols": freezeCols != null && freezeCols >= 1 ? freezeCols : undefined, "data-overflow-x": allowOverflowX ? 'true' : 'false', "data-container-width": containerWidth, "data-min-table-width": Math.round(minTableWidth), "data-has-selection": rowSelection !== 'none' ? 'true' : undefined, onContextMenu: PREVENT_DEFAULT, style: {
|
|
99
|
+
return (_jsx(CellErrorBoundary, { onError: onCellError, children: content }, `${rowId}-${col.columnId}`));
|
|
100
|
+
},
|
|
101
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- *Ref vars are stable refs from useLatestRef
|
|
102
|
+
[editCallbacks, interactionHandlers, handleFillHandleMouseDown, setPopoverAnchorEl, cancelPopoverEdit, getRowId, onCellError]);
|
|
103
|
+
return (_jsxs("div", { style: GRID_ROOT_STYLE, children: [_jsxs("div", { ref: wrapperRef, tabIndex: 0, onMouseDown: (e) => { lastMouseShiftRef.current = e.shiftKey; }, className: `${styles.tableWrapper} ${rowSelection !== 'none' ? styles.selectableGrid : ''} ${styles[`density-${density}`] || ''}`, role: "region", "aria-label": ariaLabel ?? (ariaLabelledBy ? undefined : 'Data grid'), "aria-labelledby": ariaLabelledBy, "data-empty": showEmptyInGrid ? 'true' : undefined, "data-column-count": totalColCount, "data-freeze-rows": freezeRows != null && freezeRows >= 1 ? freezeRows : undefined, "data-freeze-cols": freezeCols != null && freezeCols >= 1 ? freezeCols : undefined, "data-overflow-x": allowOverflowX ? 'true' : 'false', "data-container-width": containerWidth, "data-min-table-width": Math.round(minTableWidth), "data-has-selection": rowSelection !== 'none' ? 'true' : undefined, onContextMenu: PREVENT_DEFAULT, onKeyDown: handleGridKeyDown, style: {
|
|
292
104
|
['--data-table-column-count']: totalColCount,
|
|
293
|
-
['--data-table-width']: showEmptyInGrid
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
: fitToContent
|
|
305
|
-
? 'max-content'
|
|
306
|
-
: '100%',
|
|
307
|
-
}, onKeyDown: handleGridKeyDown, children: [_jsx("div", { className: styles.tableScrollContent, children: _jsx("div", { className: isLoading && items.length > 0 ? styles.loadingDimmed : undefined, children: _jsxs("div", { className: styles.tableWidthAnchor, ref: tableContainerRef, children: [virtualScrollEnabled && visibleRange.offsetTop > 0 && (_jsx("div", { style: { height: visibleRange.offsetTop }, "aria-hidden": true })), _jsxs(DataGrid, { items: virtualScrollEnabled ? items.slice(visibleRange.startIndex, visibleRange.endIndex + 1) : items, columns: fluentColumns, resizableColumns: true, resizableColumnsOptions: { autoFitColumns: layoutMode === 'fill' && !allowOverflowX }, columnSizingOptions: columnSizingOptions, onColumnResize: handleColumnResize, getRowId: fluentGetRowId, focusMode: "composite", className: styles.dataGrid, children: [_jsxs(DataGridHeader, { className: styles.stickyHeader, children: [hasGroupHeaders && headerRows.slice(0, -1).map((row, rowIdx) => (_jsxs("tr", { className: styles.groupHeaderRow, children: [rowIdx === 0 && hasCheckboxCol && (_jsx("th", { rowSpan: headerRows.length - 1, style: { width: CHECKBOX_COLUMN_WIDTH, minWidth: CHECKBOX_COLUMN_WIDTH } })), rowIdx === 0 && hasRowNumbersCol && (_jsx("th", { rowSpan: headerRows.length - 1, style: { width: ROW_NUMBER_COLUMN_WIDTH, minWidth: ROW_NUMBER_COLUMN_WIDTH } })), row.map((cell, cellIdx) => {
|
|
308
|
-
if (cell.isGroup) {
|
|
309
|
-
return (_jsx("th", { colSpan: cell.colSpan, className: styles.groupHeaderCell, scope: "colgroup", children: cell.label }, cellIdx));
|
|
310
|
-
}
|
|
311
|
-
return (_jsx("th", { rowSpan: headerRows.length - rowIdx, className: styles.leafHeaderCellSpan, scope: "col", children: cell.columnDef?.name }, cellIdx));
|
|
312
|
-
})] }, `group-${rowIdx}`))), _jsx(DataGridRow, { children: ({ renderHeaderCell, columnId }) => {
|
|
313
|
-
const isSorted = props.sortBy === String(columnId);
|
|
105
|
+
['--data-table-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'fit-content' : fitToContent ? 'fit-content' : '100%',
|
|
106
|
+
['--data-table-min-width']: showEmptyInGrid ? '100%' : allowOverflowX ? 'max-content' : fitToContent ? 'max-content' : '100%',
|
|
107
|
+
['--data-table-total-min-width']: `${minTableWidth}px`,
|
|
108
|
+
}, children: [_jsx("div", { className: styles.tableScrollContent, children: _jsx("div", { className: isLoading && items.length > 0 ? styles.loadingDimmed : undefined, children: _jsxs("div", { className: styles.tableWidthAnchor, ref: tableContainerRef, children: [_jsxs(Table, { role: "grid", className: styles.dataTable, children: [_jsx(TableHeader, { className: styles.stickyHeader, children: headerRows.map((row, rowIdx) => (_jsxs(TableRow, { children: [rowIdx === headerRows.length - 1 && hasCheckboxCol && (_jsx(TableHeaderCell, { className: styles.selectionHeaderCellWrapper, children: _jsx("div", { className: styles.selectionHeaderCellInner, children: _jsx(Checkbox, { checked: allSelected ? true : someSelected ? 'mixed' : false, onChange: (_, data) => handleSelectAll(!!data.checked), "aria-label": "Select all rows" }) }) }, "__selection__")), rowIdx === 0 && rowIdx < headerRows.length - 1 && hasCheckboxCol && (_jsx("th", { rowSpan: headerRows.length - 1 }, "__selection_placeholder__")), rowIdx === headerRows.length - 1 && hasRowNumbersCol && (_jsx(TableHeaderCell, { className: styles.rowNumberHeaderCellWrapper, children: _jsx("div", { className: styles.rowNumberHeaderCellInner, children: "#" }) }, "__row_number__")), rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol && (_jsx("th", { rowSpan: headerRows.length - 1 }, "__row_number_placeholder__")), row.map((cell, cellIdx) => {
|
|
109
|
+
if (cell.isGroup) {
|
|
110
|
+
return (_jsx("th", { colSpan: cell.colSpan, className: styles.groupHeaderCell, scope: "colgroup", children: cell.label }, cellIdx));
|
|
111
|
+
}
|
|
112
|
+
// Leaf cell
|
|
113
|
+
const col = cell.columnDef;
|
|
114
|
+
// Determine aria-sort value for sorted columns
|
|
115
|
+
const isSorted = props.sortBy === col.columnId;
|
|
314
116
|
const ariaSort = isSorted
|
|
315
117
|
? (props.sortDirection === 'asc' ? 'ascending' : 'descending')
|
|
316
118
|
: undefined;
|
|
317
|
-
return (
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
119
|
+
return (_jsxs(TableHeaderCell, { "data-column-id": col.columnId,
|
|
120
|
+
// rowSpan not supported by TableHeaderCell, use native th for grouped headers
|
|
121
|
+
className: columnMeta.hdrClasses[col.columnId] || undefined, style: {
|
|
122
|
+
...columnMeta.hdrStyles[col.columnId],
|
|
123
|
+
...(columnReorder ? { cursor: isReorderDragging ? 'grabbing' : 'grab' } : undefined),
|
|
124
|
+
}, "aria-sort": ariaSort, onMouseDown: columnReorder ? (e) => handleHeaderMouseDown(col.columnId, e) : undefined, children: [_jsxs("div", { className: styles.headerCellContent, children: [_jsx(ColumnHeaderFilter, { ...getHeaderFilterConfig(col, headerFilterInput) }), _jsx("button", { className: styles.headerMenuTrigger, onClick: (e) => {
|
|
125
|
+
e.stopPropagation();
|
|
126
|
+
headerMenu.open(col.columnId, e.currentTarget);
|
|
127
|
+
}, "aria-label": "Column options", title: "Column options", children: "\u22EE" })] }), _jsx("div", { className: styles.resizeHandle, onMouseDown: (e) => {
|
|
128
|
+
// Clear cell selection/focus before resize so green outlines
|
|
129
|
+
// and blue :focus-visible rings don't persist during drag.
|
|
130
|
+
setActiveCell(null);
|
|
131
|
+
interaction.setSelectionRange(null);
|
|
132
|
+
// Move DOM focus to wrapper so no cell keeps :focus-visible
|
|
133
|
+
wrapperRef.current?.focus({ preventScroll: true });
|
|
134
|
+
handleResizeStart(e, col);
|
|
135
|
+
}, "aria-label": `Resize ${col.name}` })] }, col.columnId));
|
|
136
|
+
})] }, rowIdx))) }), !showEmptyInGrid && (_jsxs(TableBody, { children: [virtualScrollEnabled && visibleRange.offsetTop > 0 && (_jsx("tr", { style: { height: visibleRange.offsetTop }, "aria-hidden": true })), (virtualScrollEnabled
|
|
137
|
+
? items.slice(visibleRange.startIndex, visibleRange.endIndex + 1).map((item, i) => {
|
|
138
|
+
const rowIndex = visibleRange.startIndex + i;
|
|
139
|
+
const rowIdStr = getRowId(item);
|
|
140
|
+
return (_jsx(GridRow, { item: item, rowIndex: rowIndex, rowId: rowIdStr, isSelected: selectedRowIds.has(rowIdStr), visibleCols: visibleCols, columnMeta: columnMeta, renderCellContent: renderCellContent, handleSingleRowClick: handleSingleRowClick, handleRowCheckboxChange: handleRowCheckboxChange, lastMouseShiftRef: lastMouseShiftRef, hasCheckboxCol: hasCheckboxCol, hasRowNumbersCol: hasRowNumbersCol, rowNumberOffset: rowNumberOffset, selectionRange: selectionRange, activeCell: interaction.activeCell, cutRange: cutRange, copyRange: copyRange, isDragging: isDragging, editingRowId: editingCell?.rowId ?? null }, rowIdStr));
|
|
141
|
+
})
|
|
142
|
+
: items.map((item, rowIndex) => {
|
|
143
|
+
const rowIdStr = getRowId(item);
|
|
144
|
+
return (_jsx(GridRow, { item: item, rowIndex: rowIndex, rowId: rowIdStr, isSelected: selectedRowIds.has(rowIdStr), visibleCols: visibleCols, columnMeta: columnMeta, renderCellContent: renderCellContent, handleSingleRowClick: handleSingleRowClick, handleRowCheckboxChange: handleRowCheckboxChange, lastMouseShiftRef: lastMouseShiftRef, hasCheckboxCol: hasCheckboxCol, hasRowNumbersCol: hasRowNumbersCol, rowNumberOffset: rowNumberOffset, selectionRange: selectionRange, activeCell: interaction.activeCell, cutRange: cutRange, copyRange: copyRange, isDragging: isDragging, editingRowId: editingCell?.rowId ?? null }, rowIdStr));
|
|
145
|
+
})), virtualScrollEnabled && visibleRange.offsetBottom > 0 && (_jsx("tr", { style: { height: visibleRange.offsetBottom }, "aria-hidden": true }))] }))] }), isReorderDragging && dropIndicatorX != null && (_jsx(DropIndicator, { dropIndicatorX: dropIndicatorX, wrapperLeft: wrapperRef.current?.getBoundingClientRect().left ?? 0 })), _jsx(MarchingAntsOverlay, { containerRef: tableContainerRef, selectionRange: selectionRange, copyRange: copyRange, cutRange: cutRange, colOffset: colOffset, items: items, visibleColumns: visibleColumns, columnSizingOverrides: columnSizingOverrides, columnOrder: columnOrder }), showEmptyInGrid && emptyState && (_jsx(EmptyState, { emptyState: emptyState }))] }) }) }), menuPosition &&
|
|
146
|
+
createPortal(_jsx(GridContextMenu, { x: menuPosition.x, y: menuPosition.y, hasSelection: hasCellSelection, canUndo: canUndo, canRedo: canRedo, onUndo: onUndo ?? NOOP, onRedo: onRedo ?? NOOP, onCopy: handleCopy, onCut: handleCut, onPaste: handlePasteVoid, onSelectAll: o.interaction.handleSelectAllCells, onClose: closeContextMenu }), wrapperRef.current?.closest('.fui-FluentProvider') ?? document.body), _jsx(ColumnHeaderMenu, { isOpen: headerMenu.isOpen, anchorElement: headerMenu.anchorElement, onClose: headerMenu.close, onPinLeft: headerMenu.handlePinLeft, onPinRight: headerMenu.handlePinRight, onUnpin: headerMenu.handleUnpin, onSortAsc: headerMenu.handleSortAsc, onSortDesc: headerMenu.handleSortDesc, onClearSort: headerMenu.handleClearSort, onAutosizeThis: headerMenu.handleAutosizeThis, onAutosizeAll: headerMenu.handleAutosizeAll, canPinLeft: headerMenu.canPinLeft, canPinRight: headerMenu.canPinRight, canUnpin: headerMenu.canUnpin, currentSort: headerMenu.currentSort, isSortable: headerMenu.isSortable, isResizable: headerMenu.isResizable })] }), statusBarConfig && (_jsx(StatusBar, { totalCount: statusBarConfig.totalCount, filteredCount: statusBarConfig.filteredCount, selectedCount: statusBarConfig.selectedCount ?? selectedRowIds.size, selectedCellCount: selectionRange ? (Math.abs(selectionRange.endRow - selectionRange.startRow) + 1) * (Math.abs(selectionRange.endCol - selectionRange.startCol) + 1) : undefined, aggregation: statusBarConfig.aggregation, suppressRowCount: statusBarConfig.suppressRowCount })), isLoading && (_jsx(LoadingOverlay, { message: loadingMessage }))] }));
|
|
324
147
|
}
|
|
325
148
|
export const DataGridTable = React.memo(DataGridTableInner);
|