@mui/x-data-grid-premium 7.5.0 → 7.6.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 (39) hide show
  1. package/CHANGELOG.md +148 -5418
  2. package/DataGridPremium/DataGridPremium.js +2 -2
  3. package/components/GridColumnMenuAggregationItem.js +1 -1
  4. package/components/GridColumnMenuRowGroupItem.d.ts +1 -5
  5. package/components/GridColumnMenuRowGroupItem.js +1 -10
  6. package/components/GridColumnMenuRowUngroupItem.d.ts +1 -5
  7. package/components/GridColumnMenuRowUngroupItem.js +1 -10
  8. package/components/GridExcelExportMenuItem.js +2 -1
  9. package/components/GridPremiumColumnMenu.d.ts +1 -2
  10. package/components/GridPremiumColumnMenu.js +1 -11
  11. package/esm/DataGridPremium/DataGridPremium.js +2 -2
  12. package/esm/components/GridColumnMenuAggregationItem.js +1 -1
  13. package/esm/components/GridColumnMenuRowGroupItem.js +2 -12
  14. package/esm/components/GridColumnMenuRowUngroupItem.js +2 -12
  15. package/esm/components/GridExcelExportMenuItem.js +2 -1
  16. package/esm/components/GridPremiumColumnMenu.js +2 -13
  17. package/esm/hooks/features/cellSelection/useGridCellSelection.js +6 -3
  18. package/esm/hooks/features/export/serializer/excelSerializer.js +43 -23
  19. package/esm/hooks/features/export/useGridExcelExport.js +9 -4
  20. package/esm/utils/releaseInfo.js +1 -1
  21. package/hooks/features/cellSelection/useGridCellSelection.js +6 -3
  22. package/hooks/features/export/serializer/excelSerializer.d.ts +12 -10
  23. package/hooks/features/export/serializer/excelSerializer.js +44 -24
  24. package/hooks/features/export/useGridExcelExport.js +8 -3
  25. package/index.d.ts +1 -0
  26. package/index.js +1 -1
  27. package/modern/DataGridPremium/DataGridPremium.js +2 -2
  28. package/modern/components/GridColumnMenuAggregationItem.js +1 -1
  29. package/modern/components/GridColumnMenuRowGroupItem.js +2 -12
  30. package/modern/components/GridColumnMenuRowUngroupItem.js +2 -12
  31. package/modern/components/GridExcelExportMenuItem.js +2 -1
  32. package/modern/components/GridPremiumColumnMenu.js +2 -13
  33. package/modern/hooks/features/cellSelection/useGridCellSelection.js +6 -3
  34. package/modern/hooks/features/export/serializer/excelSerializer.js +43 -23
  35. package/modern/hooks/features/export/useGridExcelExport.js +9 -4
  36. package/modern/index.js +1 -1
  37. package/modern/utils/releaseInfo.js +1 -1
  38. package/package.json +6 -6
  39. package/utils/releaseInfo.js +1 -1
