@alaarab/ogrid-react-material 2.3.0 → 2.4.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.
Files changed (2) hide show
  1. package/dist/esm/index.js +231 -364
  2. package/package.json +2 -2
package/dist/esm/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as React4 from 'react';
2
2
  import { useMemo, useCallback, useState, useRef, useEffect } from 'react';
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, indexToColumnLetter, getHeaderFilterConfig, MarchingAntsOverlay, NOOP, useColumnChooserState, useListVirtualizer, BaseInlineCellEditor, partitionColumnsForVirtualization, getContextMenuHandlers, GRID_CONTEXT_MENU_ITEMS, formatShortcut, getColumnHeaderMenuItems, getStatusBarParts } from '@alaarab/ogrid-react';
3
+ import { Box, Tooltip, Typography, IconButton, Popover, useTheme, TextField, InputAdornment, Button, CircularProgress, FormControlLabel, Checkbox, Avatar, Table, TableHead, TableRow, TableCell, Select, MenuItem, Menu, Divider } from '@mui/material';
4
+ import { createBaseFilterRenderers, useColumnHeaderFilterState, getColumnHeaderFilterStateParams, renderFilterContent, areGridRowPropsEqual, PaginationControlsBase, createOGrid, useListVirtualizer, CHECKBOX_COLUMN_WIDTH, STOP_PROPAGATION, ROW_NUMBER_COLUMN_WIDTH, useDataGridTableOrchestration, useColumnMeta, getCellRenderDescriptor, buildInlineEditorProps, buildPopoverEditorProps, resolveCellDisplayContent, resolveCellStyle, getCellInteractionProps, CellErrorBoundary, PREVENT_DEFAULT, indexToColumnLetter, ROW_NUMBER_COLUMN_ID, getHeaderFilterConfig, MarchingAntsOverlay, FormulaRefOverlay, NOOP, getColumnHeaderMenuProps, useColumnChooserState, ColumnChooserContent, 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
- import { FilterList, FirstPage, ChevronLeft, ChevronRight, LastPage, ExpandLess, ExpandMore, ViewColumn, Clear, Search } from '@mui/icons-material';
7
+ import { FilterList, Search, Clear, ExpandLess, ExpandMore, ViewColumn, LastPage, ChevronRight, ChevronLeft, FirstPage } from '@mui/icons-material';
8
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
9
 
10
10
  // src/OGrid/OGrid.tsx
@@ -228,56 +228,9 @@ var PeopleFilterPopover = ({
228
228
  selectedUser && /* @__PURE__ */ jsx(Box, { sx: { p: 1.5, pt: 1, borderTop: 1, borderColor: "divider" }, children: /* @__PURE__ */ jsx(Button, { size: "small", fullWidth: true, onClick: onClearUser, children: "Clear Filter" }) })
229
229
  ] });
230
230
  PeopleFilterPopover.displayName = "PeopleFilterPopover";
231
- var materialRenderers = {
232
- renderMultiSelect: (p) => /* @__PURE__ */ jsx(
233
- MultiSelectFilterPopover,
234
- {
235
- searchText: p.searchText,
236
- onSearchChange: p.onSearchChange,
237
- options: p.options,
238
- filteredOptions: p.filteredOptions,
239
- selected: p.selected,
240
- onOptionToggle: p.onOptionToggle,
241
- onSelectAll: p.onSelectAll,
242
- onClearSelection: p.onClearSelection,
243
- onApply: p.onApply,
244
- isLoading: p.isLoading
245
- }
246
- ),
247
- renderText: (p) => /* @__PURE__ */ jsx(
248
- TextFilterPopover,
249
- {
250
- value: p.value,
251
- onValueChange: p.onValueChange,
252
- onApply: p.onApply,
253
- onClear: p.onClear
254
- }
255
- ),
256
- renderPeople: (p) => /* @__PURE__ */ jsx(
257
- PeopleFilterPopover,
258
- {
259
- selectedUser: p.selectedUser,
260
- searchText: p.searchText,
261
- onSearchChange: p.onSearchChange,
262
- suggestions: p.suggestions,
263
- isLoading: p.isLoading,
264
- onUserSelect: p.onUserSelect,
265
- onClearUser: p.onClearUser,
266
- inputRef: p.inputRef
267
- }
268
- ),
269
- renderDate: (p) => /* @__PURE__ */ jsx(
270
- DateFilterContent,
271
- {
272
- tempDateFrom: p.tempDateFrom,
273
- setTempDateFrom: p.setTempDateFrom,
274
- tempDateTo: p.tempDateTo,
275
- setTempDateTo: p.setTempDateTo,
276
- onApply: p.onApply,
277
- onClear: p.onClear
278
- }
279
- )
280
- };
231
+ var materialRenderers = createBaseFilterRenderers(
232
+ { MultiSelectFilterPopover, TextFilterPopover, PeopleFilterPopover }
233
+ );
281
234
  var ColumnHeaderFilter = React4.memo((props) => {
282
235
  const {
283
236
  columnName,
@@ -772,7 +725,8 @@ function GridRowInner(props) {
772
725
  rowHeight,
773
726
  leftSpacerWidth,
774
727
  rightSpacerWidth,
775
- globalColIndexMap
728
+ globalColIndexMap,
729
+ rowNumWidth
776
730
  } = props;
777
731
  return /* @__PURE__ */ jsxs(
778
732
  "tr",
@@ -801,20 +755,23 @@ function GridRowInner(props) {
801
755
  )
802
756
  }
803
757
  ) }),
