@mui/x-data-grid 5.14.0 → 5.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CHANGELOG.md +147 -5
  2. package/DataGrid/DataGrid.js +7 -1
  3. package/DataGrid/useDataGridProps.js +1 -0
  4. package/colDef/gridStringColDef.js +1 -1
  5. package/components/GridRow.js +5 -1
  6. package/components/base/GridOverlays.js +2 -2
  7. package/components/cell/GridEditInputCell.d.ts +2 -5
  8. package/components/cell/GridEditInputCell.js +13 -14
  9. package/components/cell/GridEditSingleSelectCell.d.ts +4 -0
  10. package/components/cell/GridEditSingleSelectCell.js +11 -4
  11. package/components/columnSelection/GridCellCheckboxRenderer.js +5 -0
  12. package/components/containers/GridRoot.js +4 -2
  13. package/components/toolbar/GridToolbarDensitySelector.js +13 -4
  14. package/components/toolbar/GridToolbarExportContainer.js +13 -2
  15. package/constants/envConstants.d.ts +1 -1
  16. package/constants/envConstants.js +2 -11
  17. package/constants/gridClasses.d.ts +16 -0
  18. package/constants/gridClasses.js +1 -1
  19. package/constants/localeTextConstants.js +1 -1
  20. package/hooks/features/dimensions/useGridDimensions.js +6 -1
  21. package/hooks/features/editRows/useGridCellEditing.new.d.ts +1 -1
  22. package/hooks/features/editRows/useGridCellEditing.new.js +26 -16
  23. package/hooks/features/editRows/useGridCellEditing.old.js +2 -2
  24. package/hooks/features/editRows/useGridEditing.new.d.ts +1 -1
  25. package/hooks/features/editRows/useGridEditing.new.js +4 -0
  26. package/hooks/features/editRows/useGridEditing.old.js +1 -1
  27. package/hooks/features/editRows/useGridRowEditing.new.d.ts +1 -1
  28. package/hooks/features/editRows/useGridRowEditing.new.js +16 -10
  29. package/hooks/features/export/utils.js +8 -1
  30. package/hooks/features/filter/gridFilterState.d.ts +12 -1
  31. package/hooks/features/filter/gridFilterUtils.d.ts +8 -5
  32. package/hooks/features/filter/gridFilterUtils.js +74 -43
  33. package/hooks/features/filter/useGridFilter.js +16 -3
  34. package/hooks/features/focus/useGridFocus.js +11 -6
  35. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.d.ts +1 -1
  36. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +42 -34
  37. package/hooks/features/pagination/useGridPageSize.js +3 -1
  38. package/hooks/features/rows/gridRowsSelector.d.ts +14 -0
  39. package/hooks/features/rows/gridRowsSelector.js +20 -1
  40. package/hooks/features/rows/gridRowsState.d.ts +8 -1
  41. package/hooks/features/rows/gridRowsUtils.d.ts +4 -0
  42. package/hooks/features/rows/gridRowsUtils.js +21 -3
  43. package/hooks/features/rows/index.d.ts +1 -1
  44. package/hooks/features/rows/index.js +1 -1
  45. package/hooks/features/rows/useGridRows.js +5 -2
  46. package/hooks/features/rows/useGridRowsMeta.js +19 -4
  47. package/hooks/features/rows/useGridRowsPreProcessors.js +2 -1
  48. package/hooks/features/scroll/useGridScroll.js +7 -2
  49. package/hooks/features/selection/useGridSelection.js +7 -3
  50. package/hooks/features/sorting/useGridSorting.js +8 -0
  51. package/hooks/features/statePersistence/gridStatePersistenceInterface.d.ts +3 -0
  52. package/hooks/features/virtualization/useGridVirtualScroller.d.ts +3 -1
  53. package/hooks/features/virtualization/useGridVirtualScroller.js +31 -16
  54. package/index.js +1 -1
  55. package/internals/index.d.ts +5 -1
  56. package/internals/index.js +4 -0
  57. package/legacy/DataGrid/DataGrid.js +7 -1
  58. package/legacy/DataGrid/useDataGridProps.js +1 -0
  59. package/legacy/colDef/gridStringColDef.js +1 -1
  60. package/legacy/components/GridRow.js +5 -1
  61. package/legacy/components/base/GridOverlays.js +2 -2
  62. package/legacy/components/cell/GridEditInputCell.js +13 -14
  63. package/legacy/components/cell/GridEditSingleSelectCell.js +11 -3
  64. package/legacy/components/columnSelection/GridCellCheckboxRenderer.js +5 -0
  65. package/legacy/components/containers/GridRoot.js +4 -2
  66. package/legacy/components/toolbar/GridToolbarDensitySelector.js +14 -5
  67. package/legacy/components/toolbar/GridToolbarExportContainer.js +15 -2
  68. package/legacy/constants/envConstants.js +2 -11
  69. package/legacy/constants/gridClasses.js +1 -1
  70. package/legacy/constants/localeTextConstants.js +1 -1
  71. package/legacy/hooks/features/dimensions/useGridDimensions.js +6 -1
  72. package/legacy/hooks/features/editRows/useGridCellEditing.new.js +27 -17
  73. package/legacy/hooks/features/editRows/useGridCellEditing.old.js +2 -2
  74. package/legacy/hooks/features/editRows/useGridEditing.new.js +4 -0
  75. package/legacy/hooks/features/editRows/useGridEditing.old.js +1 -1
  76. package/legacy/hooks/features/editRows/useGridRowEditing.new.js +16 -10
  77. package/legacy/hooks/features/export/utils.js +13 -1
  78. package/legacy/hooks/features/filter/gridFilterUtils.js +84 -55
  79. package/legacy/hooks/features/filter/useGridFilter.js +16 -3
  80. package/legacy/hooks/features/focus/useGridFocus.js +11 -6
  81. package/legacy/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +47 -34
  82. package/legacy/hooks/features/pagination/useGridPageSize.js +3 -1
  83. package/legacy/hooks/features/rows/gridRowsSelector.js +23 -0
  84. package/legacy/hooks/features/rows/gridRowsUtils.js +21 -3
  85. package/legacy/hooks/features/rows/index.js +1 -1
  86. package/legacy/hooks/features/rows/useGridRows.js +5 -2
  87. package/legacy/hooks/features/rows/useGridRowsMeta.js +19 -4
  88. package/legacy/hooks/features/rows/useGridRowsPreProcessors.js +2 -1
  89. package/legacy/hooks/features/scroll/useGridScroll.js +7 -2
  90. package/legacy/hooks/features/selection/useGridSelection.js +7 -3
  91. package/legacy/hooks/features/sorting/useGridSorting.js +8 -0
  92. package/legacy/hooks/features/virtualization/useGridVirtualScroller.js +32 -16
  93. package/legacy/index.js +1 -1
  94. package/legacy/internals/index.js +4 -0
  95. package/legacy/locales/arSD.js +1 -1
  96. package/legacy/locales/bgBG.js +1 -1
  97. package/legacy/locales/csCZ.js +1 -1
  98. package/legacy/locales/daDK.js +1 -1
  99. package/legacy/locales/deDE.js +9 -9
  100. package/legacy/locales/elGR.js +1 -1
  101. package/legacy/locales/esES.js +1 -1
  102. package/legacy/locales/faIR.js +1 -1
  103. package/legacy/locales/fiFI.js +1 -1
  104. package/legacy/locales/frFR.js +1 -1
  105. package/legacy/locales/heIL.js +1 -1
  106. package/legacy/locales/huHU.js +1 -1
  107. package/legacy/locales/itIT.js +15 -15
  108. package/legacy/locales/jaJP.js +3 -3
  109. package/legacy/locales/koKR.js +34 -30
  110. package/legacy/locales/nbNO.js +1 -1
  111. package/legacy/locales/nlNL.js +1 -1
  112. package/legacy/locales/plPL.js +1 -1
  113. package/legacy/locales/ptBR.js +1 -1
  114. package/legacy/locales/roRO.js +1 -1
  115. package/legacy/locales/ruRU.js +1 -1
  116. package/legacy/locales/skSK.js +1 -1
  117. package/legacy/locales/svSE.js +1 -1
  118. package/legacy/locales/trTR.js +1 -1
  119. package/legacy/locales/ukUA.js +1 -1
  120. package/legacy/locales/viVN.js +1 -1
  121. package/legacy/locales/zhCN.js +37 -33
  122. package/legacy/locales/zhTW.js +1 -1
  123. package/legacy/utils/keyboardUtils.js +8 -5
  124. package/locales/arSD.js +1 -1
  125. package/locales/bgBG.js +1 -1
  126. package/locales/csCZ.js +1 -1
  127. package/locales/daDK.js +1 -1
  128. package/locales/deDE.js +9 -9
  129. package/locales/elGR.js +1 -1
  130. package/locales/esES.js +1 -1
  131. package/locales/faIR.js +1 -1
  132. package/locales/fiFI.js +1 -1
  133. package/locales/frFR.js +1 -1
  134. package/locales/heIL.js +1 -1
  135. package/locales/huHU.js +1 -1
  136. package/locales/itIT.js +15 -15
  137. package/locales/jaJP.js +3 -3
  138. package/locales/koKR.js +30 -30
  139. package/locales/nbNO.js +1 -1
  140. package/locales/nlNL.js +1 -1
  141. package/locales/plPL.js +1 -1
  142. package/locales/ptBR.js +1 -1
  143. package/locales/roRO.js +1 -1
  144. package/locales/ruRU.js +1 -1
  145. package/locales/skSK.js +1 -1
  146. package/locales/svSE.js +1 -1
  147. package/locales/trTR.js +1 -1
  148. package/locales/ukUA.js +1 -1
  149. package/locales/viVN.js +1 -1
  150. package/locales/zhCN.js +33 -33
  151. package/locales/zhTW.js +1 -1
  152. package/models/gridRows.d.ts +5 -0
  153. package/models/props/DataGridProps.d.ts +8 -3
  154. package/modern/DataGrid/DataGrid.js +7 -1
  155. package/modern/DataGrid/useDataGridProps.js +1 -0
  156. package/modern/colDef/gridStringColDef.js +1 -1
  157. package/modern/components/GridRow.js +5 -1
  158. package/modern/components/base/GridOverlays.js +2 -2
  159. package/modern/components/cell/GridEditInputCell.js +13 -14
  160. package/modern/components/cell/GridEditSingleSelectCell.js +11 -4
  161. package/modern/components/columnSelection/GridCellCheckboxRenderer.js +5 -0
  162. package/modern/components/containers/GridRoot.js +4 -2
  163. package/modern/components/toolbar/GridToolbarDensitySelector.js +11 -4
  164. package/modern/components/toolbar/GridToolbarExportContainer.js +11 -2
  165. package/modern/constants/envConstants.js +2 -11
  166. package/modern/constants/gridClasses.js +1 -1
  167. package/modern/constants/localeTextConstants.js +1 -1
  168. package/modern/hooks/features/dimensions/useGridDimensions.js +6 -1
  169. package/modern/hooks/features/editRows/useGridCellEditing.new.js +24 -16
  170. package/modern/hooks/features/editRows/useGridCellEditing.old.js +2 -2
  171. package/modern/hooks/features/editRows/useGridEditing.new.js +4 -0
  172. package/modern/hooks/features/editRows/useGridEditing.old.js +1 -1
  173. package/modern/hooks/features/editRows/useGridRowEditing.new.js +16 -10
  174. package/modern/hooks/features/export/utils.js +6 -1
  175. package/modern/hooks/features/filter/gridFilterUtils.js +73 -42
  176. package/modern/hooks/features/filter/useGridFilter.js +16 -3
  177. package/modern/hooks/features/focus/useGridFocus.js +11 -6
  178. package/modern/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +42 -30
  179. package/modern/hooks/features/pagination/useGridPageSize.js +3 -1
  180. package/modern/hooks/features/rows/gridRowsSelector.js +18 -1
  181. package/modern/hooks/features/rows/gridRowsUtils.js +19 -3
  182. package/modern/hooks/features/rows/index.js +1 -1
  183. package/modern/hooks/features/rows/useGridRows.js +5 -2
  184. package/modern/hooks/features/rows/useGridRowsMeta.js +17 -4
  185. package/modern/hooks/features/rows/useGridRowsPreProcessors.js +2 -1
  186. package/modern/hooks/features/scroll/useGridScroll.js +5 -2
  187. package/modern/hooks/features/selection/useGridSelection.js +7 -1
  188. package/modern/hooks/features/sorting/useGridSorting.js +8 -0
  189. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +30 -15
  190. package/modern/index.js +1 -1
  191. package/modern/internals/index.js +4 -0
  192. package/modern/locales/arSD.js +1 -1
  193. package/modern/locales/bgBG.js +1 -1
  194. package/modern/locales/csCZ.js +1 -1
  195. package/modern/locales/daDK.js +1 -1
  196. package/modern/locales/deDE.js +9 -9
  197. package/modern/locales/elGR.js +1 -1
  198. package/modern/locales/esES.js +1 -1
  199. package/modern/locales/faIR.js +1 -1
  200. package/modern/locales/fiFI.js +1 -1
  201. package/modern/locales/frFR.js +1 -1
  202. package/modern/locales/heIL.js +1 -1
  203. package/modern/locales/huHU.js +1 -1
  204. package/modern/locales/itIT.js +15 -15
  205. package/modern/locales/jaJP.js +3 -3
  206. package/modern/locales/koKR.js +30 -30
  207. package/modern/locales/nbNO.js +1 -1
  208. package/modern/locales/nlNL.js +1 -1
  209. package/modern/locales/plPL.js +1 -1
  210. package/modern/locales/ptBR.js +1 -1
  211. package/modern/locales/roRO.js +1 -1
  212. package/modern/locales/ruRU.js +1 -1
  213. package/modern/locales/skSK.js +1 -1
  214. package/modern/locales/svSE.js +1 -1
  215. package/modern/locales/trTR.js +1 -1
  216. package/modern/locales/ukUA.js +1 -1
  217. package/modern/locales/viVN.js +1 -1
  218. package/modern/locales/zhCN.js +33 -33
  219. package/modern/locales/zhTW.js +1 -1
  220. package/modern/utils/keyboardUtils.js +7 -2
  221. package/node/DataGrid/DataGrid.js +7 -1
  222. package/node/DataGrid/useDataGridProps.js +1 -0
  223. package/node/colDef/gridStringColDef.js +1 -1
  224. package/node/components/GridRow.js +5 -1
  225. package/node/components/base/GridOverlays.js +2 -2
  226. package/node/components/cell/GridEditInputCell.js +15 -16
  227. package/node/components/cell/GridEditSingleSelectCell.js +10 -4
  228. package/node/components/columnSelection/GridCellCheckboxRenderer.js +5 -0
  229. package/node/components/containers/GridRoot.js +3 -1
  230. package/node/components/toolbar/GridToolbarDensitySelector.js +13 -4
  231. package/node/components/toolbar/GridToolbarExportContainer.js +13 -2
  232. package/node/constants/envConstants.js +2 -13
  233. package/node/constants/gridClasses.js +1 -1
  234. package/node/constants/localeTextConstants.js +1 -1
  235. package/node/hooks/features/dimensions/useGridDimensions.js +7 -1
  236. package/node/hooks/features/editRows/useGridCellEditing.new.js +26 -16
  237. package/node/hooks/features/editRows/useGridCellEditing.old.js +2 -2
  238. package/node/hooks/features/editRows/useGridEditing.new.js +4 -0
  239. package/node/hooks/features/editRows/useGridEditing.old.js +1 -1
  240. package/node/hooks/features/editRows/useGridRowEditing.new.js +16 -10
  241. package/node/hooks/features/export/utils.js +7 -0
  242. package/node/hooks/features/filter/gridFilterUtils.js +81 -47
  243. package/node/hooks/features/filter/useGridFilter.js +15 -2
  244. package/node/hooks/features/focus/useGridFocus.js +11 -6
  245. package/node/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +43 -34
  246. package/node/hooks/features/pagination/useGridPageSize.js +4 -1
  247. package/node/hooks/features/rows/gridRowsSelector.js +24 -2
  248. package/node/hooks/features/rows/gridRowsUtils.js +23 -2
  249. package/node/hooks/features/rows/index.js +70 -12
  250. package/node/hooks/features/rows/useGridRows.js +5 -2
  251. package/node/hooks/features/rows/useGridRowsMeta.js +20 -4
  252. package/node/hooks/features/rows/useGridRowsPreProcessors.js +2 -1
  253. package/node/hooks/features/scroll/useGridScroll.js +7 -1
  254. package/node/hooks/features/selection/useGridSelection.js +7 -3
  255. package/node/hooks/features/sorting/useGridSorting.js +8 -0
  256. package/node/hooks/features/virtualization/useGridVirtualScroller.js +31 -16
  257. package/node/index.js +1 -1
  258. package/node/internals/index.js +36 -0
  259. package/node/locales/arSD.js +1 -1
  260. package/node/locales/bgBG.js +1 -1
  261. package/node/locales/csCZ.js +1 -1
  262. package/node/locales/daDK.js +1 -1
  263. package/node/locales/deDE.js +9 -9
  264. package/node/locales/elGR.js +1 -1
  265. package/node/locales/esES.js +1 -1
  266. package/node/locales/faIR.js +1 -1
  267. package/node/locales/fiFI.js +1 -1
  268. package/node/locales/frFR.js +1 -1
  269. package/node/locales/heIL.js +1 -1
  270. package/node/locales/huHU.js +1 -1
  271. package/node/locales/itIT.js +15 -15
  272. package/node/locales/jaJP.js +3 -3
  273. package/node/locales/koKR.js +30 -30
  274. package/node/locales/nbNO.js +1 -1
  275. package/node/locales/nlNL.js +1 -1
  276. package/node/locales/plPL.js +1 -1
  277. package/node/locales/ptBR.js +1 -1
  278. package/node/locales/roRO.js +1 -1
  279. package/node/locales/ruRU.js +1 -1
  280. package/node/locales/skSK.js +1 -1
  281. package/node/locales/svSE.js +1 -1
  282. package/node/locales/trTR.js +1 -1
  283. package/node/locales/ukUA.js +1 -1
  284. package/node/locales/viVN.js +1 -1
  285. package/node/locales/zhCN.js +33 -33
  286. package/node/locales/zhTW.js +1 -1
  287. package/node/utils/keyboardUtils.js +10 -4
  288. package/package.json +1 -1
  289. package/utils/keyboardUtils.d.ts +2 -2
  290. package/utils/keyboardUtils.js +7 -2