@@ -59,7 +59,7 @@ const DataGridPremium = exports.DataGridPremium = /*#__PURE__*/React.memo(DataGr
59
59
  process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
60
60
  // ----------------------------- Warning --------------------------------
61
61
  // | These PropTypes are generated from the TypeScript type definitions |
62
- // | To update them edit the TypeScript types and run "yarn proptypes" |
62
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
63
63
  // ----------------------------------------------------------------------
64
64
  /**
65
65
  * Aggregation functions available on the grid.
@@ -92,7 +92,7 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
92
92
  */
93
93
  'aria-labelledby': _propTypes.default.string,
94
94
  /**
95
- * If `true`, the Data Grid height is dynamic and follow the number of rows in the Data Grid.
95
+ * If `true`, the Data Grid height is dynamic and follows the number of rows in the Data Grid.
96
96
  * @default false
97
97
  */
98
98
  autoHeight: _propTypes.default.bool,
@@ -109,7 +109,7 @@ function GridColumnMenuAggregationItem(props) {
109
109
  process.env.NODE_ENV !== "production" ? GridColumnMenuAggregationItem.propTypes = {
110
110
  // ----------------------------- Warning --------------------------------
111
111
  // | These PropTypes are generated from the TypeScript type definitions |
112
- // | To update them edit the TypeScript types and run "yarn proptypes" |
112
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
113
113
  // ----------------------------------------------------------------------
114
114
  colDef: _propTypes.default.object.isRequired,
115
115
  onClick: _propTypes.default.func.isRequired
@@ -1,7 +1,3 @@
1
1
  import * as React from 'react';
2
2
  import { GridColumnMenuItemProps } from '@mui/x-data-grid-pro';
3
- declare function GridColumnMenuRowGroupItem(props: GridColumnMenuItemProps): React.JSX.Element | null;
4
- declare namespace GridColumnMenuRowGroupItem {
5
- var propTypes: any;
6
- }
7
- export { GridColumnMenuRowGroupItem };
3
+ export declare function GridColumnMenuRowGroupItem(props: GridColumnMenuItemProps): React.JSX.Element | null;
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.GridColumnMenuRowGroupItem = GridColumnMenuRowGroupItem;
8
8
  var React = _interopRequireWildcard(require("react"));
9
- var _propTypes = _interopRequireDefault(require("prop-types"));
10
9
  var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
11
10
  var _ListItemIcon = _interopRequireDefault(require("@mui/material/ListItemIcon"));
12
11
  var _ListItemText = _interopRequireDefault(require("@mui/material/ListItemText"));
@@ -55,12 +54,4 @@ function GridColumnMenuRowGroupItem(props) {
55
54
  });
56
55
  }
57
56
  return renderUnGroupingMenuItem((0, _gridRowGroupingUtils.getRowGroupingCriteriaFromGroupingField)(colDef.field));
58
- }
59
- process.env.NODE_ENV !== "production" ? GridColumnMenuRowGroupItem.propTypes = {
60
- // ----------------------------- Warning --------------------------------
61
- // | These PropTypes are generated from the TypeScript type definitions |
62
- // | To update them edit the TypeScript types and run "yarn proptypes" |
63
- // ----------------------------------------------------------------------
64
- colDef: _propTypes.default.object.isRequired,
65
- onClick: _propTypes.default.func.isRequired
66
- } : void 0;
57
+ }
@@ -1,7 +1,3 @@
1
1
  import * as React from 'react';
2
2
  import { GridColumnMenuItemProps } from '@mui/x-data-grid-pro';
3
- declare function GridColumnMenuRowUngroupItem(props: GridColumnMenuItemProps): React.JSX.Element | null;
4
- declare namespace GridColumnMenuRowUngroupItem {
5
- var propTypes: any;
6
- }
7
- export { GridColumnMenuRowUngroupItem };
3
+ export declare function GridColumnMenuRowUngroupItem(props: GridColumnMenuItemProps): React.JSX.Element | null;
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.GridColumnMenuRowUngroupItem = GridColumnMenuRowUngroupItem;
8
8
  var React = _interopRequireWildcard(require("react"));
9
- var _propTypes = _interopRequireDefault(require("prop-types"));
10
9
  var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
11
10
  var _ListItemIcon = _interopRequireDefault(require("@mui/material/ListItemIcon"));
12
11
  var _ListItemText = _interopRequireDefault(require("@mui/material/ListItemText"));
@@ -60,12 +59,4 @@ function GridColumnMenuRowUngroupItem(props) {
60
59
  children: apiRef.current.getLocaleText('groupColumn')(name)
61
60
  })]
62
61
  });