804
- hasRowNumbersCol && /* @__PURE__ */ jsx(
805
- "td",
806
- {
807
- className: "ogrid-mat-td ogrid-mat-row-number",
808
- style: {
809
- width: ROW_NUMBER_COLUMN_WIDTH,
810
- minWidth: ROW_NUMBER_COLUMN_WIDTH,
811
- maxWidth: ROW_NUMBER_COLUMN_WIDTH,
812
- left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
813
- borderBottom: "1px solid var(--ogrid-border, rgba(224,224,224,1))"
814
- },
815
- children: rowNumberOffset + rowIndex + 1
816
- }
817
- ),
758
+ hasRowNumbersCol && (() => {
759
+ const rnw = rowNumWidth ?? ROW_NUMBER_COLUMN_WIDTH;
760
+ return /* @__PURE__ */ jsx(
761
+ "td",
762
+ {
763
+ className: "ogrid-mat-td ogrid-mat-row-number",
764
+ style: {
765
+ width: rnw,
766
+ minWidth: rnw,
767
+ maxWidth: rnw,
768
+ left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
769
+ borderBottom: "1px solid var(--ogrid-border, rgba(224,224,224,1))"
770
+ },
771
+ children: rowNumberOffset + rowIndex + 1
772
+ }
773
+ );
774
+ })(),
818
775
  leftSpacerWidth != null && leftSpacerWidth > 0 && /* @__PURE__ */ jsx("td", { style: { ...SPACER_TD_STYLE, width: leftSpacerWidth, minWidth: leftSpacerWidth }, "aria-hidden": true }),