@@ -1,8 +1,8 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { GridLinkOperator } from '../../../models';
3
+ import { getDefaultGridFilterModel } from './gridFilterState';
3
4
  import { buildWarning } from '../../../utils/warning';
4
5
  import { gridColumnFieldsSelector, gridColumnLookupSelector } from '../columns';
5
- import { gridRowTreeSelector } from '../rows/gridRowsSelector';
6
6
 
7
7
  /**
8
8
  * Adds default values to the optional fields of a filter items.
@@ -78,10 +78,8 @@ export const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFil
78
78
 
79
79
  export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
80
80
  const {
81
- items,
82
- linkOperator = GridLinkOperator.And
81
+ items
83
82
  } = filterModel;
84
- const tree = gridRowTreeSelector(apiRef);
85
83
 
86
84
  const getFilterCallbackFromItem = filterItem => {
87
85
  if (!filterItem.columnField || !filterItem.operatorValue) {
@@ -143,18 +141,12 @@ export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
143
141
  }
144
142
 
145
143
  return (rowId, shouldApplyFilter) => {
146
- if (tree[rowId].position === 'footer') {
147
- return true;
148
- }
149
-
150
- const filteredAppliers = shouldApplyFilter ? appliers.filter(applier => shouldApplyFilter(applier.item.columnField)) : appliers; // Return `false` as soon as we have a failing filter
151
-
152
- if (linkOperator === GridLinkOperator.And) {
153
- return filteredAppliers.every(applier => applier.fn(rowId));
154
- } // Return `true` as soon as we have a passing filter
155
-
156
-
157
- return filteredAppliers.some(applier => applier.fn(rowId));
144
+ const resultPerItemId = {};
145
+ const filteredAppliers = shouldApplyFilter ? appliers.filter(applier => shouldApplyFilter(applier.item.columnField)) : appliers;
146
+ filteredAppliers.forEach(applier => {
147
+ resultPerItemId[applier.item.id] = applier.fn(rowId);
148
+ });
149
+ return resultPerItemId;
158
150
  };
159
151
  };
160
152
  /**
@@ -166,8 +158,7 @@ export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
166
158
 
167
159
  export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
168
160
  const {
169
- quickFilterValues = [],
170
- quickFilterLogicOperator = GridLinkOperator.And
161
+ quickFilterValues = []
171
162
  } = filterModel;
172
163
 
173
164
  if (quickFilterValues.length === 0) {
@@ -188,6 +179,11 @@ export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
188
179
  }); // If some value does not have an applier we ignore them
189
180
 
190
181
  const sanitizedQuickFilterValues = quickFilterValues.filter((value, index) => Object.keys(appliersPerColumnField).some(field => appliersPerColumnField[field][index] != null));
182
+
183
+ if (sanitizedQuickFilterValues.length === 0) {
184
+ return null;
185
+ }
186
+
191
187
  return (rowId, shouldApplyFilter) => {
192
188
  const usedCellParams = {};
193
189
  const columnsFieldsToFilter = [];
@@ -196,43 +192,78 @@ export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
196
192
  usedCellParams[columnField] = apiRef.current.getCellParams(rowId, columnField);
197
193
  columnsFieldsToFilter.push(columnField);
198
194
  }
199
- }); // Return `false` as soon as we have a quick filter value that does not match any column
200
-
201
- if (quickFilterLogicOperator === GridLinkOperator.And) {
202
- return sanitizedQuickFilterValues.every((value, index) => columnsFieldsToFilter.some(field => {
195
+ });
196
+ const quickFilterValueResult = {};
197
+ sanitizedQuickFilterValues.forEach((value, index) => {
198
+ const isPassing = columnsFieldsToFilter.some(field => {
203
199
  if (appliersPerColumnField[field][index] == null) {
204
200
  return false;
205
201
  }
206
202
 
207
203
  return appliersPerColumnField[field][index]?.(usedCellParams[field]);
208
- }));
209
- } // Return `true` as soon as we have have a quick filter value that match any column
210
-
211
-
212
- return sanitizedQuickFilterValues.some((value, index) => columnsFieldsToFilter.some(field => {
213
- if (appliersPerColumnField[field][index] == null) {
214
- return false;
215
- }
216
-
217
- return appliersPerColumnField[field][index]?.(usedCellParams[field]);
218
- }));
204
+ });
205
+ quickFilterValueResult[value] = isPassing;
206
+ });
207
+ return quickFilterValueResult;
219
208
  };
220
209
  };
221
210
  export const buildAggregatedFilterApplier = (filterModel, apiRef) => {
222
211
  const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(filterModel, apiRef);
223
212
  const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(filterModel, apiRef);
213
+ return (rowId, shouldApplyFilter) => ({
214
+ passingFilterItems: isRowMatchingFilterItems && isRowMatchingFilterItems(rowId, shouldApplyFilter),
215
+ passingQuickFilterValues: isRowMatchingQuickFilter && isRowMatchingQuickFilter(rowId, shouldApplyFilter)
216
+ });
217
+ };
218
+ export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel) => {
219
+ const cleanedAllFilterItemResults = allFilterItemResults.filter(result => result != null);
220
+ const cleanedAllQuickFilterResults = allQuickFilterResults.filter(result => result != null); // Defaultize operators
224
221
 
225
- if (isRowMatchingFilterItems == null && isRowMatchingQuickFilter == null) {
226
- return null;
227
- }
222
+ const quickFilterLogicOperator = filterModel.quickFilterLogicOperator ?? getDefaultGridFilterModel().quickFilterLogicOperator;
223
+ const linkOperator = filterModel.linkOperator ?? getDefaultGridFilterModel().linkOperator; // get result for filter items model
224
+
225
+ if (cleanedAllFilterItemResults.length > 0) {
226
+ // Return true if the item pass with one of the rows
227
+ const filterItemPredicate = item => {
228
+ return cleanedAllFilterItemResults.some(filterItemResult => filterItemResult[item.id]);
229
+ };
230
+
231
+ if (linkOperator === GridLinkOperator.And) {
232
+ const passesAllFilters = filterModel.items.every(filterItemPredicate);
233
+
234
+ if (!passesAllFilters) {
235
+ return false;
236
+ }
237
+ } else {
238
+ const passesSomeFilters = filterModel.items.some(filterItemPredicate);
239
+
240
+ if (!passesSomeFilters) {
241
+ return false;
242
+ }
243
+ }
244
+ } // get result for quick filter model
228
245
 
229
- if (isRowMatchingFilterItems == null) {
230
- return isRowMatchingQuickFilter;
231
- }
232
246
 
233
- if (isRowMatchingQuickFilter == null) {
234
- return isRowMatchingFilterItems;
247
+ if (cleanedAllQuickFilterResults.length > 0 && filterModel.quickFilterValues != null) {
248
+ // Return true if the item pass with one of the rows
249
+ const quickFilterValuePredicate = value => {
250
+ return cleanedAllQuickFilterResults.some(quickFilterValueResult => quickFilterValueResult[value]);
251
+ };
252
+
253
+ if (quickFilterLogicOperator === GridLinkOperator.And) {
254
+ const passesAllQuickFilterValues = filterModel.quickFilterValues.every(quickFilterValuePredicate);
255
+
256
+ if (!passesAllQuickFilterValues) {
257
+ return false;
258
+ }
259
+ } else {
260
+ const passesSomeQuickFilterValues = filterModel.quickFilterValues.some(quickFilterValuePredicate);
261
+
262
+ if (!passesSomeQuickFilterValues) {
263
+ return false;
264
+ }
265
+ }
235
266
  }
236
267
 
237
- return (rowId, shouldApplyFilter) => isRowMatchingFilterItems(rowId, shouldApplyFilter) && isRowMatchingQuickFilter(rowId, shouldApplyFilter);
268
+ return true;
238
269
  };
@@ -12,7 +12,7 @@ import { useFirstRender } from '../../utils/useFirstRender';
12
12
  import { gridRowIdsSelector } from '../rows';
13
13
  import { useGridRegisterPipeProcessor } from '../../core/pipeProcessing';
14
14
  import { GRID_DEFAULT_STRATEGY, useGridRegisterStrategyProcessor } from '../../core/strategyProcessing';
15
- import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem } from './gridFilterUtils';
15
+ import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem, passFilterLogic } from './gridFilterUtils';
16
16
  import { isDeepEqual } from '../../../utils/utils';
17
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
18
  export const filterStateInitializer = (state, props, apiRef) => {
@@ -45,7 +45,8 @@ export const useGridFilter = (apiRef, props) => {
45
45
  const filterModel = gridFilterModelSelector(state, apiRef.current.instanceId);
46
46
  const isRowMatchingFilters = props.filterMode === GridFeatureModeConstant.client ? buildAggregatedFilterApplier(filterModel, apiRef) : null;
47
47
  const filteringResult = apiRef.current.unstable_applyStrategyProcessor('filtering', {
48
- isRowMatchingFilters
48
+ isRowMatchingFilters,
49
+ filterModel: filterModel ?? getDefaultGridFilterModel()
49
50
  });
50
51
  return _extends({}, state, {
51
52
  filter: _extends({}, state.filter, filteringResult)
@@ -249,7 +250,19 @@ export const useGridFilter = (apiRef, props) => {
249
250
 
250
251
  for (let i = 0; i < rowIds.length; i += 1) {
251
252
  const rowId = rowIds[i];
252
- filteredRowsLookup[rowId] = params.isRowMatchingFilters(rowId);
253
+ let isRowPassing;
254
+
255
+ if (typeof rowId === 'string' && rowId.startsWith('auto-generated-group-footer')) {
256
+ isRowPassing = true;
257
+ } else {
258
+ const {
259
+ passingFilterItems,
260
+ passingQuickFilterValues
261
+ } = params.isRowMatchingFilters(rowId);
262
+ isRowPassing = passFilterLogic([passingFilterItems], [passingQuickFilterValues], params.filterModel);
263
+ }
264
+
265
+ filteredRowsLookup[rowId] = isRowPassing;
253
266
  }
254
267
 
255
268
  return {
@@ -60,6 +60,12 @@ export const useGridFocus = (apiRef, props) => {
60
60
  return;
61
61
  }
62
62
 
63
+ if (focusedCell) {
64
+ // There's a focused cell but another cell was clicked
65
+ // Publishes an event to notify that the focus was lost
66
+ apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field));
67
+ }
68
+
63
69
  apiRef.current.publishEvent('cellFocusIn', apiRef.current.getCellParams(id, field));
64
70
  }, [apiRef, logger]);
65
71
  const setColumnHeaderFocus = React.useCallback((field, event = {}) => {
@@ -191,11 +197,7 @@ export const useGridFocus = (apiRef, props) => {
191
197
 
192
198
  if (!apiRef.current.getRow(focusedCell.id)) {
193
199
  return;
194
- } // There's a focused cell but another cell was clicked
195
- // Publishes an event to notify that the focus was lost
196
-
197
-
198
- apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field), event);
200
+ }
199
201
 
200
202
  if (cellParams) {
201
203
  apiRef.current.setCellFocus(cellParams.id, cellParams.field);
@@ -206,7 +208,10 @@ export const useGridFocus = (apiRef, props) => {
206
208
  columnHeader: null
207
209
  }
208
210
  }));
209
- apiRef.current.forceUpdate();
211
+ apiRef.current.forceUpdate(); // There's a focused cell but another element (not a cell) was clicked
212
+ // Publishes an event to notify that the focus was lost
213
+
214
+ apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field), event);
210
215
  }
211
216
  }, [apiRef]);
212
217
  const handleCellModeChange = React.useCallback(params => {
@@ -9,6 +9,12 @@ import { gridClasses } from '../../../constants/gridClasses';
9
9
  import { GridCellModes } from '../../../models/gridEditRowModel';
10
10
  import { isNavigationKey } from '../../../utils/keyboardUtils';
11
11
  import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from '../../../constants/gridDetailPanelToggleField';
12
+ import { gridPinnedRowsSelector } from '../rows/gridRowsSelector';
13
+
14
+ function enrichPageRowsWithPinnedRows(apiRef, rows) {
15
+ const pinnedRows = gridPinnedRowsSelector(apiRef) || {};
16
+ return [...(pinnedRows.top || []), ...rows, ...(pinnedRows.bottom || [])];
17
+ }
12
18
  /**
13
19
  * @requires useGridSorting (method) - can be after
14
20
  * @requires useGridFilter (state) - can be after
@@ -19,18 +25,19 @@ import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from '../../../constants/gridDetailPan
19
25
  * @requires useGridColumnSpanning (method) - can be after
20
26
  */
