@alaarab/ogrid-react-material 2.1.14 → 2.2.0

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.
Files changed (2) hide show
  1. package/dist/esm/index.js +159 -84
  2. package/package.json +2 -2
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import * as React3 from 'react';
1
+ import * as React4 from 'react';
2
2
  import { useMemo, useCallback, useState, useRef, useEffect } from 'react';
3
3
  import { Box, Tooltip, Typography, IconButton, Popover, Button, Select, MenuItem, useTheme, Checkbox, Table, TableHead, TableRow, TableCell, FormControlLabel, Avatar, TextField, InputAdornment, CircularProgress, Menu, Divider } from '@mui/material';
4
- import { useColumnHeaderFilterState, getColumnHeaderFilterStateParams, renderFilterContent, areGridRowPropsEqual, usePaginationControls, createOGrid, DateFilterContent, CHECKBOX_COLUMN_WIDTH, STOP_PROPAGATION, ROW_NUMBER_COLUMN_WIDTH, useDataGridTableOrchestration, useColumnMeta, getCellRenderDescriptor, buildInlineEditorProps, buildPopoverEditorProps, resolveCellDisplayContent, resolveCellStyle, getCellInteractionProps, CellErrorBoundary, PREVENT_DEFAULT, getHeaderFilterConfig, MarchingAntsOverlay, NOOP, useColumnChooserState, useListVirtualizer, BaseInlineCellEditor, getContextMenuHandlers, GRID_CONTEXT_MENU_ITEMS, formatShortcut, getColumnHeaderMenuItems, getStatusBarParts } from '@alaarab/ogrid-react';
4
+ import { useColumnHeaderFilterState, getColumnHeaderFilterStateParams, renderFilterContent, areGridRowPropsEqual, usePaginationControls, createOGrid, DateFilterContent, CHECKBOX_COLUMN_WIDTH, STOP_PROPAGATION, ROW_NUMBER_COLUMN_WIDTH, useDataGridTableOrchestration, useColumnMeta, getCellRenderDescriptor, buildInlineEditorProps, buildPopoverEditorProps, resolveCellDisplayContent, resolveCellStyle, getCellInteractionProps, CellErrorBoundary, PREVENT_DEFAULT, getHeaderFilterConfig, MarchingAntsOverlay, NOOP, useColumnChooserState, useListVirtualizer, BaseInlineCellEditor, partitionColumnsForVirtualization, getContextMenuHandlers, GRID_CONTEXT_MENU_ITEMS, formatShortcut, getColumnHeaderMenuItems, getStatusBarParts } from '@alaarab/ogrid-react';
5
5
  export { BaseColumnHeaderMenu, BaseDropIndicator, BaseEmptyState, BaseInlineCellEditor, BaseLoadingOverlay, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, CURSOR_CELL_STYLE, CellErrorBoundary, DEFAULT_MIN_COLUMN_WIDTH, DateFilterContent, EmptyState, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, GRID_ROOT_STYLE, GridContextMenu, MAX_PAGE_BUTTONS, MarchingAntsOverlay, NOOP, OGridLayout, PAGE_SIZE_OPTIONS, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, ROW_NUMBER_COLUMN_WIDTH, STOP_PROPAGATION, SideBar, StatusBar, UndoRedoStack, areGridRowPropsEqual, booleanParser, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps, buildPopoverEditorProps, clampSelectionToBounds, computeAggregations, computeAutoScrollSpeed, computeTabNavigation, createOGrid, currencyParser, dateParser, deriveFilterOptionsFromData, editorInputStyle, editorWrapperStyle, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellInteractionProps, getCellRenderDescriptor, getCellValue, getColumnHeaderFilterStateParams, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getDateFilterContentProps, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getStatusBarParts, isInSelectionRange, isRowInRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, processClientSideData, rangesEqual, renderFilterContent, resolveCellDisplayContent, resolveCellStyle, richSelectDropdownStyle, richSelectNoMatchesStyle, richSelectOptionHighlightedStyle, richSelectOptionStyle, richSelectWrapperStyle, selectChevronStyle, selectDisplayStyle, selectEditorStyle, toUserLike, triggerCsvDownload, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnMeta, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableOrchestration, useDateFilterState, useDebounce, useFillHandle, useFilterOptions, useInlineCellEditorState, useKeyboardNavigation, useLatestRef, useListVirtualizer, useMultiSelectFilterState, useOGrid, usePaginationControls, usePeopleFilterState, useRichSelectState, useRowSelection, useSelectState, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll } from '@alaarab/ogrid-react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import { FilterList, FirstPage, ChevronLeft, ChevronRight, LastPage, ExpandLess, ExpandMore, ViewColumn, Clear, Search } from '@mui/icons-material';