63
- }
64
- process.env.NODE_ENV !== "production" ? GridColumnMenuRowUngroupItem.propTypes = {
65
- // ----------------------------- Warning --------------------------------
66
- // | These PropTypes are generated from the TypeScript type definitions |
67
- // | To update them edit the TypeScript types and run "yarn proptypes" |
68
- // ----------------------------------------------------------------------
69
- colDef: _propTypes.default.object.isRequired,
70
- onClick: _propTypes.default.func.isRequired
71
- } : void 0;
62
+ }
@@ -34,13 +34,14 @@ function GridExcelExportMenuItem(props) {
34
34
  process.env.NODE_ENV !== "production" ? GridExcelExportMenuItem.propTypes = {
35
35
  // ----------------------------- Warning --------------------------------
36
36
  // | These PropTypes are generated from the TypeScript type definitions |
37
- // | To update them edit the TypeScript types and run "yarn proptypes" |
37
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
38
38
  // ----------------------------------------------------------------------
39
39
  hideMenu: _propTypes.default.func,
40
40
  options: _propTypes.default.shape({
41
41
  allColumns: _propTypes.default.bool,
42
42
  columnsStyles: _propTypes.default.object,
43
43
  disableToolbarButton: _propTypes.default.bool,
44
+ escapeFormulas: _propTypes.default.bool,
44
45
  exceljsPostProcess: _propTypes.default.func,
45
46
  exceljsPreProcess: _propTypes.default.func,
46
47
  fields: _propTypes.default.arrayOf(_propTypes.default.string),
@@ -30,5 +30,4 @@ export declare const GRID_COLUMN_MENU_SLOT_PROPS_PREMIUM: {
30
30
  displayOrder: number;
31
31
  };
32
32
  };
33
- declare const GridPremiumColumnMenu: React.ForwardRefExoticComponent<GridColumnMenuProps & React.RefAttributes<HTMLUListElement>>;
34
- export { GridPremiumColumnMenu };
33
+ export declare const GridPremiumColumnMenu: React.ForwardRefExoticComponent<GridColumnMenuProps & React.RefAttributes<HTMLUListElement>>;
@@ -9,7 +9,6 @@ exports.GridColumnMenuGroupingItem = GridColumnMenuGroupingItem;
9
9
  exports.GridPremiumColumnMenu = void 0;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
11
  var React = _interopRequireWildcard(require("react"));
12
- var _propTypes = _interopRequireDefault(require("prop-types"));
13
12
  var _xDataGridPro = require("@mui/x-data-grid-pro");
14
13
  var _GridColumnMenuAggregationItem = require("./GridColumnMenuAggregationItem");
15
14
  var _rowGrouping = require("../hooks/features/rowGrouping");
@@ -46,13 +45,4 @@ const GridPremiumColumnMenu = exports.GridPremiumColumnMenu = /*#__PURE__*/React
46
45
  defaultSlots: GRID_COLUMN_MENU_SLOTS_PREMIUM,
47
46
  defaultSlotProps: GRID_COLUMN_MENU_SLOT_PROPS_PREMIUM
48
47
  }));
49
- });
50
- process.env.NODE_ENV !== "production" ? GridPremiumColumnMenu.propTypes = {
51
- // ----------------------------- Warning --------------------------------
52
- // | These PropTypes are generated from the TypeScript type definitions |
53
- // | To update them edit the TypeScript types and run "yarn proptypes" |
54
- // ----------------------------------------------------------------------
55
- colDef: _propTypes.default.object.isRequired,
56
- hideMenu: _propTypes.default.func.isRequired,
57
- open: _propTypes.default.bool.isRequired
58
- } : void 0;
48
+ });
@@ -51,7 +51,7 @@ export const DataGridPremium = /*#__PURE__*/React.memo(DataGridPremiumRaw);
51
51
  process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
52
52
  // ----------------------------- Warning --------------------------------
53
53
  // | These PropTypes are generated from the TypeScript type definitions |
54
- // | To update them edit the TypeScript types and run "yarn proptypes" |
54
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
55
55
  // ----------------------------------------------------------------------
56
56
  /**
57
57
  * Aggregation functions available on the grid.
@@ -84,7 +84,7 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
84
84
  */
85
85
  'aria-labelledby': PropTypes.string,
86
86
  /**
87
- * If `true`, the Data Grid height is dynamic and follow the number of rows in the Data Grid.
87
+ * If `true`, the Data Grid height is dynamic and follows the number of rows in the Data Grid.
88
88
  * @default false
89
89
  */
90
90
  autoHeight: PropTypes.bool,