819
776
  columnLayouts.map((cl, colIdx) => {
820
777
  const globalIdx = globalColIndexMap ? globalColIndexMap[colIdx] : colIdx;
@@ -860,7 +817,8 @@ function MaterialTableBody(props) {
860
817
  copyRange,
861
818
  isDragging,
862
819
  editingCell,
863
- pinnedColumns
820
+ pinnedColumns,
821
+ rowNumWidth
864
822
  } = props;
865
823
  const { rowLayouts, globalColIndexMap, leftSpacerWidth, rightSpacerWidth } = React4.useMemo(() => {
866
824
  if (!columnRange) {
@@ -915,7 +873,8 @@ function MaterialTableBody(props) {
915
873
  editingRowId: editingCell?.rowId ?? null,
916
874
  leftSpacerWidth,
917
875
  rightSpacerWidth,
918
- globalColIndexMap
876
+ globalColIndexMap,
877
+ rowNumWidth
919
878
  },
920
879
  rowIdStr
921
880
  );
@@ -1084,9 +1043,14 @@ function DataGridTableInner(props) {
1084
1043
  )
1085
1044
  ] });
1086
1045
  } else {
1087
- const content = resolveCellDisplayContent(col, item, descriptor.displayValue);
1088
- const cellStyle = resolveCellStyle(col, item, descriptor.displayValue);
1089
- const styledContent = cellStyle ? /* @__PURE__ */ jsx("span", { style: cellStyle, children: content }) : content;
1046
+ let displayNode;
1047
+ if (descriptor.columnType === "boolean") {
1048
+ displayNode = /* @__PURE__ */ jsx("input", { type: "checkbox", checked: !!descriptor.displayValue, disabled: true, style: { margin: 0, pointerEvents: "none" }, "aria-label": descriptor.displayValue ? "True" : "False" });
1049
+ } else {
1050
+ const content = resolveCellDisplayContent(col, item, descriptor.displayValue);
1051
+ const cellStyle = resolveCellStyle(col, item, descriptor.displayValue);
1052
+ displayNode = cellStyle ? /* @__PURE__ */ jsx("span", { style: cellStyle, children: content }) : content;
1053
+ }
1090
1054
  let cls = "ogrid-mat-cell";
1091
1055
  if (col.type === "numeric") cls += " ogrid-mat-cell--numeric";
1092
1056
  else if (col.type === "boolean") cls += " ogrid-mat-cell--boolean";
@@ -1103,7 +1067,7 @@ function DataGridTableInner(props) {
1103
1067
  ...interactionProps,
1104
1068
  style: cellDensityStyle,
1105
1069
  children: [
1106
- styledContent,
1070
+ displayNode,
1107
1071
  descriptor.canEditAny && descriptor.isSelectionEndCell && /* @__PURE__ */ jsx("div", { className: "ogrid-mat-fill-handle", onMouseDown: handleFillHandleMouseDown, "aria-label": "Fill handle" })
1108
1072
  ]
1109
1073
  }
@@ -1184,45 +1148,59 @@ function DataGridTableInner(props) {
1184
1148
  }
1185
1149
  ),
1186
1150
  rowIdx === 0 && rowIdx < headerRows.length - 1 && hasCheckboxCol && /* @__PURE__ */ jsx(TableCell, { ...{ rowSpan: headerRows.length - 1, sx: CHECKBOX_PLACEHOLDER_SX } }),
