@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
358 lines (299 loc) • 14.1 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useGridRowEditing = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _utils = require("@mui/material/utils");
var _useGridApiMethod = require("../../utils/useGridApiMethod");
var _gridEditRowModel = require("../../../models/gridEditRowModel");
var _useGridSelector = require("../../utils/useGridSelector");
var _gridColumnsSelector = require("../columns/gridColumnsSelector");
var _gridEditRowsSelector = require("./gridEditRowsSelector");
var _gridFocusStateSelector = require("../focus/gridFocusStateSelector");
var _useGridApiEventHandler = require("../../utils/useGridApiEventHandler");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const useGridRowEditing = (apiRef, props) => {
var _props$experimentalFe2, _props$experimentalFe4;
const focusTimeout = React.useRef(null);
const nextFocusedCell = React.useRef(null);
const columns = (0, _useGridSelector.useGridSelector)(apiRef, _gridColumnsSelector.gridColumnDefinitionsSelector);
const buildCallback = callback => (...args) => {
if (props.editMode === _gridEditRowModel.GridEditModes.Row) {
callback(...args);
}
};
const setRowMode = React.useCallback((id, mode) => {
if (mode === apiRef.current.getRowMode(id)) {
return;
}
apiRef.current.setState(state => {
const newEditRowsState = (0, _extends2.default)({}, state.editRows);
if (mode === _gridEditRowModel.GridRowModes.Edit) {
newEditRowsState[id] = {};
columns.forEach(column => {
const cellParams = apiRef.current.getCellParams(id, column.field);
if (cellParams.isEditable) {
newEditRowsState[id][column.field] = {
value: cellParams.value
};
}
});
} else {
delete newEditRowsState[id];
}
return (0, _extends2.default)({}, state, {
editRows: newEditRowsState
});
});
apiRef.current.forceUpdate();
}, [apiRef, columns]);
const getRowMode = React.useCallback(id => {
if (props.editMode === _gridEditRowModel.GridEditModes.Cell) {
return _gridEditRowModel.GridRowModes.View;
}
const editRowsState = (0, _gridEditRowsSelector.gridEditRowsStateSelector)(apiRef.current.state);
return editRowsState[id] ? _gridEditRowModel.GridRowModes.Edit : _gridEditRowModel.GridRowModes.View;
}, [apiRef, props.editMode]);
const commitRowChange = React.useCallback((id, event = {}) => {
var _props$experimentalFe;
if (props.editMode === _gridEditRowModel.GridEditModes.Cell) {
throw new Error(`MUI: You can't commit changes when the edit mode is 'cell'.`);
}
apiRef.current.unstable_runPendingEditCellValueMutation(id);
const model = apiRef.current.getEditRowsModel();
const editRowProps = model[id];
if (!editRowProps) {
throw new Error(`MUI: Row at id: ${id} is not being edited.`);
}
if ((_props$experimentalFe = props.experimentalFeatures) != null && _props$experimentalFe.preventCommitWhileValidating) {
const isValid = Object.keys(editRowProps).reduce((acc, field) => {
return acc && !editRowProps[field].isValidating && !editRowProps[field].error;
}, true);
if (!isValid) {
return false;
}
}
const hasFieldWithError = Object.values(editRowProps).some(value => !!value.error);
if (hasFieldWithError) {
return false;
}
const fieldsWithValidator = Object.keys(editRowProps).filter(field => {
const column = apiRef.current.getColumn(field);
return typeof column.preProcessEditCellProps === 'function';
});
if (fieldsWithValidator.length > 0) {
const row = apiRef.current.getRow(id);
const validatorErrors = fieldsWithValidator.map(async field => {
const column = apiRef.current.getColumn(field);
const newEditCellProps = await Promise.resolve(column.preProcessEditCellProps({
id,
row,
props: editRowProps[field]
}));
apiRef.current.unstable_setEditCellProps({
id,
field,
props: newEditCellProps
});
return newEditCellProps.error;
});
return Promise.all(validatorErrors).then(errors => {
if (errors.some(error => !!error)) {
return false;
}
apiRef.current.publishEvent('rowEditCommit', id, event);
return true;
});
}
apiRef.current.publishEvent('rowEditCommit', id, event);
return true;
}, [apiRef, props.editMode, (_props$experimentalFe2 = props.experimentalFeatures) == null ? void 0 : _props$experimentalFe2.preventCommitWhileValidating]);
const setRowEditingEditCellValue = React.useCallback(params => {
const model = apiRef.current.getEditRowsModel();
const editRow = model[params.id];
const row = apiRef.current.getRow(params.id);
let isValid = true;
return new Promise(resolve => {
Object.keys(editRow).forEach(async field => {
const column = apiRef.current.getColumn(field);
let editCellProps = field === params.field ? {
value: params.value
} : editRow[field]; // setEditCellProps runs the value parser and returns the updated props
editCellProps = apiRef.current.unstable_setEditCellProps({
id: params.id,
field,
props: (0, _extends2.default)({}, editCellProps, {
isValidating: true
})
});
if (column.preProcessEditCellProps) {
editCellProps = await Promise.resolve(column.preProcessEditCellProps({
id: params.id,
row,
props: (0, _extends2.default)({}, editCellProps, {
value: field === params.field ? apiRef.current.unstable_parseValue(params.id, field, params.value) : editCellProps.value
})
}));
}
if (editCellProps.error) {
isValid = false;
}
apiRef.current.unstable_setEditCellProps({
id: params.id,
field,
props: (0, _extends2.default)({}, editCellProps, {
isValidating: false
})
});
});
resolve(isValid);
});
}, [apiRef]);
const rowEditingApi = {
setRowMode,
getRowMode,
commitRowChange,
unstable_setRowEditingEditCellValue: setRowEditingEditCellValue
};
(0, _useGridApiMethod.useGridApiMethod)(apiRef, rowEditingApi, 'EditRowApi');
const handleCellKeyDown = React.useCallback(async (params, event) => {
// Wait until IME is settled for Asian languages like Japanese and Chinese
// TODO: `event.which` is depricated but this is a temporary workaround
if (event.which === 229) {
return;
}
const {
cellMode,
isEditable
} = params;
if (!isEditable) {
return;
}
const isEditMode = cellMode === _gridEditRowModel.GridCellModes.Edit;
const rowParams = apiRef.current.getRowParams(params.id);
if (isEditMode) {
if (event.key === 'Enter') {
var _props$experimentalFe3;
// TODO: check the return before firing 'rowEditStop'
// On cell editing, it won't exits the edit mode with error
const isValid = await apiRef.current.commitRowChange(params.id);
if (!isValid && (_props$experimentalFe3 = props.experimentalFeatures) != null && _props$experimentalFe3.preventCommitWhileValidating) {
return;
}
apiRef.current.publishEvent('rowEditStop', rowParams, event);
} else if (event.key === 'Escape') {
apiRef.current.publishEvent('rowEditStop', rowParams, event);
}
} else if (event.key === 'Enter') {
apiRef.current.publishEvent('rowEditStart', rowParams, event);
}
}, [apiRef, (_props$experimentalFe4 = props.experimentalFeatures) == null ? void 0 : _props$experimentalFe4.preventCommitWhileValidating]);
const handleCellDoubleClick = React.useCallback((params, event) => {
if (!params.isEditable) {
return;
}
const rowParams = apiRef.current.getRowParams(params.id);
apiRef.current.publishEvent('rowEditStart', rowParams, event);
}, [apiRef]);
const handleEditCellPropsChange = React.useCallback(params => {
const row = apiRef.current.getRow(params.id);
const model = apiRef.current.getEditRowsModel();
const editRow = model[params.id];
Object.keys(editRow).forEach(async field => {
const column = apiRef.current.getColumn(field);
if (column.preProcessEditCellProps) {
const editCellProps = field === params.field ? params.props : editRow[field];
const newEditCellProps = await Promise.resolve(column.preProcessEditCellProps({
id: params.id,
row,
props: editCellProps
}));
apiRef.current.unstable_setEditCellProps({
id: params.id,
field,
props: newEditCellProps
});
} else if (field === params.field) {
apiRef.current.unstable_setEditCellProps(params);
}
});
}, [apiRef]);
const handleRowEditStart = React.useCallback(params => {
apiRef.current.setRowMode(params.id, _gridEditRowModel.GridRowModes.Edit);
}, [apiRef]);
const handleRowEditStop = React.useCallback((params, event) => {
apiRef.current.setRowMode(params.id, _gridEditRowModel.GridRowModes.View);
if (event.key === 'Enter') {
apiRef.current.publishEvent('cellNavigationKeyDown', params, event);
}
}, [apiRef]);
const handleRowEditCommit = React.useCallback(id => {
const model = apiRef.current.getEditRowsModel();
const editRow = model[id];
if (!editRow) {
throw new Error(`MUI: Row at id: ${id} is not being edited.`);
}
const row = apiRef.current.getRow(id);
if (row) {
let rowUpdate = (0, _extends2.default)({}, row);
Object.keys(editRow).forEach(field => {
const column = apiRef.current.getColumn(field);
const value = editRow[field].value;
if (column.valueSetter) {
rowUpdate = column.valueSetter({
row: rowUpdate,
value
});
} else {
rowUpdate[field] = value;
}
});
apiRef.current.updateRows([rowUpdate]);
}
}, [apiRef]);
const handleCellFocusIn = React.useCallback(params => {
nextFocusedCell.current = params;
}, []);
const commitPropsAndExit = async (params, event) => {
if (params.cellMode === _gridEditRowModel.GridCellModes.View) {
return;
}
nextFocusedCell.current = null;
focusTimeout.current = setTimeout(async () => {
var _nextFocusedCell$curr;
if (((_nextFocusedCell$curr = nextFocusedCell.current) == null ? void 0 : _nextFocusedCell$curr.id) !== params.id) {
await apiRef.current.commitRowChange(params.id, event);
const rowParams = apiRef.current.getRowParams(params.id);
apiRef.current.publishEvent('rowEditStop', rowParams, event);
}
});
};
const handleCellFocusOut = (0, _utils.useEventCallback)((params, event) => {
commitPropsAndExit(params, event);
});
const handleColumnHeaderDragStart = (0, _utils.useEventCallback)(() => {
const cell = (0, _gridFocusStateSelector.gridFocusCellSelector)(apiRef);
if (!cell) {
return;
}
const params = apiRef.current.getCellParams(cell.id, cell.field);
commitPropsAndExit(params, {});
});
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellKeyDown', buildCallback(handleCellKeyDown));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellDoubleClick', buildCallback(handleCellDoubleClick));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'editCellPropsChange', buildCallback(handleEditCellPropsChange));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'rowEditStart', buildCallback(handleRowEditStart));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'rowEditStop', buildCallback(handleRowEditStop));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'rowEditCommit', buildCallback(handleRowEditCommit));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellFocusIn', buildCallback(handleCellFocusIn));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellFocusOut', buildCallback(handleCellFocusOut));
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'columnHeaderDragStart', buildCallback(handleColumnHeaderDragStart));
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'rowEditCommit', props.onRowEditCommit);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'rowEditStart', props.onRowEditStart);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'rowEditStop', props.onRowEditStop);
};
exports.useGridRowEditing = useGridRowEditing;