@@ -100,7 +100,7 @@ function GridColumnMenuAggregationItem(props) {
100
100
  process.env.NODE_ENV !== "production" ? GridColumnMenuAggregationItem.propTypes = {
101
101
  // ----------------------------- Warning --------------------------------
102
102
  // | These PropTypes are generated from the TypeScript type definitions |
103
- // | To update them edit the TypeScript types and run "yarn proptypes" |
103
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
104
104
  // ----------------------------------------------------------------------
105
105
  colDef: PropTypes.object.isRequired,
106
106
  onClick: PropTypes.func.isRequired
@@ -1,5 +1,4 @@
1
1
  import * as React from 'react';
2
- import PropTypes from 'prop-types';
3
2
  import MenuItem from '@mui/material/MenuItem';
4
3
  import ListItemIcon from '@mui/material/ListItemIcon';
5
4
  import ListItemText from '@mui/material/ListItemText';
@@ -9,7 +8,7 @@ import { gridRowGroupingSanitizedModelSelector } from '../hooks/features/rowGrou
9
8
  import { getRowGroupingCriteriaFromGroupingField, GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, isGroupingColumn } from '../hooks/features/rowGrouping/gridRowGroupingUtils';
10
9
  import { useGridRootProps } from '../hooks/utils/useGridRootProps';
11
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
- function GridColumnMenuRowGroupItem(props) {
11
+ export function GridColumnMenuRowGroupItem(props) {
13
12
  const {
14
13
  colDef,
15
14
  onClick
@@ -46,13 +45,4 @@ function GridColumnMenuRowGroupItem(props) {
46
45
  });
47
46
  }
48
47
  return renderUnGroupingMenuItem(getRowGroupingCriteriaFromGroupingField(colDef.field));
49
- }
50
- process.env.NODE_ENV !== "production" ? GridColumnMenuRowGroupItem.propTypes = {
51
- // ----------------------------- Warning --------------------------------
52
- // | These PropTypes are generated from the TypeScript type definitions |
53
- // | To update them edit the TypeScript types and run "yarn proptypes" |
54
- // ----------------------------------------------------------------------
55
- colDef: PropTypes.object.isRequired,
56
- onClick: PropTypes.func.isRequired
57
- } : void 0;
58
- export { GridColumnMenuRowGroupItem };
48
+ }
@@ -1,5 +1,4 @@
1
1
  import * as React from 'react';
2
- import PropTypes from 'prop-types';
3
2
  import MenuItem from '@mui/material/MenuItem';
4
3
  import ListItemIcon from '@mui/material/ListItemIcon';
5
4
  import ListItemText from '@mui/material/ListItemText';
@@ -8,7 +7,7 @@ import { useGridApiContext } from '../hooks/utils/useGridApiContext';
8
7
  import { gridRowGroupingSanitizedModelSelector } from '../hooks/features/rowGrouping/gridRowGroupingSelector';
9
8
  import { useGridRootProps } from '../hooks/utils/useGridRootProps';
10
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- function GridColumnMenuRowUngroupItem(props) {
10
+ export function GridColumnMenuRowUngroupItem(props) {
12
11
  const {
13
12
  colDef,
14
13
  onClick
@@ -51,13 +50,4 @@ function GridColumnMenuRowUngroupItem(props) {
51
50
  children: apiRef.current.getLocaleText('groupColumn')(name)
52
51
  })]
53
52
  });