1187
- rowIdx === headerRows.length - 1 && hasRowNumbersCol && /* @__PURE__ */ jsx(
1188
- TableCell,
1189
- {
1190
- ...{
1191
- component: "th",
1192
- scope: "col",
1193
- rowSpan: headerRows.length > 1 ? 1 : void 0,
1194
- sx: {
1195
- width: ROW_NUMBER_COLUMN_WIDTH,
1196
- minWidth: ROW_NUMBER_COLUMN_WIDTH,
1197
- maxWidth: ROW_NUMBER_COLUMN_WIDTH,
1198
- textAlign: "center",
1199
- fontWeight: 600,
1200
- backgroundColor: HEADER_BG,
1201
- position: "sticky",
1202
- left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
1203
- zIndex: 4,
1204
- ...headerCellSx
1205
- }
1206
- },
1207
- children: "#"
1208
- }
1209
- ),
1210
- rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol && /* @__PURE__ */ jsx(
1211
- TableCell,
1212
- {
1213
- ...{
1214
- rowSpan: headerRows.length - 1,
1215
- sx: {
1216
- width: ROW_NUMBER_COLUMN_WIDTH,
1217
- minWidth: ROW_NUMBER_COLUMN_WIDTH,
1218
- position: "sticky",
1219
- left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
1220
- zIndex: 4,
1221
- backgroundColor: "background.paper"
1151
+ rowIdx === headerRows.length - 1 && hasRowNumbersCol && (() => {
1152
+ const rnw = columnSizingOverrides?.[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH;
1153
+ return /* @__PURE__ */ jsxs(
1154
+ TableCell,
1155
+ {
1156
+ ...{
1157
+ component: "th",
1158
+ scope: "col",
1159
+ rowSpan: headerRows.length > 1 ? 1 : void 0,
1160
+ sx: {
1161
+ width: rnw,
1162
+ minWidth: rnw,
1163
+ maxWidth: rnw,
1164
+ textAlign: "center",
1165
+ fontWeight: 600,
1166
+ backgroundColor: HEADER_BG,
1167
+ position: "sticky",
1168
+ left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
1169
+ zIndex: 4,
1170
+ ...headerCellSx
1171
+ }
1172
+ },
1173
+ children: [
1174
+ "#",
1175
+ /* @__PURE__ */ jsx(Box, { onMouseDown: (e) => {
1176
+ setActiveCell(null);
1177
+ interaction.setSelectionRange(null);
1178
+ wrapperRef.current?.focus({ preventScroll: true });
1179
+ handleResizeStart(e, { columnId: ROW_NUMBER_COLUMN_ID, name: "#" });
1180
+ }, sx: RESIZE_HANDLE_SX })
1181
+ ]
1182
+ }
1183
+ );
1184
+ })(),
1185
+ rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol && (() => {
1186
+ const spacerRnw = columnSizingOverrides?.[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH;
1187
+ return /* @__PURE__ */ jsx(
1188
+ TableCell,
1189
+ {
1190
+ ...{
1191
+ rowSpan: headerRows.length - 1,
1192
+ sx: {
1193
+ width: spacerRnw,
1194
+ minWidth: spacerRnw,
1195
+ position: "sticky",
1196
+ left: hasCheckboxCol ? CHECKBOX_COLUMN_WIDTH : 0,
1197
+ zIndex: 4,
1198
+ backgroundColor: "background.paper"
1199
+ }
1222
1200
  }
1223
1201
  }
1224
- }
1225
- ),
1202
+ );
1203
+ })(),
1226
1204
  row.map((cell, cellIdx) => {
1227
1205
  if (cell.isGroup) {
1228
1206
  return /* @__PURE__ */ jsx(
@@ -1282,7 +1260,11 @@ function DataGridTableInner(props) {
1282
1260
  component: "button",
1283
1261
  onClick: (e) => {
1284
1262
  e.stopPropagation();
1285
- headerMenu.open(col.columnId, e.currentTarget);
1263
+ if (headerMenu.isOpen && headerMenu.openForColumn === col.columnId) {
1264
+ headerMenu.close();
1265
+ } else {
1266
+ headerMenu.open(col.columnId, e.currentTarget);
1267
+ }
1286
1268
  },
1287
1269
  "aria-label": "Column options",
1288
1270
  title: "Column options",
@@ -1329,7 +1311,8 @@ function DataGridTableInner(props) {
1329
1311
  copyRange,
1330
1312
  isDragging,
1331
1313
  editingCell,
1332
- pinnedColumns: pinning.pinnedColumns
1314
+ pinnedColumns: pinning.pinnedColumns,
1315
+ rowNumWidth: hasRowNumbersCol ? columnSizingOverrides?.[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH : void 0
1333
1316
  }
1334
1317
  )
1335
1318
  ]
@@ -1351,6 +1334,14 @@ function DataGridTableInner(props) {
1351
1334
  isDragging
1352
1335
  }
1353
1336
  ),
1337
+ props.formulaReferences && props.formulaReferences.length > 0 && /* @__PURE__ */ jsx(
1338
+ FormulaRefOverlay,
1339
+ {
1340
+ containerRef: tableContainerRef,
1341
+ references: props.formulaReferences,
1342
+ colOffset
1343
+ }
1344
+ ),
1354
1345
  showEmptyInGrid && emptyState && /* @__PURE__ */ jsx(EmptyState, { emptyState })
1355
1346
  ] }) }) }),
1356
1347
  menuPosition && createPortal(
@@ -1373,28 +1364,7 @@ function DataGridTableInner(props) {
1373
1364
  ),
1374
1365
  document.body
1375
1366
  ),
1376
- /* @__PURE__ */ jsx(
1377
- ColumnHeaderMenu,
1378
- {
1379
- isOpen: headerMenu.isOpen,
1380
- anchorElement: headerMenu.anchorElement,
1381
- onClose: headerMenu.close,
1382
- onPinLeft: headerMenu.handlePinLeft,
1383
- onPinRight: headerMenu.handlePinRight,
1384
- onUnpin: headerMenu.handleUnpin,
1385
- onSortAsc: headerMenu.handleSortAsc,
1386
- onSortDesc: headerMenu.handleSortDesc,
1387
- onClearSort: headerMenu.handleClearSort,
1388
- onAutosizeThis: headerMenu.handleAutosizeThis,
1389
- onAutosizeAll: headerMenu.handleAutosizeAll,
1390
- canPinLeft: headerMenu.canPinLeft,
1391
- canPinRight: headerMenu.canPinRight,
1392
- canUnpin: headerMenu.canUnpin,
1393
- currentSort: headerMenu.currentSort,
1394
- isSortable: headerMenu.isSortable,
1395
- isResizable: headerMenu.isResizable
1396
- }
1397
- )
1367
+ /* @__PURE__ */ jsx(ColumnHeaderMenu, { ...getColumnHeaderMenuProps(headerMenu) })
1398
1368
  ]