21
27
 
28
+
22
29
  export const useGridKeyboardNavigation = (apiRef, props) => {
23
30
  const logger = useGridLogger(apiRef, 'useGridKeyboardNavigation');
24
- const currentPage = useGridVisibleRows(apiRef, props);
31
+ const initialCurrentPageRows = useGridVisibleRows(apiRef, props).rows;
32
+ const currentPageRows = React.useMemo(() => enrichPageRowsWithPinnedRows(apiRef, initialCurrentPageRows), [apiRef, initialCurrentPageRows]);
25
33
  /**
26
34
  * @param {number} colIndex Index of the column to focus
27
35
  * @param {number} rowIndex index of the row to focus
28
36
  * @param {string} closestColumnToUse Which closest column cell to use when the cell is spanned by `colSpan`.
29
37
  */
30
38
 
31
- const goToCell = React.useCallback((colIndex, rowIndex, closestColumnToUse = 'left') => {
39
+ const goToCell = React.useCallback((colIndex, rowId, closestColumnToUse = 'left') => {
32
40
  const visibleSortedRows = gridVisibleSortedRowEntriesSelector(apiRef);
33
- const rowId = visibleSortedRows[rowIndex]?.id;
34
41
  const nextCellColSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowId, colIndex);
35
42
 
36
43
  if (nextCellColSpanInfo && nextCellColSpanInfo.spannedByColSpan) {
@@ -39,12 +46,15 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
39
46
  } else if (closestColumnToUse === 'right') {
40
47
  colIndex = nextCellColSpanInfo.rightVisibleCellIndex;
41
48
  }
42
- }
49
+ } // `scrollToIndexes` requires a rowIndex relative to all visible rows.
50
+ // Those rows do not include pinned rows, but pinned rows do not need scroll anyway.
43
51
 
44
- logger.debug(`Navigating to cell row ${rowIndex}, col ${colIndex}`);
52
+
53
+ const rowIndexRelativeToAllRows = visibleSortedRows.findIndex(row => row.id === rowId);
54
+ logger.debug(`Navigating to cell row ${rowIndexRelativeToAllRows}, col ${colIndex}`);
45
55
  apiRef.current.scrollToIndexes({
46
56
  colIndex,
47
- rowIndex
57
+ rowIndex: rowIndexRelativeToAllRows
48
58
  });
49
59
  const field = apiRef.current.getVisibleColumns()[colIndex].field;
50
60
  apiRef.current.setCellFocus(rowId, field);
@@ -57,19 +67,21 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
57
67
  const field = apiRef.current.getVisibleColumns()[colIndex].field;
58
68
  apiRef.current.setColumnHeaderFocus(field, event);
59
69
  }, [apiRef, logger]);
