@alaarab/ogrid-fluent 1.8.0 → 1.8.2
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.
|
@@ -7,7 +7,7 @@ import { ColumnHeaderFilter } from '../ColumnHeaderFilter';
|
|
|
7
7
|
import { InlineCellEditor } from './InlineCellEditor';
|
|
8
8
|
import { StatusBar } from './StatusBar';
|
|
9
9
|
import { GridContextMenu } from './GridContextMenu';
|
|
10
|
-
import { useDataGridState, getHeaderFilterConfig, getCellRenderDescriptor, buildHeaderRows, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from '@alaarab/ogrid-core';
|
|
10
|
+
import { useDataGridState, getHeaderFilterConfig, getCellRenderDescriptor, buildHeaderRows, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, isRowInRange, } from '@alaarab/ogrid-core';
|
|
11
11
|
import styles from './DataGridTable.module.css';
|
|
12
12
|
// Module-scope stable constants (avoid per-render allocations)
|
|
13
13
|
const gridRootStyle = {
|
|
@@ -23,6 +23,66 @@ const BOOLEAN_STYLE = { justifyContent: 'center', textAlign: 'center' };
|
|
|
23
23
|
const EDITABLE_NUMERIC_STYLE = { cursor: 'cell', justifyContent: 'flex-end', textAlign: 'right' };
|
|
24
24
|
const EDITABLE_BOOLEAN_STYLE = { cursor: 'cell', justifyContent: 'center', textAlign: 'center' };
|
|
25
25
|
const PREVENT_DEFAULT = (e) => { e.preventDefault(); };
|
|
26
|
+
function GridRowInner(props) {
|
|
27
|
+
const { item, rowId, rowIndex, isSelected, cellClassMap, handleSingleRowClick, activeCell } = props;
|
|
28
|
+
const rowClassName = [
|
|
29
|
+
isSelected ? styles.selectedRow : '',
|
|
30
|
+
activeCell !== null && rowIndex === activeCell.rowIndex ? styles.activeRow : '',
|
|
31
|
+
].filter(Boolean).join(' ') || undefined;
|
|
32
|
+
return (
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
_jsx(DataGridRow, { className: rowClassName, onClick: () => handleSingleRowClick(rowId), children: ({ renderCell, columnId }) => (_jsx(DataGridCell, { className: cellClassMap[String(columnId)] || undefined, children: renderCell(item) })) }));
|
|
35
|
+
}
|
|
36
|
+
function areGridRowPropsEqual(prev, next) {
|
|
37
|
+
// Data / structure changes — always re-render
|
|
38
|
+
if (prev.item !== next.item)
|
|
39
|
+
return false;
|
|
40
|
+
if (prev.isSelected !== next.isSelected)
|
|
41
|
+
return false;
|
|
42
|
+
if (prev.cellClassMap !== next.cellClassMap)
|
|
43
|
+
return false;
|
|
44
|
+
const ri = prev.rowIndex;
|
|
45
|
+
// Editing cell in this row?
|
|
46
|
+
if (prev.editingRowId !== next.editingRowId) {
|
|
47
|
+
if (prev.editingRowId === prev.rowId || next.editingRowId === next.rowId)
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// Active cell in this row?
|
|
51
|
+
const prevActive = prev.activeCell?.rowIndex === ri;
|
|
52
|
+
const nextActive = next.activeCell?.rowIndex === ri;
|
|
53
|
+
if (prevActive !== nextActive)
|
|
54
|
+
return false;
|
|
55
|
+
if (prevActive && nextActive && prev.activeCell.columnIndex !== next.activeCell.columnIndex)
|
|
56
|
+
return false;
|
|
57
|
+
// Selection range touches this row?
|
|
58
|
+
const prevInSel = isRowInRange(prev.selectionRange, ri);
|
|
59
|
+
const nextInSel = isRowInRange(next.selectionRange, ri);
|
|
60
|
+
if (prevInSel !== nextInSel)
|
|
61
|
+
return false;
|
|
62
|
+
if (prevInSel && nextInSel) {
|
|
63
|
+
if (prev.selectionRange.startCol !== next.selectionRange.startCol ||
|
|
64
|
+
prev.selectionRange.endCol !== next.selectionRange.endCol)
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// Fill handle (selection end row) + isDragging
|
|
68
|
+
const prevIsEnd = prev.selectionRange?.endRow === ri;
|
|
69
|
+
const nextIsEnd = next.selectionRange?.endRow === ri;
|
|
70
|
+
if (prevIsEnd !== nextIsEnd)
|
|
71
|
+
return false;
|
|
72
|
+
if ((prevIsEnd || nextIsEnd) && prev.isDragging !== next.isDragging)
|
|
73
|
+
return false;
|
|
74
|
+
// Cut/copy ranges touch this row?
|
|
75
|
+
if (prev.cutRange !== next.cutRange) {
|
|
76
|
+
if (isRowInRange(prev.cutRange, ri) || isRowInRange(next.cutRange, ri))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (prev.copyRange !== next.copyRange) {
|
|
80
|
+
if (isRowInRange(prev.copyRange, ri) || isRowInRange(next.copyRange, ri))
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const GridRow = React.memo(GridRowInner, areGridRowPropsEqual);
|
|
26
86
|
function DataGridTableInner(props) {
|
|
27
87
|
const wrapperRef = useRef(null);
|
|
28
88
|
const tableContainerRef = useRef(null);
|
|
@@ -259,11 +319,7 @@ function DataGridTableInner(props) {
|
|
|
259
319
|
return (_jsx("th", { rowSpan: headerRows.length - rowIdx, className: styles.leafHeaderCellSpan, scope: "col", children: cell.columnDef?.name }, cellIdx));
|
|
260
320
|
})] }, `group-${rowIdx}`))), _jsx(DataGridRow, { children: ({ renderHeaderCell, columnId }) => (_jsx(DataGridHeaderCell, { className: headerClassMap[String(columnId)] || undefined, children: renderHeaderCell() })) })] }), _jsx(DataGridBody, { children: ({ item }) => {
|
|
261
321
|
const rowId = getRowId(item);
|
|
262
|
-
|
|
263
|
-
const ac = activeCellRef.current;
|
|
264
|
-
return (_jsx(DataGridRow, { className: `${isSelected ? styles.selectedRow : ''} ${ac !== null && (rowIndexByRowId.get(rowId) ?? -1) === ac.rowIndex
|
|
265
|
-
? styles.activeRow
|
|
266
|
-
: ''}`, onClick: () => handleSingleRowClick(rowId), children: ({ renderCell, columnId }) => (_jsx(DataGridCell, { className: cellClassMap[String(columnId)] || undefined, children: renderCell(item) })) }, rowId));
|
|
322
|
+
return (_jsx(GridRow, { item: item, rowId: rowId, rowIndex: rowIndexByRowId.get(rowId) ?? -1, isSelected: selectedRowIds.has(rowId), cellClassMap: cellClassMap, handleSingleRowClick: handleSingleRowClick, selectionRange: selectionRange, activeCell: activeCell, cutRange: cutRange, copyRange: copyRange, isDragging: isDragging, editingRowId: editingCell?.rowId ?? null }, rowId));
|
|
267
323
|
} })] }), _jsx(MarchingAntsOverlay, { containerRef: tableContainerRef, selectionRange: selectionRange, copyRange: copyRange, cutRange: cutRange, colOffset: colOffset }), showEmptyInGrid && emptyState && (_jsx("div", { className: styles.emptyStateInGrid, children: _jsx("div", { className: styles.emptyStateInGridMessageSticky, children: emptyState.render ? (emptyState.render()) : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.emptyStateInGridIcon, "aria-hidden": true, children: "\uD83D\uDCCB" }), _jsx("div", { className: styles.emptyStateInGridTitle, children: "No results found" }), _jsx("div", { className: styles.emptyStateInGridMessage, children: emptyState.message != null ? (emptyState.message) : emptyState.hasActiveFilters ? (_jsxs(_Fragment, { children: ["No items match your current filters. Try adjusting your search or", ' ', _jsx("button", { type: "button", className: styles.emptyStateInGridLink, onClick: emptyState.onClearAll, children: "clear all filters" }), ' ', "to see all items."] })) : ('There are no items available at this time.') })] })) }) }))] }) }) }), menuPosition &&
|
|
268
324
|
createPortal(_jsx(GridContextMenu, { x: menuPosition.x, y: menuPosition.y, hasSelection: hasCellSelection, canUndo: canUndo, canRedo: canRedo, onUndo: onUndo ?? (() => { }), onRedo: onRedo ?? (() => { }), onCopy: handleCopy, onCut: handleCut, onPaste: () => void handlePaste(), onSelectAll: handleSelectAllCells, onClose: closeContextMenu }), document.body)] }), 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 && items.length > 0 && (_jsx("div", { className: styles.loadingOverlay, "aria-live": "polite", children: _jsxs("div", { className: styles.loadingOverlayContent, children: [_jsx(Spinner, { size: "small" }), _jsx("span", { className: styles.loadingOverlayText, children: loadingMessage })] }) }))] }));
|
|
269
325
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-fluent",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"description": "OGrid Fluent UI implementation – DataGrid-powered data table with sorting, filtering, pagination, column chooser, and CSV export.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=18"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@alaarab/ogrid-core": "^1.8.
|
|
43
|
+
"@alaarab/ogrid-core": "^1.8.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@fluentui/react-components": "^9.0.0",
|