54
- }
55
- process.env.NODE_ENV !== "production" ? GridColumnMenuRowUngroupItem.propTypes = {
56
- // ----------------------------- Warning --------------------------------
57
- // | These PropTypes are generated from the TypeScript type definitions |
58
- // | To update them edit the TypeScript types and run "yarn proptypes" |
59
- // ----------------------------------------------------------------------
60
- colDef: PropTypes.object.isRequired,
61
- onClick: PropTypes.func.isRequired
62
- } : void 0;
63
- export { GridColumnMenuRowUngroupItem };
53
+ }
@@ -25,13 +25,14 @@ function GridExcelExportMenuItem(props) {
25
25
  process.env.NODE_ENV !== "production" ? GridExcelExportMenuItem.propTypes = {
26
26
  // ----------------------------- Warning --------------------------------
27
27
  // | These PropTypes are generated from the TypeScript type definitions |
28
- // | To update them edit the TypeScript types and run "yarn proptypes" |
28
+ // | To update them edit the TypeScript types and run "pnpm proptypes" |
29
29
  // ----------------------------------------------------------------------
30
30
  hideMenu: PropTypes.func,
31
31
  options: PropTypes.shape({
32
32
  allColumns: PropTypes.bool,
33
33
  columnsStyles: PropTypes.object,
34
34
  disableToolbarButton: PropTypes.bool,
35
+ escapeFormulas: PropTypes.bool,
35
36
  exceljsPostProcess: PropTypes.func,
36
37
  exceljsPreProcess: PropTypes.func,
37
38
  fields: PropTypes.arrayOf(PropTypes.string),
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import PropTypes from 'prop-types';
4
3
  import { GridGenericColumnMenu, GRID_COLUMN_MENU_SLOTS, GRID_COLUMN_MENU_SLOT_PROPS } from '@mui/x-data-grid-pro';
5
4
  import { GridColumnMenuAggregationItem } from './GridColumnMenuAggregationItem';
6
5
  import { isGroupingColumn } from '../hooks/features/rowGrouping';
@@ -28,21 +27,11 @@ export const GRID_COLUMN_MENU_SLOT_PROPS_PREMIUM = _extends({}, GRID_COLUMN_MENU
28
27
  displayOrder: 27
29
28
  }
30
29
  });
31
- const GridPremiumColumnMenu = /*#__PURE__*/React.forwardRef(function GridPremiumColumnMenuSimple(props, ref) {
30
+ export const GridPremiumColumnMenu = /*#__PURE__*/React.forwardRef(function GridPremiumColumnMenuSimple(props, ref) {
32
31
  return /*#__PURE__*/_jsx(GridGenericColumnMenu, _extends({
33
32
  ref: ref
34
33
  }, props, {
35
34
  defaultSlots: GRID_COLUMN_MENU_SLOTS_PREMIUM,
36
35
  defaultSlotProps: GRID_COLUMN_MENU_SLOT_PROPS_PREMIUM
37
36
  }));
38
- });
39
- process.env.NODE_ENV !== "production" ? GridPremiumColumnMenu.propTypes = {
40
- // ----------------------------- Warning --------------------------------
41
- // | These PropTypes are generated from the TypeScript type definitions |
42
- // | To update them edit the TypeScript types and run "yarn proptypes" |
43
- // ----------------------------------------------------------------------
44
- colDef: PropTypes.object.isRequired,
45
- hideMenu: PropTypes.func.isRequired,
46
- open: PropTypes.bool.isRequired
47
- } : void 0;
48
- export { GridPremiumColumnMenu };
37
+ });
@@ -445,9 +445,12 @@ export const useGridCellSelection = (apiRef, props) => {
445
445
  if (fieldsMap[field]) {
446
446
  const cellParams = apiRef.current.getCellParams(rowId, field);
447
447
  cellData = serializeCellValue(cellParams, {
448
- delimiterCharacter: clipboardCopyCellDelimiter,
449
- ignoreValueFormatter,
450
- shouldAppendQuotes: false
448
+ csvOptions: {
449
+ delimiter: clipboardCopyCellDelimiter,
450
+ shouldAppendQuotes: false,
451
+ escapeFormulas: false
452
+ },
453
+ ignoreValueFormatter
451
454
  });
452
455
  } else {
453
456
  cellData = '';
@@ -1,6 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF } from '@mui/x-data-grid-pro';
3
- import { buildWarning, isObject, isSingleSelectColDef } from '@mui/x-data-grid/internals';
3
+ import { buildWarning, isObject, isSingleSelectColDef, gridHasColSpanSelector } from '@mui/x-data-grid/internals';
4
4
  const getExcelJs = async () => {
5
5
  const excelJsModule = await import('exceljs');
6
6
  return excelJsModule.default ?? excelJsModule;
@@ -23,22 +23,30 @@ const getFormattedValueOptions = (colDef, row, valueOptions, api) => {
23
23
  }
24
24
  return valueOptionsFormatted.map(option => typeof option === 'object' ? option.label : option);
25
25
  };
26
- export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
26
+ /**
27
+ * FIXME: This function mutates the colspan info, but colspan info assumes that the columns
28
+ * passed to it are always consistent. In this case, the exported columns may differ from the
29
+ * actual rendered columns.
30
+ * The caller of this function MUST call `resetColSpan()` before and after usage.
31
+ */
32
+ export const serializeRowUnsafe = (id, columns, apiRef, defaultValueOptionsFormulae, options) => {
27
33
  const row = {};
28
34
  const dataValidation = {};
29
35
  const mergedCells = [];
30
- const firstCellParams = api.getCellParams(id, columns[0].field);
36
+ const firstCellParams = apiRef.current.getCellParams(id, columns[0].field);
31
37
  const outlineLevel = firstCellParams.rowNode.depth;
32
-
33
- // `colSpan` is only calculated for rendered rows, so we need to calculate it during export for every row
34
- api.calculateColSpan({
35
- rowId: id,
36
- minFirstColumn: 0,
37
- maxLastColumn: columns.length,
38
- columns
39
- });
38
+ const hasColSpan = gridHasColSpanSelector(apiRef);
39
+ if (hasColSpan) {
40
+ // `colSpan` is only calculated for rendered rows, so we need to calculate it during export for every row
41
+ apiRef.current.calculateColSpan({
42
+ rowId: id,
43
+ minFirstColumn: 0,
44
+ maxLastColumn: columns.length,
45
+ columns
46
+ });
47
+ }
40
48
  columns.forEach((column, colIndex) => {
41
- const colSpanInfo = api.unstable_getCellColSpanInfo(id, colIndex);
49
+ const colSpanInfo = hasColSpan ? apiRef.current.unstable_getCellColSpanInfo(id, colIndex) : undefined;
42
50
  if (colSpanInfo && colSpanInfo.spannedByColSpan) {
43
51
  return;
44
52
  }
@@ -48,7 +56,8 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
48
56
  rightIndex: colIndex + colSpanInfo.cellProps.colSpan
49
57
  });
50
58
  }
51
- const cellParams = api.getCellParams(id, column.field);
59
+ const cellParams = apiRef.current.getCellParams(id, column.field);
60
+ let cellValue;
52
61
  switch (cellParams.colDef.type) {
53
62
  case 'singleSelect':
54
63
  {
@@ -61,7 +70,7 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
61
70
  row,
62
71
  field: cellParams.field
63
72
  });
64
- const formattedValueOptions = getFormattedValueOptions(castColumn, row, valueOptions, api);
73
+ const formattedValueOptions = getFormattedValueOptions(castColumn, row, valueOptions, apiRef.current);
65
74
  dataValidation[castColumn.field] = {
66
75
  type: 'list',
67
76
  allowBlank: true,
@@ -77,7 +86,7 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
77
86
  formulae: [address]
78
87
  };
79
88
  }
80
- const formattedValue = api.getCellParams(id, castColumn.field).formattedValue;
89
+ const formattedValue = apiRef.current.getCellParams(id, castColumn.field).formattedValue;
81
90
  if (process.env.NODE_ENV !== 'production') {
82
91
  if (String(cellParams.formattedValue) === '[object Object]') {
83
92
  warnInvalidFormattedValue();
@@ -92,7 +101,7 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
92
101
  }
93
102
  case 'boolean':
94
103
  case 'number':
95
- row[column.field] = api.getCellParams(id, column.field).value;
104
+ cellValue = apiRef.current.getCellParams(id, column.field).value;
96
105
  break;
97
106
  case 'date':
98
107
  case 'dateTime':
@@ -100,7 +109,7 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
100
109
  // Excel does not do any timezone conversion, so we create a date using UTC instead of local timezone
101
110
  // Solution from: https://github.com/exceljs/exceljs/issues/486#issuecomment-432557582
102
111
  // About Date.UTC(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC#exemples
103
- const value = api.getCellParams(id, column.field).value;
112
+ const value = apiRef.current.getCellParams(id, column.field).value;
104
113
  // value may be `undefined` in auto-generated grouping rows
105
114
  if (!value) {
106
115
  break;
@@ -112,7 +121,7 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
112
121
  case 'actions':
113
122
  break;
114
123
  default:
115
- row[column.field] = api.getCellParams(id, column.field).formattedValue;
124
+ cellValue = apiRef.current.getCellParams(id, column.field).formattedValue;
116
125
  if (process.env.NODE_ENV !== 'production') {
117
126
  if (String(cellParams.formattedValue) === '[object Object]') {
118
127
  warnInvalidFormattedValue();
@@ -120,6 +129,15 @@ export const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
120
129
  }
121
130
  break;
122
131
  }
132
+ if (typeof cellValue === 'string' && options.escapeFormulas) {
133
+ // See https://owasp.org/www-community/attacks/CSV_Injection
134
+ if (['=', '+', '-', '@', '\t', '\r'].includes(cellValue[0])) {
135
+ cellValue = `'${cellValue}`;
136
+ }
137
+ }
138
+ if (typeof cellValue !== 'undefined') {
139
+ row[column.field] = cellValue;
140
+ }
123
141
  });
124
142
  return {
125
143
  row,
@@ -266,7 +284,7 @@ async function createValueOptionsSheetIfNeeded(valueOptionsData, sheetName, work
266
284
  valueOptionsWorksheet.getColumn(field).values = values;
267
285
  });
268
286
  }
269
- export async function buildExcel(options, api) {
287
+ export async function buildExcel(options, apiRef) {
270
288
  const {
271
289
  columns,
272
290
  rowIds,
@@ -290,20 +308,22 @@ export async function buildExcel(options, api) {
290
308
  }
291
309
  if (includeColumnGroupsHeaders) {
292
310
  const columnGroupPaths = columns.reduce((acc, column) => {
293
- acc[column.field] = api.getColumnGroupPath(column.field);
311
+ acc[column.field] = apiRef.current.getColumnGroupPath(column.field);
294
312
  return acc;
295
313
  }, {});
296
- addColumnGroupingHeaders(worksheet, serializedColumns, columnGroupPaths, api.getAllGroupDetails());
314
+ addColumnGroupingHeaders(worksheet, serializedColumns, columnGroupPaths, apiRef.current.getAllGroupDetails());
297
315
  }
298
316
  if (includeHeaders) {
299
317
  worksheet.addRow(columns.map(column => column.headerName ?? column.field));
300
318
  }
301
- const valueOptionsData = await getDataForValueOptionsSheet(columns, valueOptionsSheetName, api);
319
+ const valueOptionsData = await getDataForValueOptionsSheet(columns, valueOptionsSheetName, apiRef.current);
302
320
  createValueOptionsSheetIfNeeded(valueOptionsData, valueOptionsSheetName, workbook);
321
+ apiRef.current.resetColSpan();
303
322
  rowIds.forEach(id => {
304
- const serializedRow = serializeRow(id, columns, api, valueOptionsData);
323
+ const serializedRow = serializeRowUnsafe(id, columns, apiRef, valueOptionsData, options);
305
324
  addSerializedRowToWorksheet(serializedRow, worksheet);
306
325
  });
326
+ apiRef.current.resetColSpan();
307
327
  if (exceljsPostProcess) {
308
328
  await exceljsPostProcess({
309
329
  workbook,
@@ -3,7 +3,7 @@ const _excluded = ["worker", "exceljsPostProcess", "exceljsPreProcess", "columns
3
3
  import * as React from 'react';
4
4
  import { useGridApiMethod, useGridLogger, useGridApiOptionHandler } from '@mui/x-data-grid';
5
5
  import { useGridRegisterPipeProcessor, exportAs, getColumnsToExport, defaultGetRowsToExport } from '@mui/x-data-grid/internals';
6
- import { buildExcel, getDataForValueOptionsSheet, serializeColumns, serializeRow } from './serializer/excelSerializer';
6
+ import { buildExcel, getDataForValueOptionsSheet, serializeColumns, serializeRowUnsafe } from './serializer/excelSerializer';
7
7
  import { GridExcelExportMenuItem } from '../../../components';
8
8
 
9
9
  /**
@@ -34,8 +34,9 @@ export const useGridExcelExport = (apiRef, props) => {
34
34
  valueOptionsSheetName: options?.valueOptionsSheetName || 'Options',
35
35
  columnsStyles: options?.columnsStyles,
36
36
  exceljsPreProcess: options?.exceljsPreProcess,
37
- exceljsPostProcess: options?.exceljsPostProcess
38
- }, apiRef.current);
37
+ exceljsPostProcess: options?.exceljsPostProcess,
38
+ escapeFormulas: options.escapeFormulas ?? true
39
+ }, apiRef);
39
40
  }, [logger, apiRef]);
40
41
  const exportDataAsExcel = React.useCallback(async (options = {}) => {
41
42
  const {
@@ -87,7 +88,11 @@ export const useGridExcelExport = (apiRef, props) => {
87
88
  });
88
89
  const valueOptionsData = await getDataForValueOptionsSheet(exportedColumns, valueOptionsSheetName, apiRef.current);
89
90
  const serializedColumns = serializeColumns(exportedColumns, options.columnsStyles || {});
90
- const serializedRows = exportedRowIds.map(id => serializeRow(id, exportedColumns, apiRef.current, valueOptionsData));
91
+ apiRef.current.resetColSpan();
92
+ const serializedRows = exportedRowIds.map(id => serializeRowUnsafe(id, exportedColumns, apiRef, valueOptionsData, {
93
+ escapeFormulas: options.escapeFormulas ?? true
94
+ }));
95
+ apiRef.current.resetColSpan();
91
96
  const columnGroupPaths = exportedColumns.reduce((acc, column) => {
92
97
  acc[column.field] = apiRef.current.getColumnGroupPath(column.field);
93
98
  return acc;
@@ -1,6 +1,6 @@
1
1
  import { ponyfillGlobal } from '@mui/utils';
2
2
  export const getReleaseInfo = () => {
3
- const releaseInfo = "MTcxNTg5NjgwMDAwMA==";
3
+ const releaseInfo = "MTcxNzAxNjQwMDAwMA==";
4
4
  if (process.env.NODE_ENV !== 'production') {
5
5
  // A simple hack to set the value in the test environment (has no build step).
6
6
  // eslint-disable-next-line no-useless-concat
@@ -455,9 +455,12 @@ const useGridCellSelection = (apiRef, props) => {
455
455
  if (fieldsMap[field]) {
456
456
  const cellParams = apiRef.current.getCellParams(rowId, field);
457
457
  cellData = (0, _internals.serializeCellValue)(cellParams, {
458
- delimiterCharacter: clipboardCopyCellDelimiter,
459
- ignoreValueFormatter,
460
- shouldAppendQuotes: false
458
+ csvOptions: {
459
+ delimiter: clipboardCopyCellDelimiter,
460
+ shouldAppendQuotes: false,
461
+ escapeFormulas: false
462
+ },
463
+ ignoreValueFormatter
461
464
  });
462
465
  } else {
463
466
  cellData = '';
@@ -1,7 +1,8 @@
1
+ /// <reference types="react" />
1
2
  import type * as Excel from 'exceljs';
2
3
  import { GridRowId, GridColDef } from '@mui/x-data-grid-pro';
3
4
  import { GridStateColDef, GridColumnGroupLookup } from '@mui/x-data-grid/internals';
4
- import { GridExceljsProcessInput, ColumnsStylesInterface, GridExcelExportOptions } from '../gridExcelExportInterface';
5
+ import { ColumnsStylesInterface, GridExcelExportOptions } from '../gridExcelExportInterface';
5
6
  import { GridPrivateApiPremium } from '../../../../models/gridApiPremium';
6
7
  interface SerializedRow {
7
8
  row: Record<string, undefined | number | boolean | string | Date>;
@@ -12,11 +13,17 @@ interface SerializedRow {
12
13
  rightIndex: number;
13
14
  }[];
14
15
  }
15
- export declare const serializeRow: (id: GridRowId, columns: GridStateColDef[], api: GridPrivateApiPremium, defaultValueOptionsFormulae: {
16
+ /**
17
+ * FIXME: This function mutates the colspan info, but colspan info assumes that the columns
18
+ * passed to it are always consistent. In this case, the exported columns may differ from the
19
+ * actual rendered columns.
20
+ * The caller of this function MUST call `resetColSpan()` before and after usage.
21
+ */
22
+ export declare const serializeRowUnsafe: (id: GridRowId, columns: GridStateColDef[], apiRef: React.MutableRefObject<GridPrivateApiPremium>, defaultValueOptionsFormulae: {
16
23
  [field: string]: {
17
24
  address: string;
18
25
  };
19
- }) => SerializedRow;
26
+ }, options: Pick<BuildExcelOptions, 'escapeFormulas'>) => SerializedRow;
20
27
  export declare const serializeColumn: (column: GridColDef, columnsStyles: ColumnsStylesInterface) => {
21
28
  key: string;
22
29
  headerText: string;
@@ -42,17 +49,12 @@ type ValueOptionsData = Record<string, {
42
49
  address: string;
43
50
  }>;
44
51
  export declare function getDataForValueOptionsSheet(columns: GridStateColDef[], valueOptionsSheetName: string, api: GridPrivateApiPremium): Promise<ValueOptionsData>;
45
- interface BuildExcelOptions {
52
+ interface BuildExcelOptions extends Pick<GridExcelExportOptions, 'exceljsPreProcess' | 'exceljsPostProcess'>, Pick<Required<GridExcelExportOptions>, 'valueOptionsSheetName' | 'includeHeaders' | 'includeColumnGroupsHeaders' | 'escapeFormulas'> {
46
53
  columns: GridStateColDef[];
47
54
  rowIds: GridRowId[];
48
- includeHeaders: boolean;
49
- includeColumnGroupsHeaders: boolean;
50
- valueOptionsSheetName: string;
51
- exceljsPreProcess?: (processInput: GridExceljsProcessInput) => Promise<void>;
52
- exceljsPostProcess?: (processInput: GridExceljsProcessInput) => Promise<void>;
53
55
  columnsStyles?: ColumnsStylesInterface;
54
56
  }
55
- export declare function buildExcel(options: BuildExcelOptions, api: GridPrivateApiPremium): Promise<Excel.Workbook>;
57
+ export declare function buildExcel(options: BuildExcelOptions, apiRef: React.MutableRefObject<GridPrivateApiPremium>): Promise<Excel.Workbook>;
56
58
  export interface ExcelExportInitEvent {
57
59
  serializedColumns: SerializedColumns;
58
60
  serializedRows: SerializedRow[];