70
+ const getRowIdFromIndex = React.useCallback(rowIndex => {
71
+ return currentPageRows[rowIndex].id;
72
+ }, [currentPageRows]);
60
73
  const handleCellNavigationKeyDown = React.useCallback((params, event) => {
61
74
  const dimensions = apiRef.current.getRootDimensions();
62
75
 
63
- if (!currentPage.range || !dimensions) {
76
+ if (currentPageRows.length === 0 || !dimensions) {
64
77
  return;
65
78
  }
66
79
 
67
80
  const viewportPageSize = apiRef.current.unstable_getViewportPageSize();
68
- const visibleSortedRows = gridVisibleSortedRowEntriesSelector(apiRef);
69
81
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
70
- const rowIndexBefore = visibleSortedRows.findIndex(row => row.id === params.id);
71
- const firstRowIndexInPage = currentPage.range.firstRowIndex;
72
- const lastRowIndexInPage = currentPage.range.lastRowIndex;
82
+ const rowIndexBefore = currentPageRows.findIndex(row => row.id === params.id);
83
+ const firstRowIndexInPage = 0;
84
+ const lastRowIndexInPage = currentPageRows.length - 1;
73
85
  const firstColIndex = 0;
74
86
  const lastColIndex = gridVisibleColumnDefinitionsSelector(apiRef).length - 1;
75
87
  let shouldPreventDefault = true;
@@ -80,7 +92,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
80
92
  {
81
93
  // "Enter" is only triggered by the row / cell editing feature
82
94
  if (rowIndexBefore < lastRowIndexInPage) {
83
- goToCell(colIndexBefore, rowIndexBefore + 1);
95
+ goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore + 1));
84
96
  }
85
97
 
86
98
  break;
@@ -89,7 +101,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
89
101
  case 'ArrowUp':
90
102
  {
91
103
  if (rowIndexBefore > firstRowIndexInPage) {
92
- goToCell(colIndexBefore, rowIndexBefore - 1);
104
+ goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore - 1));
93
105
  } else {
94
106
  goToHeader(colIndexBefore, event);
95
107
  }
@@ -100,7 +112,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
100
112
  case 'ArrowRight':
101
113
  {
102
114
  if (colIndexBefore < lastColIndex) {
103
- goToCell(colIndexBefore + 1, rowIndexBefore, 'right');
115
+ goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right');
104
116
  }
105
117
 
106
118
  break;
@@ -109,7 +121,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
109
121
  case 'ArrowLeft':
110
122
  {
111
123
  if (colIndexBefore > firstColIndex) {
112
- goToCell(colIndexBefore - 1, rowIndexBefore);
124
+ goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore));
113
125
  }
114
126
 
115
127
  break;
@@ -119,9 +131,9 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
119
131
  {
120
132
  // "Tab" is only triggered by the row / cell editing feature
121
133
  if (event.shiftKey && colIndexBefore > firstColIndex) {
122
- goToCell(colIndexBefore - 1, rowIndexBefore, 'left');
134
+ goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore), 'left');
123
135
  } else if (!event.shiftKey && colIndexBefore < lastColIndex) {
124
- goToCell(colIndexBefore + 1, rowIndexBefore, 'right');
136
+ goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right');
125
137
  }
