@mui/x-data-grid-premium
Version:
The Premium plan edition of the MUI X Data Grid Components.
376 lines (355 loc) • 12 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createRowEditHistoryHandler = exports.createDefaultHistoryHandlers = exports.createClipboardPasteHistoryHandler = exports.createCellEditHistoryHandler = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _isDeepEqual = require("@mui/x-internals/isDeepEqual");
var _xDataGridPro = require("@mui/x-data-grid-pro");
/**
* Create the default handler for cellEditStop events.
*/
const createCellEditHistoryHandler = apiRef => {
return {
store: params => {
const {
id,
field
} = params;
const oldValue = apiRef.current.getRow(id)[field];
const newValue = apiRef.current.getRowWithUpdatedValues(id, field)[field];
if ((0, _isDeepEqual.isDeepEqual)(oldValue, newValue)) {
return null;
}
return {
id,
field,
oldValue,
newValue
};
},
validate: (data, direction) => {
const {
id,
field,
oldValue,
newValue
} = data;
// Check if column is visible
if (!(0, _xDataGridPro.gridVisibleColumnFieldsSelector)(apiRef).includes(field)) {
return false;
}
const {
rowIdToIndexMap,
range
} = (0, _xDataGridPro.gridVisibleRowsSelector)(apiRef);
// Check if row is in the current page
const rowIndex = rowIdToIndexMap.get(id);
if (rowIndex === undefined || rowIndex < (range?.firstRowIndex || 0) || rowIndex > (range?.lastRowIndex || rowIndex)) {
return false;
}
const row = apiRef.current.getRow(id);
// Check if the value hasn't changed externally
const currentValue = row[field];
const expectedValue = direction === 'undo' ? newValue : oldValue;
if (!(0, _isDeepEqual.isDeepEqual)(currentValue, expectedValue)) {
return false;
}
return true;
},
undo: async data => {
const {
id,
field,
oldValue
} = data;
if (apiRef.current.state.props.dataSource?.updateRow) {
const row = apiRef.current.getRow(id);
await apiRef.current.dataSource.editRow({
rowId: id,
updatedRow: (0, _extends2.default)({}, row, {
[field]: oldValue
}),
previousRow: row
});
} else {
apiRef.current.updateRows([{
id,
[field]: oldValue
}]);
}
// Use `requestAnimationFrame` to ensure all undo updates are applied
requestAnimationFrame(() => {
apiRef.current.setCellFocus(id, field);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(id),
colIndex: apiRef.current.getColumnIndex(field)
});
});
},
redo: async data => {
const {
id,
field,
newValue
} = data;
if (apiRef.current.state.props.dataSource?.updateRow) {
const row = apiRef.current.getRow(id);
await apiRef.current.dataSource.editRow({
rowId: id,
updatedRow: (0, _extends2.default)({}, row, {
[field]: newValue
}),
previousRow: row
});
} else {
apiRef.current.updateRows([{
id,
[field]: newValue
}]);
}
// Use `requestAnimationFrame` to ensure all redo updates are applied
requestAnimationFrame(() => {
apiRef.current.setCellFocus(id, field);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(id),
colIndex: apiRef.current.getColumnIndex(field)
});
});
}
};
};
/**
* Create the default handler for rowEditStop events.
*/
exports.createCellEditHistoryHandler = createCellEditHistoryHandler;
const createRowEditHistoryHandler = apiRef => {
return {
store: params => {
const {
id
} = params;
const oldRow = apiRef.current.getRow(id) || {};
const newRow = apiRef.current.getRowWithUpdatedValues(id, '');
if ((0, _isDeepEqual.isDeepEqual)(oldRow, newRow)) {
return null;
}
return {
id,
oldRow,
newRow
};
},
validate: (data, direction) => {
const {
id,
oldRow,
newRow
} = data;
const {
rowIdToIndexMap,
range
} = (0, _xDataGridPro.gridVisibleRowsSelector)(apiRef);
// Check if row is in the current page
const rowIndex = rowIdToIndexMap.get(id);
if (rowIndex === undefined || rowIndex < (range?.firstRowIndex || 0) || rowIndex > (range?.lastRowIndex || rowIndex)) {
return false;
}
const row = apiRef.current.getRow(id);
// Check if modified fields haven't changed externally
const expectedRow = direction === 'undo' ? newRow : oldRow;
for (const field of Object.keys(expectedRow)) {
if (!(0, _isDeepEqual.isDeepEqual)(row[field], expectedRow[field])) {
return false;
}
}
return true;
},
undo: async data => {
const {
id,
oldRow,
newRow
} = data;
if (apiRef.current.state.props.dataSource?.updateRow) {
await apiRef.current.dataSource.editRow({
rowId: id,
updatedRow: oldRow,
previousRow: newRow
});
} else {
apiRef.current.updateRows([(0, _extends2.default)({
id
}, oldRow)]);
}
// Use `requestAnimationFrame` to ensure all undo updates are applied
requestAnimationFrame(() => {
apiRef.current.setCellFocus(id, Object.keys(oldRow)[0]);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(id),
colIndex: 0
});
});
},
redo: async data => {
const {
id,
oldRow,
newRow
} = data;
if (apiRef.current.state.props.dataSource?.updateRow) {
await apiRef.current.dataSource.editRow({
rowId: id,
updatedRow: newRow,
previousRow: oldRow
});
} else {
apiRef.current.updateRows([(0, _extends2.default)({
id
}, newRow)]);
}
// Use `requestAnimationFrame` to ensure all redo updates are applied
requestAnimationFrame(() => {
apiRef.current.setCellFocus(id, Object.keys(newRow)[0]);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(id),
colIndex: 0
});
});
}
};
};
/**
* Create the default handler for clipboardPasteEnd events.
*/
exports.createRowEditHistoryHandler = createRowEditHistoryHandler;
const createClipboardPasteHistoryHandler = apiRef => {
return {
store: params => params,
validate: (data, direction) => {
const {
oldRows,
newRows
} = data;
const updatedRowIds = Array.from(newRows.keys());
// Check if any rows were updated
if (updatedRowIds.length === 0) {
return false;
}
// Check if all affected rows are still visible and have expected values
const {
rowIdToIndexMap,
range
} = (0, _xDataGridPro.gridVisibleRowsSelector)(apiRef);
for (let i = 0; i < updatedRowIds.length; i += 1) {
const rowId = updatedRowIds[i];
const rowIndex = rowIdToIndexMap.get(rowId);
if (rowIndex === undefined || rowIndex < (range?.firstRowIndex || 0) || rowIndex > (range?.lastRowIndex || rowIndex)) {
return false;
}
const row = apiRef.current.getRow(rowId);
if (!row) {
return false;
}
const expectedRow = direction === 'undo' ? newRows.get(rowId) : oldRows.get(rowId);
// Check if the row values match what we expect
for (const field of Object.keys(expectedRow)) {
if (!(0, _isDeepEqual.isDeepEqual)(row[field], expectedRow[field])) {
return false;
}
}
}
return true;
},
undo: async data => {
const {
oldRows,
newRows
} = data;
const oldRowsValues = Array.from(oldRows.values());
const visibleColumns = apiRef.current.getVisibleColumns();
// Focus the first affected cell
if (oldRowsValues.length > 0 && visibleColumns.length > 0) {
const columnOrder = (0, _xDataGridPro.gridColumnFieldsSelector)(apiRef);
// Since we undo, oldRowData is the new data that will be set and newRowData is the current row
const firstOldRow = Array.from(newRows.values())[0];
const [firstNewRowId, firstNewRow] = Array.from(oldRows.entries())[0];
let differentFieldIndex = columnOrder.length - 1;
// Find the first field that is different to set the focus on
for (let i = 0; i < columnOrder.length; i += 1) {
const field = columnOrder[i];
if (!(0, _isDeepEqual.isDeepEqual)(firstOldRow[field], firstNewRow[field])) {
differentFieldIndex = i;
break;
}
}
// Restore all rows to their original state
apiRef.current.updateRows(oldRowsValues);
if (differentFieldIndex >= 0) {
requestAnimationFrame(() => {
apiRef.current.setCellFocus(firstNewRowId, columnOrder[differentFieldIndex]);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(firstNewRowId),
colIndex: differentFieldIndex
});
});
}
}
},
redo: async data => {
const {
oldRows,
newRows
} = data;
const newRowsValues = Array.from(newRows.values());
const visibleColumns = apiRef.current.getVisibleColumns();
// Focus the first affected cell
if (newRowsValues.length > 0 && visibleColumns.length > 0) {
const columnOrder = (0, _xDataGridPro.gridColumnFieldsSelector)(apiRef);
const firstOldRow = Array.from(oldRows.values())[0];
const [firstNewRowId, firstNewRow] = Array.from(newRows.entries())[0];
let differentFieldIndex = columnOrder.length - 1;
// Find the first field that is different to set the focus on
for (let i = 0; i < columnOrder.length; i += 1) {
const field = columnOrder[i];
if (!(0, _isDeepEqual.isDeepEqual)(firstOldRow[field], firstNewRow[field])) {
differentFieldIndex = i;
break;
}
}
// Restore all rows to the pasted state
apiRef.current.updateRows(newRowsValues);
if (differentFieldIndex >= 0) {
requestAnimationFrame(() => {
apiRef.current.setCellFocus(firstNewRowId, columnOrder[differentFieldIndex]);
apiRef.current.scrollToIndexes({
rowIndex: apiRef.current.getRowIndexRelativeToVisibleRows(firstNewRowId),
colIndex: differentFieldIndex
});
});
}
}
}
};
};
/**
* Create the default history events map.
*/
exports.createClipboardPasteHistoryHandler = createClipboardPasteHistoryHandler;
const createDefaultHistoryHandlers = (apiRef, props) => {
const handlers = {};
const canHaveEditing = props.isCellEditable || props.columns.some(col => col.editable);
if (!canHaveEditing) {
return handlers;
}
if (!props.dataSource || props.dataSource.updateRow) {
handlers.cellEditStop = createCellEditHistoryHandler(apiRef);
handlers.rowEditStop = createRowEditHistoryHandler(apiRef);
}
if (!props.dataSource) {
handlers.clipboardPasteEnd = createClipboardPasteHistoryHandler(apiRef);
}
return handlers;
};
exports.createDefaultHistoryHandlers = createDefaultHistoryHandlers;