@alaarab/ogrid-react-material 2.0.23 → 2.1.1
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.
|
@@ -4,10 +4,10 @@ import { Button, Popover, Checkbox, Box, Typography, FormControlLabel, } from '@
|
|
|
4
4
|
import { ViewColumn as ViewColumnIcon, ExpandMore as ExpandMoreIcon, ExpandLess as ExpandLessIcon, } from '@mui/icons-material';
|
|
5
5
|
import { useColumnChooserState } from '@alaarab/ogrid-react';
|
|
6
6
|
export const ColumnChooser = (props) => {
|
|
7
|
-
const { columns, visibleColumns, onVisibilityChange, className } = props;
|
|
7
|
+
const { columns, visibleColumns, onVisibilityChange, onSetVisibleColumns, className } = props;
|
|
8
8
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
9
9
|
const buttonRef = useRef(null);
|
|
10
|
-
const { open: isOpen, setOpen, handleClose, handleCheckboxChange: setColumnVisible, handleSelectAll, handleClearAll, visibleCount, totalCount, } = useColumnChooserState({ columns, visibleColumns, onVisibilityChange });
|
|
10
|
+
const { open: isOpen, setOpen, handleClose, handleCheckboxChange: setColumnVisible, handleSelectAll, handleClearAll, visibleCount, totalCount, } = useColumnChooserState({ columns, visibleColumns, onVisibilityChange, onSetVisibleColumns });
|
|
11
11
|
const handleToggle = (e) => {
|
|
12
12
|
if (isOpen) {
|
|
13
13
|
handleClose();
|
|
@@ -40,7 +40,7 @@ export const ColumnChooser = (props) => {
|
|
|
40
40
|
borderBottom: 1,
|
|
41
41
|
borderColor: 'divider',
|
|
42
42
|
bgcolor: 'action.hover',
|
|
43
|
-
}, children: _jsxs(Typography, { variant: "subtitle2", fontWeight: 600, children: ["Select Columns (", visibleCount, " of ", totalCount, ")"] }) }), _jsx(Box, { sx: { maxHeight: 320, overflowY: 'auto', py: 0.5 }, children: columns.map((column) => (_jsx(Box, { sx: { px: 1.5, minHeight: 32, display: 'flex', alignItems: 'center' }, children: _jsx(FormControlLabel, { control: _jsx(Checkbox, { size: "small", checked: visibleColumns.has(column.columnId), onChange: handleCheckboxChange(column.columnId) }), label: _jsx(Typography, { variant: "body2", children: column.name }), sx: { m: 0 } }) }, column.columnId))) }), _jsxs(Box, { sx: {
|
|
43
|
+
}, children: _jsxs(Typography, { variant: "subtitle2", fontWeight: 600, children: ["Select Columns (", visibleCount, " of ", totalCount, ")"] }) }), _jsx(Box, { sx: { maxHeight: 320, overflowY: 'auto', py: 0.5 }, children: columns.map((column) => (_jsx(Box, { sx: { px: 1.5, minHeight: 32, display: 'flex', alignItems: 'center' }, children: _jsx(FormControlLabel, { control: _jsx(Checkbox, { size: "small", checked: visibleColumns.has(column.columnId), onChange: handleCheckboxChange(column.columnId), disabled: column.required === true }), label: _jsx(Typography, { variant: "body2", children: column.name }), sx: { m: 0 } }) }, column.columnId))) }), _jsxs(Box, { sx: {
|
|
44
44
|
display: 'flex',
|
|
45
45
|
justifyContent: 'flex-end',
|
|
46
46
|
gap: 1,
|
|
@@ -11,7 +11,7 @@ import { GridContextMenu } from './GridContextMenu';
|
|
|
11
11
|
import { EmptyState } from './EmptyState';
|
|
12
12
|
import { LoadingOverlay } from './LoadingOverlay';
|
|
13
13
|
import { DropIndicator } from './DropIndicator';
|
|
14
|
-
import { useDataGridTableOrchestration, getHeaderFilterConfig, getCellRenderDescriptor, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, areGridRowPropsEqual, CellErrorBoundary, CHECKBOX_COLUMN_WIDTH, ROW_NUMBER_COLUMN_WIDTH,
|
|
14
|
+
import { useDataGridTableOrchestration, useColumnMeta, getHeaderFilterConfig, getCellRenderDescriptor, MarchingAntsOverlay, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, areGridRowPropsEqual, CellErrorBoundary, CHECKBOX_COLUMN_WIDTH, ROW_NUMBER_COLUMN_WIDTH, PREVENT_DEFAULT, NOOP, STOP_PROPAGATION, } from '@alaarab/ogrid-react';
|
|
15
15
|
// ── Module-scope stable styles (avoid per-render Emotion resolutions) ──
|
|
16
16
|
const gridRootSx = { position: 'relative', flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' };
|
|
17
17
|
// Editing cell wrapper (plain div, not MUI)
|
|
@@ -229,11 +229,22 @@ function DataGridTableInner(props) {
|
|
|
229
229
|
// Density-aware cell padding
|
|
230
230
|
const densityPadding = useMemo(() => getDensityPadding(density), [density]);
|
|
231
231
|
const headerCellSx = useMemo(() => ({ px: densityPadding.px, py: densityPadding.py }), [densityPadding]);
|
|
232
|
-
//
|
|
232
|
+
// Shared width/minWidth computation (deduped with Radix/Fluent via useColumnMeta)
|
|
233
|
+
const columnMeta = useColumnMeta({
|
|
234
|
+
visibleCols,
|
|
235
|
+
getColumnWidth,
|
|
236
|
+
columnSizingOverrides,
|
|
237
|
+
measuredColumnWidths,
|
|
238
|
+
pinnedColumns: pinning.pinnedColumns,
|
|
239
|
+
leftOffsets: pinning.leftOffsets,
|
|
240
|
+
rightOffsets: pinning.rightOffsets,
|
|
241
|
+
pinnedColLeftClass: '',
|
|
242
|
+
pinnedColRightClass: '',
|
|
243
|
+
});
|
|
244
|
+
// Pre-compute per-column layout (tdSx + widths from columnMeta) so GridRow doesn't recalculate per-cell
|
|
233
245
|
const columnLayouts = useMemo(() => visibleCols.map((col) => {
|
|
234
246
|
const isPinnedLeft = pinning.pinnedColumns[col.columnId] === 'left';
|
|
235
247
|
const isPinnedRight = pinning.pinnedColumns[col.columnId] === 'right';
|
|
236
|
-
const columnWidth = getColumnWidth(col);
|
|
237
248
|
const baseTdSx = isPinnedLeft ? CELL_TD_PINNED_LEFT_SX : isPinnedRight ? CELL_TD_PINNED_RIGHT_SX : CELL_TD_BASE_SX;
|
|
238
249
|
// Override sticky offset for pinned columns (supports multiple pinned columns)
|
|
239
250
|
const tdSx = isPinnedLeft && pinning.leftOffsets[col.columnId] != null
|
|
@@ -241,14 +252,15 @@ function DataGridTableInner(props) {
|
|
|
241
252
|
: isPinnedRight && pinning.rightOffsets[col.columnId] != null
|
|
242
253
|
? { ...baseTdSx, right: pinning.rightOffsets[col.columnId] }
|
|
243
254
|
: baseTdSx;
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
const cellStyle = columnMeta.cellStyles[col.columnId];
|
|
256
|
+
return {
|
|
257
|
+
col,
|
|
258
|
+
tdSx,
|
|
259
|
+
minWidth: cellStyle?.minWidth ?? 0,
|
|
260
|
+
width: cellStyle?.width ?? getColumnWidth(col),
|
|
261
|
+
maxWidth: cellStyle?.maxWidth ?? getColumnWidth(col),
|
|
262
|
+
};
|
|
263
|
+
}), [visibleCols, columnMeta, pinning.pinnedColumns, pinning.leftOffsets, pinning.rightOffsets, getColumnWidth]);
|
|
252
264
|
// Wrapper sx (depends on dynamic values — memoize to avoid recreation)
|
|
253
265
|
const wrapperSx = useMemo(() => ({
|
|
254
266
|
position: 'relative',
|
|
@@ -284,14 +296,10 @@ function DataGridTableInner(props) {
|
|
|
284
296
|
// Select pre-computed sx variant (module-scope = no per-cell allocation)
|
|
285
297
|
const cellSx = getCellSx(col.type, descriptor.canEditAny, descriptor.isActive && !descriptor.isInRange, descriptor.isInRange, descriptor.isInCutRange);
|
|
286
298
|
const interactionProps = getCellInteractionProps(descriptor, col.columnId, interactionHandlers);
|
|
287
|
-
cellContent = (_jsxs(Box, { component: "div", ...interactionProps,
|
|
288
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
289
|
-
sx: Array.isArray(cellSx) ? [...cellSx, densityPadding] : { ...cellSx, ...densityPadding }, children: [styledContent, descriptor.canEditAny && descriptor.isSelectionEndCell && (_jsx(Box, { component: "div", onMouseDown: handleFillHandleMouseDown, "aria-label": "Fill handle", sx: FILL_HANDLE_SX }))] }));
|
|
299
|
+
cellContent = (_jsxs(Box, { component: "div", ...interactionProps, sx: Array.isArray(cellSx) ? [...cellSx, densityPadding] : { ...cellSx, ...densityPadding }, children: [styledContent, descriptor.canEditAny && descriptor.isSelectionEndCell && (_jsx(Box, { component: "div", onMouseDown: handleFillHandleMouseDown, "aria-label": "Fill handle", sx: FILL_HANDLE_SX }))] }));
|
|
290
300
|
}
|
|
291
301
|
return (_jsx(CellErrorBoundary, { onError: onCellError, children: cellContent }, `${rowId}-${col.columnId}`));
|
|
292
|
-
},
|
|
293
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- *Ref vars are stable refs from useLatestRef
|
|
294
|
-
[editCallbacks, interactionHandlers, handleFillHandleMouseDown, setPopoverAnchorEl, cancelPopoverEdit, getRowId, onCellError]);
|
|
302
|
+
}, [editCallbacks, interactionHandlers, handleFillHandleMouseDown, setPopoverAnchorEl, cancelPopoverEdit, getRowId, onCellError, cellDescriptorInputRef, densityPadding, pendingEditorValueRef, popoverAnchorElRef]);
|
|
295
303
|
return (_jsxs(Box, { sx: gridRootSx, children: [_jsxs(Box, { ref: wrapperRef, tabIndex: 0, role: "region", "aria-label": ariaLabel ?? (ariaLabelledBy ? undefined : 'Data grid'), "aria-labelledby": ariaLabelledBy, onMouseDown: (e) => { lastMouseShiftRef.current = e.shiftKey; }, onKeyDown: handleGridKeyDown, onContextMenu: PREVENT_DEFAULT, "data-overflow-x": allowOverflowX ? 'true' : 'false', "data-density": density, sx: wrapperSx, children: [_jsx(Box, { sx: WRAPPER_SCROLL_SX, children: _jsx(TableContainer, { sx: { minWidth: allowOverflowX ? minTableWidth : undefined }, children: _jsxs(Box, { ref: tableContainerRef, sx: isLoading && items.length > 0 ? TABLE_WRAPPER_LOADING_SX : TABLE_WRAPPER_SX, children: [_jsxs(Table, { size: "small", sx: { minWidth: minTableWidth, borderCollapse: 'separate', borderSpacing: 0 }, children: [_jsx(TableHead, { sx: STICKY_HEADER_SX, children: headerRows.map((row, rowIdx) => (_jsxs(TableRow, { sx: HEADER_ROW_SX, children: [rowIdx === headerRows.length - 1 && hasCheckboxCol && (_jsx(TableCell, { ...{ padding: "checkbox", rowSpan: headerRows.length > 1 ? 1 : undefined, sx: CHECKBOX_CELL_SX }, children: _jsx(Checkbox, { checked: allSelected, indeterminate: someSelected, onChange: (_, c) => handleSelectAll(!!c), size: "small", "aria-label": "Select all rows" }) })), rowIdx === 0 && rowIdx < headerRows.length - 1 && hasCheckboxCol && (_jsx(TableCell, { ...{ rowSpan: headerRows.length - 1, sx: CHECKBOX_PLACEHOLDER_SX } })), rowIdx === headerRows.length - 1 && hasRowNumbersCol && (_jsx(TableCell, { ...{
|
|
296
304
|
component: "th",
|
|
297
305
|
scope: "col",
|
|
@@ -328,10 +336,11 @@ function DataGridTableInner(props) {
|
|
|
328
336
|
}, children: cell.label }, cellIdx));
|
|
329
337
|
}
|
|
330
338
|
// Leaf cell
|
|
339
|
+
if (!cell.columnDef)
|
|
340
|
+
return null;
|
|
331
341
|
const col = cell.columnDef;
|
|
332
342
|
const isPinnedLeft = pinning.pinnedColumns[col.columnId] === 'left';
|
|
333
343
|
const isPinnedRight = pinning.pinnedColumns[col.columnId] === 'right';
|
|
334
|
-
const columnWidth = getColumnWidth(col);
|
|
335
344
|
const baseHeaderSx = isPinnedLeft ? HEADER_PINNED_LEFT_SX : isPinnedRight ? HEADER_PINNED_RIGHT_SX : HEADER_BASE_SX;
|
|
336
345
|
// Override sticky offset for pinned columns (supports multiple pinned columns)
|
|
337
346
|
const headerSx = isPinnedLeft && pinning.leftOffsets[col.columnId] != null
|
|
@@ -339,6 +348,8 @@ function DataGridTableInner(props) {
|
|
|
339
348
|
: isPinnedRight && pinning.rightOffsets[col.columnId] != null
|
|
340
349
|
? { ...baseHeaderSx, right: pinning.rightOffsets[col.columnId] }
|
|
341
350
|
: baseHeaderSx;
|
|
351
|
+
// Width/minWidth from shared useColumnMeta (avoids duplicate calculation)
|
|
352
|
+
const hdrStyle = columnMeta.hdrStyles[col.columnId];
|
|
342
353
|
// Determine aria-sort value for sorted columns
|
|
343
354
|
const isSorted = props.sortBy === col.columnId;
|
|
344
355
|
const ariaSort = isSorted
|
|
@@ -353,9 +364,9 @@ function DataGridTableInner(props) {
|
|
|
353
364
|
sx: {
|
|
354
365
|
...headerSx,
|
|
355
366
|
...headerCellSx,
|
|
356
|
-
minWidth:
|
|
357
|
-
width:
|
|
358
|
-
maxWidth:
|
|
367
|
+
minWidth: hdrStyle?.minWidth,
|
|
368
|
+
width: hdrStyle?.width,
|
|
369
|
+
maxWidth: hdrStyle?.maxWidth,
|
|
359
370
|
...(columnReorder ? { cursor: isReorderDragging ? 'grabbing' : 'grab' } : {}),
|
|
360
371
|
'&:focus-visible': {
|
|
361
372
|
outline: '2px solid',
|
package/dist/esm/OGrid/OGrid.js
CHANGED
|
@@ -22,7 +22,6 @@ const OGridInner = forwardRef(function OGridInner(props, ref) {
|
|
|
22
22
|
}), [theme]);
|
|
23
23
|
return (_jsx(OGridLayout, { containerComponent: Box, containerProps: { sx: containerSx }, className: layout.className, sideBar: layout.sideBarProps, toolbar: layout.toolbar, toolbarBelow: layout.toolbarBelow, toolbarEnd: columnChooser.placement === 'toolbar' ? (_jsx(ColumnChooser, { columns: columnChooser.columns, visibleColumns: columnChooser.visibleColumns, onVisibilityChange: columnChooser.onVisibilityChange })) : undefined, pagination: _jsx(PaginationControls, { currentPage: pagination.page, pageSize: pagination.pageSize, totalCount: pagination.displayTotalCount, onPageChange: pagination.setPage, onPageSizeChange: (size) => {
|
|
24
24
|
pagination.setPageSize(size);
|
|
25
|
-
pagination.setPage(1);
|
|
26
25
|
}, pageSizeOptions: pagination.pageSizeOptions, entityLabelPlural: pagination.entityLabelPlural }), children: _jsx(DataGridTable, { ...dataGridProps }) }));
|
|
27
26
|
});
|
|
28
27
|
OGridInner.displayName = 'OGrid';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-react-material",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "OGrid React Material implementation – MUI Table–based data grid with sorting, filtering, pagination, column chooser, spreadsheet selection, and CSV export.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"node": ">=18"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@alaarab/ogrid-react": "2.
|
|
42
|
+
"@alaarab/ogrid-react": "2.1.1"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@emotion/react": "^11.0.0",
|
|
@@ -68,5 +68,12 @@
|
|
|
68
68
|
},
|
|
69
69
|
"publishConfig": {
|
|
70
70
|
"access": "public"
|
|
71
|
-
}
|
|
71
|
+
},
|
|
72
|
+
"repository": {
|
|
73
|
+
"type": "git",
|
|
74
|
+
"url": "https://github.com/alaarab/ogrid.git",
|
|
75
|
+
"directory": "packages/react-material"
|
|
76
|
+
},
|
|
77
|
+
"homepage": "https://ogrid.dev",
|
|
78
|
+
"bugs": "https://github.com/alaarab/ogrid/issues"
|
|
72
79
|
}
|