126
138
 
127
139
  break;
@@ -142,7 +154,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
142
154
  }
143
155
 
144
156
  if (!event.shiftKey && rowIndexBefore < lastRowIndexInPage) {
145
- goToCell(colIndexBefore, Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage));
157
+ goToCell(colIndexBefore, getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)));
146
158
  }
147
159
 
148
160
  break;
@@ -151,7 +163,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
151
163
  case 'PageDown':
152
164
  {
153
165
  if (rowIndexBefore < lastRowIndexInPage) {
154
- goToCell(colIndexBefore, Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage));
166
+ goToCell(colIndexBefore, getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)));
155
167
  }
156
168
 
157
169
  break;
@@ -163,7 +175,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
163
175
  const nextRowIndex = Math.max(rowIndexBefore - viewportPageSize, firstRowIndexInPage);
164
176
 
165
177
  if (nextRowIndex !== rowIndexBefore && nextRowIndex >= firstRowIndexInPage) {
166
- goToCell(colIndexBefore, nextRowIndex);
178
+ goToCell(colIndexBefore, getRowIdFromIndex(nextRowIndex));
167
179
  } else {
168
180
  goToHeader(colIndexBefore, event);
169
181
  }
@@ -174,9 +186,9 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
174
186
  case 'Home':
175
187
  {
176
188
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
177
- goToCell(firstColIndex, firstRowIndexInPage);
189
+ goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage));
178
190
  } else {
179
- goToCell(firstColIndex, rowIndexBefore);
191
+ goToCell(firstColIndex, getRowIdFromIndex(rowIndexBefore));
180
192
  }