@@ -18,8 +18,10 @@ var STYLES = `
18
18
  .ogrid-mat-td--pinned-left { position: sticky; left: 0; z-index: var(--ogrid-z-pinned, 6); background-color: var(--ogrid-paper-bg, #fff); will-change: transform; border-right: 1px solid var(--ogrid-border, rgba(224,224,224,1)); box-shadow: 2px 0 4px -1px rgba(0,0,0,0.1); }
19
19
  .ogrid-mat-td--pinned-right { position: sticky; right: 0; z-index: var(--ogrid-z-pinned, 6); background-color: var(--ogrid-paper-bg, #fff); will-change: transform; border-left: 1px solid var(--ogrid-border, rgba(224,224,224,1)); box-shadow: -2px 0 4px -1px rgba(0,0,0,0.1); }
20
20
 
21
- .ogrid-mat-cell { width: 100%; height: 100%; display: flex; align-items: center; min-width: 0; box-sizing: border-box; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: none; outline: none; }
21
+ .ogrid-mat-cell { width: 100%; height: 100%; display: flex; align-items: center; min-width: 0; box-sizing: border-box; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: none; outline: none; contain: content; }
22
22
  .ogrid-mat-cell:focus-visible { outline: 2px solid var(--ogrid-primary, #1976d2); outline-offset: -2px; z-index: 3; }
23
+ .ogrid-mat-td--pinned-left .ogrid-mat-cell, .ogrid-mat-td--pinned-right .ogrid-mat-cell { contain: none; }
24
+ table:not([data-virtual-scroll]) .ogrid-mat-tbody tr { content-visibility: auto; }
23
25
 
24
26
  .ogrid-mat-cell--numeric { justify-content: flex-end; text-align: right; }
25
27
  .ogrid-mat-cell--boolean { justify-content: center; text-align: center; }
@@ -275,7 +277,7 @@ var materialRenderers = {
275
277
  }
276
278
  )
277
279
  };
278
- var ColumnHeaderFilter = React3.memo((props) => {
280
+ var ColumnHeaderFilter = React4.memo((props) => {
279
281
  const {
280
282
  columnName,
281
283
  filterType,
@@ -487,8 +489,8 @@ function StatusBar(props) {
487
489
  }
488
490
  function GridContextMenu(props) {
489
491
  const { x, y, hasSelection, canUndo, canRedo, onClose } = props;
490
- const handlers = React3.useMemo(() => getContextMenuHandlers(props), [props]);
491
- const isDisabled = React3.useCallback(
492
+ const handlers = React4.useMemo(() => getContextMenuHandlers(props), [props]);
493
+ const isDisabled = React4.useCallback(
492
494
  (item) => {
493
495
  if (item.disabledWhenNoSelection && !hasSelection) return true;
494
496
  if (item.id === "undo" && !canUndo) return true;
@@ -738,6 +740,7 @@ var COLUMN_OPTIONS_BUTTON_SX = {
738
740
  };
739
741
  var TABLE_WRAPPER_SX = { position: "relative", opacity: 1 };
740
742
  var TABLE_WRAPPER_LOADING_SX = { position: "relative", opacity: 0.6 };
743
+ var SPACER_TD_STYLE = { padding: 0, border: "none" };
741
744
  function GridRowInner(props) {
742
745
  const {
743
746
  item,
@@ -752,7 +755,10 @@ function GridRowInner(props) {
752
755
  hasCheckboxCol,
753
756
  hasRowNumbersCol,
754
757
  rowNumberOffset,
755
- rowHeight
758
+ rowHeight,
759
+ leftSpacerWidth,
760
+ rightSpacerWidth,
761
+ globalColIndexMap
756
762
  } = props;
757
763
  return /* @__PURE__ */ jsxs(
758
764
  "tr",
@@ -795,22 +801,119 @@ function GridRowInner(props) {
795
801
  children: rowNumberOffset + rowIndex + 1
796
802
  }
797
803
  ),
798
- columnLayouts.map((cl, colIdx) => /* @__PURE__ */ jsx(
799
- "td",
800
- {
801
- "data-column-id": cl.col.columnId,
802
- className: cl.tdClassName,
803
- style: { ...cl.tdStyle, minWidth: cl.minWidth, width: cl.width, maxWidth: cl.maxWidth },
804
- children: renderCellContent(item, cl.col, rowIndex, colIdx)
805
- },
806
- cl.col.columnId
807
- ))
804
+ leftSpacerWidth != null && leftSpacerWidth > 0 && /* @__PURE__ */ jsx("td", { style: { ...SPACER_TD_STYLE, width: leftSpacerWidth, minWidth: leftSpacerWidth }, "aria-hidden": true }),
805
+ columnLayouts.map((cl, colIdx) => {
806
+ const globalIdx = globalColIndexMap ? globalColIndexMap[colIdx] : colIdx;
807
+ return /* @__PURE__ */ jsx(
808
+ "td",
809
+ {
810
+ "data-column-id": cl.col.columnId,
811
+ className: cl.tdClassName,
812
+ style: { ...cl.tdStyle, minWidth: cl.minWidth, width: cl.width, maxWidth: cl.maxWidth },
813
+ children: renderCellContent(item, cl.col, rowIndex, globalIdx)
814
+ },
815
+ cl.col.columnId
816
+ );
817
+ }),
818
+ rightSpacerWidth != null && rightSpacerWidth > 0 && /* @__PURE__ */ jsx("td", { style: { ...SPACER_TD_STYLE, width: rightSpacerWidth, minWidth: rightSpacerWidth }, "aria-hidden": true })
808
819
  ]
809
820
  }
810
821
  );
811
822
  }
812
- var GridRow = React3.memo(GridRowInner, areGridRowPropsEqual);
823
+ var GridRow = React4.memo(GridRowInner, areGridRowPropsEqual);
813
824
  injectDataGridStyles();
825
+ function MaterialTableBody(props) {
826
+ const {
827
+ virtualScrollEnabled,
828
+ visibleRange,
829
+ columnRange,
830
+ items,
831
+ getRowId,
832
+ selectedRowIds,
833
+ visibleCols,
834
+ columnLayouts,
835
+ renderCellContent,
836
+ handleSingleRowClick,
837
+ handleRowCheckboxChange,
838
+ lastMouseShiftRef,
839
+ hasCheckboxCol,
840
+ hasRowNumbersCol,
841
+ rowNumberOffset,
842
+ rowHeight,
843
+ selectionRange,
844
+ activeCell,
845
+ cutRange,
846
+ copyRange,
847
+ isDragging,
848
+ editingCell,
849
+ pinnedColumns
850
+ } = props;
851
+ const { rowLayouts, globalColIndexMap, leftSpacerWidth, rightSpacerWidth } = React4.useMemo(() => {
852
+ if (!columnRange) {
853
+ return { rowLayouts: columnLayouts, globalColIndexMap: void 0, leftSpacerWidth: void 0, rightSpacerWidth: void 0 };
854
+ }
855
+ const partition = partitionColumnsForVirtualization(
856
+ visibleCols,
857
+ columnRange,
858
+ pinnedColumns
859
+ );
860
+ const combined = [...partition.pinnedLeft, ...partition.virtualizedUnpinned, ...partition.pinnedRight];
861
+ const layoutMap = new Map(columnLayouts.map((cl) => [cl.col.columnId, cl]));
862
+ const partitionedLayouts = [];
863
+ const idxMap = [];
864
+ for (const col of combined) {
865
+ const layout = layoutMap.get(col.columnId);
866
+ if (layout) {
867
+ partitionedLayouts.push(layout);
868
+ idxMap.push(visibleCols.indexOf(col));
869
+ }
870
+ }
871
+ return {
872
+ rowLayouts: partitionedLayouts,
873
+ globalColIndexMap: idxMap,
874
+ leftSpacerWidth: partition.leftSpacerWidth,
875
+ rightSpacerWidth: partition.rightSpacerWidth
876
+ };
877
+ }, [columnRange, visibleCols, columnLayouts, pinnedColumns]);
878
+ const renderRow = (item, rowIndex) => {
879
+ const rowIdStr = getRowId(item);
880
+ return /* @__PURE__ */ jsx(
881
+ GridRow,
882
+ {
883
+ item,
884
+ rowIndex,
885
+ rowId: rowIdStr,
886
+ isSelected: selectedRowIds.has(rowIdStr),
887
+ columnLayouts: rowLayouts,
888
+ renderCellContent,
889
+ handleSingleRowClick,
890
+ handleRowCheckboxChange,
891
+ lastMouseShiftRef,
892
+ hasCheckboxCol,
893
+ hasRowNumbersCol,
894
+ rowNumberOffset,
895
+ selectionRange,
896
+ activeCell,
897
+ cutRange,
898
+ copyRange,
899
+ isDragging,
900
+ rowHeight,
901
+ editingRowId: editingCell?.rowId ?? null,
902
+ leftSpacerWidth,
903
+ rightSpacerWidth,
904
+ globalColIndexMap
905
+ },
906
+ rowIdStr
907
+ );
908
+ };
909
+ return /* @__PURE__ */ jsxs("tbody", { className: "ogrid-mat-tbody", children: [
910
+ virtualScrollEnabled && visibleRange.offsetTop > 0 && /* @__PURE__ */ jsx("tr", { style: { height: visibleRange.offsetTop }, "aria-hidden": true }),
911
+ virtualScrollEnabled ? items.slice(visibleRange.startIndex, visibleRange.endIndex + 1).map(
912
+ (item, i) => renderRow(item, visibleRange.startIndex + i)
913
+ ) : items.map((item, rowIndex) => renderRow(item, rowIndex)),
914
+ virtualScrollEnabled && visibleRange.offsetBottom > 0 && /* @__PURE__ */ jsx("tr", { style: { height: visibleRange.offsetBottom }, "aria-hidden": true })
915
+ ] });
916
+ }
814
917
  function DataGridTableInner(props) {
815
918
  const o = useDataGridTableOrchestration({ props });
816
919
  const {
@@ -827,6 +930,8 @@ function DataGridTableInner(props) {
827
930
  handleHeaderMouseDown,
828
931
  virtualScrollEnabled,
829
932
  visibleRange,
933
+ columnRange,
934
+ onHorizontalScroll,
830
935
  items,
831
936
  getRowId,
832
937
  emptyState,
@@ -971,8 +1076,8 @@ function DataGridTableInner(props) {
971
1076
  if (col.type === "numeric") cls += " ogrid-mat-cell--numeric";
972
1077
  else if (col.type === "boolean") cls += " ogrid-mat-cell--boolean";
973
1078
  if (descriptor.canEditAny) cls += " ogrid-mat-cell--editable";
974
- if (descriptor.isActive && !descriptor.isInRange) cls += " ogrid-mat-cell--active";
975
- if (descriptor.isInRange) cls += " ogrid-mat-cell--range";
1079
+ if (descriptor.isActive) cls += " ogrid-mat-cell--active";
1080
+ if (descriptor.isInRange && !descriptor.isActive) cls += " ogrid-mat-cell--range";
976
1081
  if (descriptor.isInCutRange) cls += " ogrid-mat-cell--cut";
977
1082
  const interactionProps = getCellInteractionProps(descriptor, col.columnId, interactionHandlers);
978
1083
  cellContent = /* @__PURE__ */ jsxs(
@@ -1004,6 +1109,7 @@ function DataGridTableInner(props) {
1004
1109
  onMouseDown: (e) => {
1005
1110
  lastMouseShiftRef.current = e.shiftKey;
1006
1111
  },
1112
+ onScroll: onHorizontalScroll ? (e) => onHorizontalScroll(e.target.scrollLeft) : void 0,
1007
1113
  onKeyDown: handleGridKeyDown,
1008
1114
  onContextMenu: PREVENT_DEFAULT,
1009
1115
  "data-density": density,
@@ -1018,6 +1124,7 @@ function DataGridTableInner(props) {
1018
1124
  size: "small",
1019
1125
  role: "grid",
1020
1126
  sx: { minWidth: minTableWidth, borderCollapse: "separate", borderSpacing: 0 },
1127
+ "data-virtual-scroll": virtualScrollEnabled ? "" : void 0,
1021
1128
  children: [
1022
1129
  /* @__PURE__ */ jsx(TableHead, { sx: STICKY_HEADER_SX, children: headerRows.map((row, rowIdx) => /* @__PURE__ */ jsxs(TableRow, { sx: HEADER_ROW_SX, children: [
1023
1130
  rowIdx === headerRows.length - 1 && hasCheckboxCol && /* @__PURE__ */ jsx(
@@ -1156,66 +1263,34 @@ function DataGridTableInner(props) {
1156
1263
  );
1157
1264
  })
1158
1265
  ] }, rowIdx)) }),
1159
- !showEmptyInGrid && /* @__PURE__ */ jsxs("tbody", { className: "ogrid-mat-tbody", children: [
1160
- virtualScrollEnabled && visibleRange.offsetTop > 0 && /* @__PURE__ */ jsx("tr", { style: { height: visibleRange.offsetTop }, "aria-hidden": true }),
1161
- virtualScrollEnabled ? items.slice(visibleRange.startIndex, visibleRange.endIndex + 1).map((item, i) => {
1162
- const rowIndex = visibleRange.startIndex + i;
1163
- const rowIdStr = getRowId(item);
1164
- return /* @__PURE__ */ jsx(
1165
- GridRow,
1166
- {
1167
- item,
1168
- rowIndex,
1169
- rowId: rowIdStr,
1170
- isSelected: selectedRowIds.has(rowIdStr),
1171
- columnLayouts,
1172
- renderCellContent,
1173
- handleSingleRowClick,
1174
- handleRowCheckboxChange,
1175
- lastMouseShiftRef,
1176
- hasCheckboxCol,
1177
- hasRowNumbersCol,
1178
- rowNumberOffset,
1179
- selectionRange,
1180
- activeCell: interaction.activeCell,
1181
- cutRange,
1182
- copyRange,
1183
- isDragging,
1184
- rowHeight,
1185
- editingRowId: editingCell?.rowId ?? null
1186
- },
1187
- rowIdStr
1188
- );
1189
- }) : items.map((item, rowIndex) => {
1190
- const rowIdStr = getRowId(item);
1191
- return /* @__PURE__ */ jsx(
1192
- GridRow,
1193
- {
1194
- item,
1195
- rowIndex,
1196
- rowId: rowIdStr,
1197
- isSelected: selectedRowIds.has(rowIdStr),
1198
- columnLayouts,
1199
- renderCellContent,
1200
- handleSingleRowClick,
1201
- handleRowCheckboxChange,
1202
- lastMouseShiftRef,
1203
- hasCheckboxCol,
1204
- hasRowNumbersCol,
1205
- rowNumberOffset,
1206
- selectionRange,
1207
- activeCell: interaction.activeCell,
1208
- cutRange,
1209
- copyRange,
1210
- isDragging,
1211
- rowHeight,
1212
- editingRowId: editingCell?.rowId ?? null
1213
- },
1214
- rowIdStr
1215
- );
1216
- }),
1217
- virtualScrollEnabled && visibleRange.offsetBottom > 0 && /* @__PURE__ */ jsx("tr", { style: { height: visibleRange.offsetBottom }, "aria-hidden": true })
1218
- ] })
1266
+ !showEmptyInGrid && /* @__PURE__ */ jsx(
1267
+ MaterialTableBody,
1268
+ {
1269
+ virtualScrollEnabled,
1270
+ visibleRange,
1271
+ columnRange,
1272
+ items,
1273
+ getRowId,
1274
+ selectedRowIds,
1275
+ visibleCols,
1276
+ columnLayouts,
1277
+ renderCellContent,
1278
+ handleSingleRowClick,
1279
+ handleRowCheckboxChange,
1280
+ lastMouseShiftRef,
1281
+ hasCheckboxCol,
1282
+ hasRowNumbersCol,
1283
+ rowNumberOffset,
1284
+ rowHeight,
1285
+ selectionRange,
1286
+ activeCell: interaction.activeCell,
1287
+ cutRange,
1288
+ copyRange,
1289
+ isDragging,
1290
+ editingCell,
1291
+ pinnedColumns: pinning.pinnedColumns
1292
+ }
1293
+ )
1219
1294
  ]
1220
1295
  }
1221
1296
  ),
@@ -1296,7 +1371,7 @@ function DataGridTableInner(props) {
1296
1371
  isLoading && /* @__PURE__ */ jsx(LoadingOverlay, { message: loadingMessage })
1297
1372
  ] });
1298
1373
  }
1299
- var DataGridTable = React3.memo(DataGridTableInner);
1374
+ var DataGridTable = React4.memo(DataGridTableInner);
1300
1375
  var ColumnChooser = (props) => {
1301
1376
  const { columns, visibleColumns, onVisibilityChange, onSetVisibleColumns, className } = props;
1302
1377
  const [anchorEl, setAnchorEl] = useState(null);
@@ -1437,7 +1512,7 @@ var ColumnChooser = (props) => {
1437
1512
  )
1438
1513
  ] });
1439
1514
  };
1440
- var PaginationControls = React3.memo((props) => {
1515
+ var PaginationControls = React4.memo((props) => {
1441
1516
  const {
1442
1517
  currentPage,
1443
1518
  pageSize,
@@ -1593,10 +1668,10 @@ var PaginationControls = React3.memo((props) => {
1593
1668
  }
1594
1669
  );
1595
1670
  });
1596
- var MuiThemeContainer = React3.forwardRef(
1671
+ var MuiThemeContainer = React4.forwardRef(
1597
1672
  function MuiThemeContainer2(props, ref) {
1598
1673
  const theme = useTheme();
1599
- const sx = React3.useMemo(() => ({
1674
+ const sx = React4.useMemo(() => ({
1600
1675
  display: "flex",
1601
1676
  flexDirection: "column",
1602
1677
  gap: 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-react-material",
3
- "version": "2.1.14",
3
+ "version": "2.2.0",
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.1.14"
42
+ "@alaarab/ogrid-react": "2.2.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@emotion/react": "^11.0.0",