1399
1369
  }
1400
1370
  ),
@@ -1413,6 +1383,53 @@ function DataGridTableInner(props) {
1413
1383
  ] });
1414
1384
  }
1415
1385
  var DataGridTable = React4.memo(DataGridTableInner);
1386
+ var CheckboxItem = ({ columnId: _columnId, columnName, checked, disabled, onChange }) => /* @__PURE__ */ jsx(
1387
+ FormControlLabel,
1388
+ {
1389
+ control: /* @__PURE__ */ jsx(
1390
+ Checkbox,
1391
+ {
1392
+ size: "small",
1393
+ checked,
1394
+ onChange: (ev) => {
1395
+ ev.stopPropagation();
1396
+ onChange(ev.target.checked);
1397
+ },
1398
+ disabled
1399
+ }
1400
+ ),
1401
+ label: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: columnName }),
1402
+ sx: { m: 0 }
1403
+ }
1404
+ );
1405
+ var Header = ({ visibleCount, totalCount }) => /* @__PURE__ */ jsx(Box, { sx: { px: 1.5, py: 1, borderBottom: 1, borderColor: "divider", bgcolor: "action.hover" }, children: /* @__PURE__ */ jsxs(Typography, { variant: "subtitle2", fontWeight: 600, children: [
1406
+ "Select Columns (",
1407
+ visibleCount,
1408
+ " of ",
1409
+ totalCount,
1410
+ ")"
1411
+ ] }) });
1412
+ var OptionsListContainer = ({ children }) => /* @__PURE__ */ jsx(Box, { sx: { maxHeight: 320, overflowY: "auto", py: 0.5 }, children });
1413
+ var OptionItemContainer = ({ children }) => /* @__PURE__ */ jsx(Box, { sx: { px: 1.5, minHeight: 32, display: "flex", alignItems: "center" }, children });
1414
+ var Actions = ({ onClearAll, onSelectAll }) => /* @__PURE__ */ jsxs(
1415
+ Box,
1416
+ {
1417
+ sx: {
1418
+ display: "flex",
1419
+ justifyContent: "flex-end",
1420
+ gap: 1,
1421
+ px: 1.5,
1422
+ py: 1,
1423
+ borderTop: 1,
1424
+ borderColor: "divider",
1425
+ bgcolor: "action.hover"
1426
+ },
1427
+ children: [
1428
+ /* @__PURE__ */ jsx(Button, { size: "small", onClick: onClearAll, sx: { textTransform: "none" }, children: "Clear All" }),
1429
+ /* @__PURE__ */ jsx(Button, { size: "small", variant: "contained", onClick: onSelectAll, sx: { textTransform: "none" }, children: "Select All" })
1430
+ ]
1431
+ }
1432
+ );
1416
1433
  var ColumnChooser = (props) => {
1417
1434
  const { columns, visibleColumns, onVisibilityChange, onSetVisibleColumns, className } = props;
1418
1435
  const [anchorEl, setAnchorEl] = useState(null);
@@ -1440,10 +1457,7 @@ var ColumnChooser = (props) => {
1440
1457
  handleClose();
1441
1458
  setAnchorEl(null);
1442
1459
  };
1443
- const handleCheckboxChange = (columnKey) => (ev) => {
1444
- ev.stopPropagation();
1445
- setColumnVisible(columnKey)(ev.target.checked);
1446
- };
1460
+ const handleCheckboxChange = (columnKey) => (checked) => setColumnVisible(columnKey)(checked);
1447
1461
  return /* @__PURE__ */ jsxs(Box, { className, sx: { display: "inline-flex" }, children: [
1448
1462
  /* @__PURE__ */ jsxs(
1449
1463
  Button,
@@ -1471,7 +1485,7 @@ var ColumnChooser = (props) => {
1471
1485
  ]
1472
1486
  }
1473
1487
  ),
1474
- /* @__PURE__ */ jsxs(
1488
+ /* @__PURE__ */ jsx(
1475
1489
  Popover,
1476
1490
  {
1477
1491
  open: isOpen,
@@ -1479,236 +1493,89 @@ var ColumnChooser = (props) => {
1479
1493
  onClose: handlePopoverClose,
1480
1494
  anchorOrigin: { vertical: "bottom", horizontal: "right" },
1481
1495
  transformOrigin: { vertical: "top", horizontal: "right" },
1482
- slotProps: {
1483
- paper: {
1484
- sx: { mt: 0.5, minWidth: 220 }
1496
+ slotProps: { paper: { sx: { mt: 0.5, minWidth: 220 } } },
1497
+ children: /* @__PURE__ */ jsx(
1498
+ ColumnChooserContent,
1499
+ {
1500
+ columns,
1501
+ visibleColumns,
1502
+ visibleCount,
1503
+ totalCount,
1504
+ handleSelectAll,
1505
+ handleClearAll,
1506
+ handleCheckboxChange,
1507
+ CheckboxItem,
1508
+ Header,
1509
+ OptionsListContainer,
1510
+ OptionItemContainer,
1511
+ Actions
1485
1512
  }
1486
- },
1487
- children: [
1488
- /* @__PURE__ */ jsx(
1489
- Box,
1490
- {
1491
- sx: {
1492
- px: 1.5,
1493
- py: 1,
1494
- borderBottom: 1,
1495
- borderColor: "divider",
1496
- bgcolor: "action.hover"
1497
- },
1498
- children: /* @__PURE__ */ jsxs(Typography, { variant: "subtitle2", fontWeight: 600, children: [
1499
- "Select Columns (",
1500
- visibleCount,
1501
- " of ",
1502
- totalCount,
1503
- ")"
1504
- ] })
1505
- }
1506
- ),
1507
- /* @__PURE__ */ jsx(Box, { sx: { maxHeight: 320, overflowY: "auto", py: 0.5 }, children: columns.map((column) => /* @__PURE__ */ jsx(Box, { sx: { px: 1.5, minHeight: 32, display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx(
1508
- FormControlLabel,
1509
- {
1510
- control: /* @__PURE__ */ jsx(
1511
- Checkbox,
1512
- {
1513
- size: "small",
1514
- checked: visibleColumns.has(column.columnId),
1515
- onChange: handleCheckboxChange(column.columnId),
1516
- disabled: column.required === true
1517
- }
1518
- ),
1519
- label: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: column.name }),
1520
- sx: { m: 0 }
1521
- }
1522
- ) }, column.columnId)) }),
1523
- /* @__PURE__ */ jsxs(
1524
- Box,
1525
- {
1526
- sx: {
1527
- display: "flex",
1528
- justifyContent: "flex-end",
1529
- gap: 1,
1530
- px: 1.5,
1531
- py: 1,
1532
- borderTop: 1,
1533
- borderColor: "divider",
1534
- bgcolor: "action.hover"
1535
- },
1536
- children: [
1537
- /* @__PURE__ */ jsx(Button, { size: "small", onClick: handleClearAll, sx: { textTransform: "none" }, children: "Clear All" }),
1538
- /* @__PURE__ */ jsx(
1539
- Button,
1540
- {
1541
- size: "small",
1542
- variant: "contained",
1543
- onClick: handleSelectAll,
1544
- sx: { textTransform: "none" },
1545
- children: "Select All"
1546
- }
1547
- )
1548
- ]
1549
- }
1550
- )
1551
- ]
1513
+ )
1552
1514
  }
1553
1515
  )
1554
1516
  ] });
1555
1517
  };
1556
- var PaginationControls = React4.memo((props) => {
1557
- const {
1558
- currentPage,
1559
- pageSize,
1560
- totalCount,
1561
- onPageChange,
1562
- onPageSizeChange,
1563
- pageSizeOptions,
1564
- entityLabelPlural,
1565
- className
1566
- } = props;
1567
- const { labelPlural, vm, handlePageSizeChange } = usePaginationControls({
1568
- currentPage,
1569
- pageSize,
1570
- totalCount,
1571
- onPageChange,
1572
- onPageSizeChange,
1573
- pageSizeOptions,
1574
- entityLabelPlural
1575
- });
1576
- const handlePageSizeChangeEvent = (event) => {
1577
- handlePageSizeChange(Number(event.target.value));
1578
- };
1579
- if (!vm) {
1580
- return null;
1518
+ var MUI_NAV_ICONS = {
1519
+ first: /* @__PURE__ */ jsx(FirstPage, { fontSize: "small" }),
1520
+ prev: /* @__PURE__ */ jsx(ChevronLeft, { fontSize: "small" }),
1521
+ next: /* @__PURE__ */ jsx(ChevronRight, { fontSize: "small" }),
1522
+ last: /* @__PURE__ */ jsx(LastPage, { fontSize: "small" })
1523
+ };
1524
+ var NavButton = ({ variant, onClick, disabled, "aria-label": ariaLabel }) => /* @__PURE__ */ jsx(IconButton, { size: "small", onClick, disabled, "aria-label": ariaLabel, children: MUI_NAV_ICONS[variant] });
1525
+ var PageButton = ({ onClick, active, "aria-label": ariaLabel, "aria-current": ariaCurrent, children }) => /* @__PURE__ */ jsx(
1526
+ Button,
1527
+ {
1528
+ variant: active ? "contained" : "outlined",
1529
+ size: "small",
1530
+ onClick,
1531
+ "aria-label": ariaLabel,
1532
+ "aria-current": ariaCurrent,
1533
+ sx: { minWidth: 32, px: 0.5 },
1534
+ children
1581
1535
  }
1582
- const { pageNumbers, showStartEllipsis, showEndEllipsis, totalPages, startItem, endItem } = vm;
1583
- return /* @__PURE__ */ jsxs(
1584
- Box,
1585
- {
1586
- className,
1587
- role: "navigation",
1588
- "aria-label": "Pagination",
1589
- sx: {
1590
- display: "flex",
1591
- alignItems: "center",
1592
- justifyContent: "space-between",
1593
- flexWrap: "wrap",
1594
- gap: 2,
1595
- px: 1.5,
1596
- width: "100%",
1597
- minWidth: 0,
1598
- boxSizing: "border-box"
1599
- },
1600
- children: [
1601
- /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "text.secondary", children: [
1602
- "Showing ",
1603
- startItem,
1604
- " to ",
1605
- endItem,
1606
- " of ",
1607
- totalCount.toLocaleString(),
1608
- " ",
1609
- labelPlural
1610
- ] }),
1611
- /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
1612
- /* @__PURE__ */ jsx(
1613
- IconButton,
1614
- {
1615
- size: "small",
1616
- onClick: () => onPageChange(1),
1617
- disabled: currentPage === 1,
1618
- "aria-label": "First page",
1619
- children: /* @__PURE__ */ jsx(FirstPage, { fontSize: "small" })
1620
- }
1621
- ),
1622
- /* @__PURE__ */ jsx(
1623
- IconButton,
1624
- {
1625
- size: "small",
1626
- onClick: () => onPageChange(currentPage - 1),
1627
- disabled: currentPage === 1,
1628
- "aria-label": "Previous page",
1629
- children: /* @__PURE__ */ jsx(ChevronLeft, { fontSize: "small" })
1630
- }
1631
- ),
1632
- showStartEllipsis && /* @__PURE__ */ jsxs(Fragment, { children: [
1633
- /* @__PURE__ */ jsx(
1634
- Button,
1635
- {
1636
- variant: "outlined",
1637
- size: "small",
1638
- onClick: () => onPageChange(1),
1639
- "aria-label": "Page 1",
1640
- sx: { minWidth: 32, px: 0.5 },
1641
- children: "1"
1642
- }
1643
- ),
1644
- /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mx: 0.5 }, "aria-hidden": true, children: "\u2026" })
1645
- ] }),
1646
- pageNumbers.map((pageNum) => /* @__PURE__ */ jsx(
1647
- Button,
1648
- {
1649
- variant: currentPage === pageNum ? "contained" : "outlined",
1650
- size: "small",
1651
- onClick: () => onPageChange(pageNum),
1652
- "aria-label": `Page ${pageNum}`,
1653
- "aria-current": currentPage === pageNum ? "page" : void 0,
1654
- sx: { minWidth: 32, px: 0.5 },
1655
- children: pageNum
1656
- },
1657
- pageNum
1658
- )),
1659
- showEndEllipsis && /* @__PURE__ */ jsxs(Fragment, { children: [
1660
- /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mx: 0.5 }, "aria-hidden": true, children: "\u2026" }),
1661
- /* @__PURE__ */ jsx(
1662
- Button,
1663
- {
1664
- variant: "outlined",
1665
- size: "small",
1666
- onClick: () => onPageChange(totalPages),
1667
- "aria-label": `Page ${totalPages}`,
1668
- sx: { minWidth: 32, px: 0.5 },
1669
- children: totalPages
1670
- }
1671
- )
1672
- ] }),
1673
- /* @__PURE__ */ jsx(
1674
- IconButton,
1675
- {
1676
- size: "small",
1677
- onClick: () => onPageChange(currentPage + 1),
1678
- disabled: currentPage >= totalPages,
1679
- "aria-label": "Next page",
1680
- children: /* @__PURE__ */ jsx(ChevronRight, { fontSize: "small" })
1681
- }
1682
- ),
1683
- /* @__PURE__ */ jsx(
1684
- IconButton,
1685
- {
1686
- size: "small",
1687
- onClick: () => onPageChange(totalPages),
1688
- disabled: currentPage >= totalPages,
1689
- "aria-label": "Last page",
1690
- children: /* @__PURE__ */ jsx(LastPage, { fontSize: "small" })
1691
- }
1692
- )
1693
- ] }),
1694
- /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1695
- /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "Rows" }),
1696
- /* @__PURE__ */ jsx(
1697
- Select,
1698
- {
1699
- value: pageSize,
1700
- onChange: handlePageSizeChangeEvent,
1701
- size: "small",
1702
- "aria-label": "Rows per page",
1703
- sx: { minWidth: 70 },
1704
- children: vm.pageSizeOptions.map((n) => /* @__PURE__ */ jsx(MenuItem, { value: n, children: n }, n))
1705
- }
1706
- )
1707
- ] })
1708
- ]
1709
- }
1710
- );
1711
- });
1536
+ );
1537
+ var PageSizeSelect = ({ value, options, onChange, "aria-label": ariaLabel }) => {
1538
+ const handleChange = (event) => onChange(Number(event.target.value));
1539
+ return /* @__PURE__ */ jsx(Select, { value, onChange: handleChange, size: "small", "aria-label": ariaLabel, sx: { minWidth: 70 }, children: options.map((n) => /* @__PURE__ */ jsx(MenuItem, { value: n, children: n }, n)) });
1540
+ };
1541
+ var OuterContainer = ({ children, className, role, "aria-label": ariaLabel }) => /* @__PURE__ */ jsx(
1542
+ Box,
1543
+ {
1544
+ className,
1545
+ role,
1546
+ "aria-label": ariaLabel,
1547
+ sx: {
1548
+ display: "flex",
1549
+ alignItems: "center",
1550
+ justifyContent: "space-between",
1551
+ flexWrap: "wrap",
1552
+ gap: 2,
1553
+ px: 1.5,
1554
+ width: "100%",
1555
+ minWidth: 0,
1556
+ boxSizing: "border-box"
1557
+ },
1558
+ children
1559
+ }
1560
+ );
1561
+ var InfoText = ({ children }) => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children });
1562
+ var NavButtonsContainer = ({ children }) => /* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children });
1563
+ var PageSizeContainer = ({ children }) => /* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children });
1564
+ var PageSizeLabel = () => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "Rows" });
1565
+ var Ellipsis = () => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mx: 0.5 }, "aria-hidden": true, children: "\u2026" });
1566
+ var SLOTS = {
1567
+ NavButton,
1568
+ PageButton,
1569
+ PageSizeSelect,
1570
+ OuterContainer,
1571
+ InfoText,
1572
+ NavButtonsContainer,
1573
+ PageSizeContainer,
1574
+ PageSizeLabel,
1575
+ Ellipsis
1576
+ };
1577
+ var PaginationControls = React4.memo((props) => /* @__PURE__ */ jsx(PaginationControlsBase, { ...props, slots: SLOTS }));
1578
+ PaginationControls.displayName = "PaginationControls";
1712
1579
  var MuiThemeContainer = React4.forwardRef(
1713
1580
  function MuiThemeContainer2(props, ref) {
1714
1581
  const theme = useTheme();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-react-material",
3
- "version": "2.3.0",
3
+ "version": "2.4.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.3.0"
42
+ "@alaarab/ogrid-react": "2.4.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@emotion/react": "^11.0.0",