181
193
 
182
194
  break;
@@ -185,9 +197,9 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
185
197
  case 'End':
186
198
  {
187
199
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
188
- goToCell(lastColIndex, lastRowIndexInPage);
200
+ goToCell(lastColIndex, getRowIdFromIndex(lastRowIndexInPage));
189
201
  } else {
190
- goToCell(lastColIndex, rowIndexBefore);
202
+ goToCell(lastColIndex, getRowIdFromIndex(rowIndexBefore));
191
203
  }
192
204
 
193
205
  break;
@@ -202,7 +214,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
202
214
  if (shouldPreventDefault) {
203
215
  event.preventDefault();
204
216
  }
205
- }, [apiRef, currentPage, goToCell, goToHeader]);
217
+ }, [apiRef, currentPageRows, goToCell, goToHeader, getRowIdFromIndex]);
206
218
  const handleColumnHeaderKeyDown = React.useCallback((params, event) => {
207
219
  const headerTitleNode = event.currentTarget.querySelector(`.${gridClasses.columnHeaderTitleContainerContent}`);
208
220
  const isFromInsideContent = !!headerTitleNode && headerTitleNode.contains(event.target);
@@ -221,8 +233,8 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
221
233
 
222
234
  const viewportPageSize = apiRef.current.unstable_getViewportPageSize();
223
235
  const colIndexBefore = params.field ? apiRef.current.getColumnIndex(params.field) : 0;
224
- const firstRowIndexInPage = currentPage.range?.firstRowIndex ?? null;
225
- const lastRowIndexInPage = currentPage.range?.lastRowIndex ?? null;
236
+ const firstRowIndexInPage = 0;
237
+ const lastRowIndexInPage = currentPageRows.length - 1;
226
238
  const firstColIndex = 0;
227
239
  const lastColIndex = gridVisibleColumnDefinitionsSelector(apiRef).length - 1;
228
240
  let shouldPreventDefault = true;
@@ -231,7 +243,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
231
243
  case 'ArrowDown':
232
244
  {
233
245
  if (firstRowIndexInPage !== null) {
234
- goToCell(colIndexBefore, firstRowIndexInPage);
246
+ goToCell(colIndexBefore, getRowIdFromIndex(firstRowIndexInPage));
235
247
  }
236
248
 
237
249
  break;
@@ -258,7 +270,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
258
270
  case 'PageDown':
259
271
  {
260
272
  if (firstRowIndexInPage !== null && lastRowIndexInPage !== null) {
261
- goToCell(colIndexBefore, Math.min(firstRowIndexInPage + viewportPageSize, lastRowIndexInPage));
273
+ goToCell(colIndexBefore, getRowIdFromIndex(Math.min(firstRowIndexInPage + viewportPageSize, lastRowIndexInPage)));
262
274
  }
263
275
 
264
276
  break;
@@ -300,7 +312,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
300
312
  if (shouldPreventDefault) {
301
313
  event.preventDefault();
302
314
  }
303
- }, [apiRef, currentPage, goToCell, goToHeader]);
315
+ }, [apiRef, currentPageRows, goToCell, goToHeader, getRowIdFromIndex]);
304
316
  const handleCellKeyDown = React.useCallback((params, event) => {
305
317
  // Ignore portal
306
318
  if (!event.currentTarget.contains(event.target)) {
@@ -4,6 +4,7 @@ import { useGridLogger, useGridApiMethod, useGridApiEventHandler, useGridSelecto
4
4
  import { gridPageSizeSelector } from './gridPaginationSelector';
5
5
  import { gridDensityRowHeightSelector } from '../density';
6
6
  import { useGridRegisterPipeProcessor } from '../../core/pipeProcessing';
7
+ import { calculatePinnedRowsHeight } from '../rows/gridRowsUtils';
7
8
  export const defaultPageSize = autoPageSize => autoPageSize ? 0 : 100;
8
9
 
9
10
  const mergeStateWithPageSize = pageSize => state => _extends({}, state, {
@@ -91,7 +92,8 @@ export const useGridPageSize = (apiRef, props) => {
91
92
  return;
92
93
  }
93
94
 
94
- const maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / rowHeight);
95
+ const pinnedRowsHeight = calculatePinnedRowsHeight(apiRef);
96
+ const maximumPageSizeWithoutScrollBar = Math.floor((dimensions.viewportInnerSize.height - pinnedRowsHeight.top - pinnedRowsHeight.bottom) / rowHeight);
95
97
  apiRef.current.setPageSize(maximumPageSizeWithoutScrollBar);
96
98
  }, [apiRef, props.autoPageSize, rowHeight]);
97
99
  useGridApiEventHandler(apiRef, 'viewportInnerSizeChange', handleUpdateAutoPageSize);
@@ -8,4 +8,21 @@ export const gridRowsIdToIdLookupSelector = createSelector(gridRowsStateSelector
8
8
  export const gridRowTreeSelector = createSelector(gridRowsStateSelector, rows => rows.tree);
9
9
  export const gridRowGroupingNameSelector = createSelector(gridRowsStateSelector, rows => rows.groupingName);
10
10
  export const gridRowTreeDepthSelector = createSelector(gridRowsStateSelector, rows => rows.treeDepth);
11
- export const gridRowIdsSelector = createSelector(gridRowsStateSelector, rows => rows.ids);
11
+ export const gridRowIdsSelector = createSelector(gridRowsStateSelector, rows => rows.ids);
12
+ /**
13
+ * @ignore - do not document.
14
+ */
15
+
16
+ export const gridAdditionalRowGroupsSelector = createSelector(gridRowsStateSelector, rows => rows?.additionalRowGroups);
17
+ /**
18
+ * @ignore - do not document.
19
+ */
20
+
21
+ export const gridPinnedRowsSelector = createSelector(gridAdditionalRowGroupsSelector, additionalRowGroups => additionalRowGroups?.pinnedRows);
22
+ /**
23
+ * @ignore - do not document.
24
+ */
25
+
26
+ export const gridPinnedRowsCountSelector = createSelector(gridPinnedRowsSelector, pinnedRows => {
27
+ return (pinnedRows?.top?.length || 0) + (pinnedRows?.bottom?.length || 0);
28
+ });
@@ -1,13 +1,14 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["rowsBeforePartialUpdates"];
4
-
4
+ import { gridPinnedRowsSelector } from './gridRowsSelector';
5
5
  /**
6
6
  * A helper function to check if the id provided is valid.
7
7
  * @param {GridRowId} id Id as [[GridRowId]].
8
8
  * @param {GridRowModel | Partial<GridRowModel>} row Row as [[GridRowModel]].
9
9
  * @param {string} detailErrorMessage A custom error message to display for invalid IDs
10
10
  */
11
+
11
12
  export function checkGridRowIdIsValid(id, row, detailErrorMessage = 'A row was provided without id in the rows prop:') {
12
13
  if (id == null) {
13
14
  throw new Error(['MUI: The data grid component requires all rows to have a unique `id` property.', 'Alternatively, you can use the `getRowId` prop to specify a custom id for each row.', detailErrorMessage, JSON.stringify(row)].join('\n'));
@@ -55,7 +56,7 @@ export const getRowsStateFromCache = ({
55
56
  previousTree
56
57
  }));
57
58
  const processedGroupingResponse = apiRef.current.unstable_applyPipeProcessors('hydrateRows', groupingResponse);
58
- const dataTopLevelRowCount = processedGroupingResponse.treeDepth === 1 ? processedGroupingResponse.ids.length : Object.values(processedGroupingResponse.tree).filter(node => node.parent == null).length;
59
+ const dataTopLevelRowCount = processedGroupingResponse.treeDepth === 1 ? processedGroupingResponse.ids.length : Object.values(processedGroupingResponse.tree).filter(node => node.parent == null && !node.isPinned).length;
59
60
  return _extends({}, processedGroupingResponse, {
60
61
  groupingResponseBeforeRowHydration: groupingResponse,
61
62
  loading: loadingProp,
@@ -84,4 +85,19 @@ export const getTreeNodeDescendants = (tree, parentId, skipAutoGeneratedRows) =>
84
85
  }
85
86
 
86
87
  return validDescendants;
87
- };
88
+ };
89
+ export function calculatePinnedRowsHeight(apiRef) {
90
+ const pinnedRows = gridPinnedRowsSelector(apiRef);
91
+ const topPinnedRowsHeight = pinnedRows?.top?.reduce((acc, value) => {
92
+ acc += apiRef.current.unstable_getRowHeight(value.id);
93
+ return acc;
94
+ }, 0) || 0;
95
+ const bottomPinnedRowsHeight = pinnedRows?.bottom?.reduce((acc, value) => {
96
+ acc += apiRef.current.unstable_getRowHeight(value.id);
97
+ return acc;
98
+ }, 0) || 0;
99
+ return {
100
+ top: topPinnedRowsHeight,
101
+ bottom: bottomPinnedRowsHeight
102
+ };
103
+ }
@@ -1,4 +1,4 @@
1
1
  export * from './gridRowsMetaSelector';
2
2
  export * from './gridRowsMetaState';
3
- export * from './gridRowsSelector';
3
+ export { gridRowsStateSelector, gridRowCountSelector, gridRowsLoadingSelector, gridTopLevelRowCountSelector, gridRowsLookupSelector, gridRowsIdToIdLookupSelector, gridRowTreeSelector, gridRowGroupingNameSelector, gridRowTreeDepthSelector, gridRowIdsSelector } from './gridRowsSelector';
4
4
  export { checkGridRowIdIsValid } from './gridRowsUtils';
@@ -26,8 +26,11 @@ export const rowsStateInitializer = (state, props, apiRef) => {
26
26
  };
27
27
  export const useGridRows = (apiRef, props) => {
28
28
  if (process.env.NODE_ENV !== 'production') {
29
- // Freeze rows for immutability
30
- Object.freeze(props.rows);
29
+ try {
30
+ // Freeze the `rows` prop so developers have a fast failure if they try to use Array.prototype.push().
31
+ Object.freeze(props.rows);
32
+ } catch (error) {// Sometimes, it's impossible to freeze, so we give up on it.
33
+ }
31
34
  }
32
35
 
33
36
  const logger = useGridLogger(apiRef, 'useGridRows');
@@ -9,6 +9,7 @@ import { gridFilterStateSelector } from '../filter/gridFilterSelector';
9
9
  import { gridPaginationSelector } from '../pagination/gridPaginationSelector';
10
10
  import { gridSortingStateSelector } from '../sorting/gridSortingSelector';
11
11
  import { useGridRegisterPipeApplier } from '../../core/pipeProcessing';
12
+ import { gridPinnedRowsSelector } from './gridRowsSelector';
12
13
  export const rowsMetaStateInitializer = state => _extends({}, state, {
13
14
  rowsMeta: {
14
15
  currentPageTotalHeight: 0,
@@ -35,13 +36,12 @@ export const useGridRowsMeta = (apiRef, props) => {
35
36
  const paginationState = useGridSelector(apiRef, gridPaginationSelector);
36
37
  const sortingState = useGridSelector(apiRef, gridSortingStateSelector);
37
38
  const currentPage = useGridVisibleRows(apiRef, props);
39
+ const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector);
38
40
  const hydrateRowsMeta = React.useCallback(() => {
39
41
  hasRowWithAutoHeight.current = false;
40
42
  const densityFactor = gridDensityFactorSelector(apiRef.current.state, apiRef.current.instanceId);
41
- const positions = [];
42
- const currentPageTotalHeight = currentPage.rows.reduce((acc, row) => {
43
- positions.push(acc);
44
43
 
44
+ const calculateRowProcessedSizes = row => {
45
45
  if (!rowsHeightLookup.current[row.id]) {
46
46
  rowsHeightLookup.current[row.id] = {
47
47
  sizes: {
@@ -111,9 +111,22 @@ export const useGridRowsMeta = (apiRef, props) => {
111
111
 
112
112
  const processedSizes = apiRef.current.unstable_applyPipeProcessors('rowHeight', initialHeights, row);
113
113
  rowsHeightLookup.current[row.id].sizes = processedSizes;
114
+ return processedSizes;
115
+ };
116
+
117
+ const positions = [];
118
+ const currentPageTotalHeight = currentPage.rows.reduce((acc, row) => {
119
+ positions.push(acc);
120
+ const processedSizes = calculateRowProcessedSizes(row);
114
121
  const finalRowHeight = Object.values(processedSizes).reduce((acc2, value) => acc2 + value, 0);
115
122
  return acc + finalRowHeight;
116
123
  }, 0);
124
+ pinnedRows?.top?.forEach(row => {
125
+ calculateRowProcessedSizes(row);
126
+ });
127
+ pinnedRows?.bottom?.forEach(row => {
128
+ calculateRowProcessedSizes(row);
129
+ });
117
130
  apiRef.current.setState(state => {
118
131
  return _extends({}, state, {
119
132
  rowsMeta: {
@@ -129,7 +142,7 @@ export const useGridRowsMeta = (apiRef, props) => {
129
142
  }
130
143
 
131
144
  apiRef.current.forceUpdate();
132
- }, [apiRef, currentPage.rows, rowHeightFromDensity, getRowHeightProp, getRowSpacing, getEstimatedRowHeight]);
145
+ }, [apiRef, currentPage.rows, rowHeightFromDensity, getRowHeightProp, getRowSpacing, getEstimatedRowHeight, pinnedRows]);
133
146
  const getRowHeight = React.useCallback(rowId => {
134
147
  const height = rowsHeightLookup.current[rowId];
135
148
  return height ? height.sizes.base : rowHeightFromDensity;
@@ -11,7 +11,8 @@ const flatRowTreeCreationMethod = ({
11
11
  for (let i = 0; i < ids.length; i += 1) {
12
12
  const rowId = ids[i];
13
13
 
14
- if (previousTree && previousTree[rowId] && previousTree[rowId].depth === 0 && previousTree[rowId].parent == null) {
14
+ if (previousTree && previousTree[rowId] && previousTree[rowId].depth === 0 && previousTree[rowId].parent == null && // pinned row can be unpinned
15
+ !previousTree[rowId].isPinned) {
15
16
  tree[rowId] = previousTree[rowId];
16
17
  } else {
17
18
  tree[rowId] = {