@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
411 lines (348 loc) • 14.2 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _extends from "@babel/runtime/helpers/esm/extends";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import * as React from 'react';
import { useEventCallback } from '@mui/material/utils';
import { useGridApiOptionHandler, useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
import { GridCellModes, GridEditModes } from '../../../models/gridEditRowModel';
import { isKeyboardEvent, isPrintableKey, isCellEnterEditModeKeys, isCellExitEditModeKeys, isCellEditCommitKeys, isDeleteKeys } from '../../../utils/keyboardUtils';
import { useGridLogger } from '../../utils/useGridLogger';
import { gridFocusCellSelector } from '../focus/gridFocusStateSelector';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { gridEditRowsStateSelector } from './gridEditRowsSelector';
function isPromise(promise) {
return typeof promise.then === 'function';
}
export var useCellEditing = function useCellEditing(apiRef, props) {
var _props$experimentalFe2;
var logger = useGridLogger(apiRef, 'useGridEditRows');
var buildCallback = function buildCallback(callback) {
return function () {
if (props.editMode === GridEditModes.Cell) {
callback.apply(void 0, arguments);
}
};
};
var setCellMode = React.useCallback(function (id, field, mode) {
if (apiRef.current.getCellMode(id, field) === mode) {
return;
}
logger.debug("Switching cell id: ".concat(id, " field: ").concat(field, " to mode: ").concat(mode));
apiRef.current.setState(function (state) {
var newEditRowsState = _extends({}, state.editRows);
newEditRowsState[id] = _extends({}, newEditRowsState[id]);
if (mode === GridCellModes.Edit) {
newEditRowsState[id][field] = {
value: apiRef.current.getCellValue(id, field)
};
} else {
delete newEditRowsState[id][field];
if (!Object.keys(newEditRowsState[id]).length) {
delete newEditRowsState[id];
}
}
return _extends({}, state, {
editRows: newEditRowsState
});
});
apiRef.current.forceUpdate();
apiRef.current.publishEvent('cellModeChange', apiRef.current.getCellParams(id, field));
}, [apiRef, logger]);
var getCellMode = React.useCallback(function (id, field) {
var editRowsState = gridEditRowsStateSelector(apiRef.current.state);
var isEditing = editRowsState[id] && editRowsState[id][field];
return isEditing ? GridCellModes.Edit : GridCellModes.View;
}, [apiRef]); // TODO v6: it should always return a promise
var commitCellChange = React.useCallback(function (params) {
var _props$experimentalFe;
var event = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var id = params.id,
field = params.field;
apiRef.current.unstable_runPendingEditCellValueMutation(id, field);
var model = apiRef.current.getEditRowsModel();
if (!model[id] || !model[id][field]) {
throw new Error("MUI: Cell at id: ".concat(id, " and field: ").concat(field, " is not in edit mode."));
}
var editCellProps = model[id][field];
var column = apiRef.current.getColumn(field);
var row = apiRef.current.getRow(id);
if ((_props$experimentalFe = props.experimentalFeatures) != null && _props$experimentalFe.preventCommitWhileValidating) {
var cellProps = model[id][field];
if (cellProps.isValidating || cellProps.error) {
return false;
}
}
var commitParams = _extends({}, params, {
value: editCellProps.value
});
var hasError = !!editCellProps.error;
if (!hasError && typeof column.preProcessEditCellProps === 'function') {
var result = column.preProcessEditCellProps({
id: id,
row: row,
props: editCellProps
});
if (isPromise(result)) {
return result.then(function (newEditCellProps) {
apiRef.current.unstable_setEditCellProps({
id: id,
field: field,
props: newEditCellProps
});
if (newEditCellProps.error) {
return false;
}
apiRef.current.publishEvent('cellEditCommit', commitParams, event);
return true;
});
}
apiRef.current.unstable_setEditCellProps({
id: id,
field: field,
props: result
});
hasError = !!result.error;
}
if (!hasError) {
apiRef.current.publishEvent('cellEditCommit', commitParams, event);
return true;
}
return false;
}, [apiRef, (_props$experimentalFe2 = props.experimentalFeatures) == null ? void 0 : _props$experimentalFe2.preventCommitWhileValidating]);
var setCellEditingEditCellValue = React.useCallback(function (params) {
var column = apiRef.current.getColumn(params.field);
var row = apiRef.current.getRow(params.id);
return new Promise(function (resolve) {
var newEditCellProps = {
value: params.value
};
var model = apiRef.current.getEditRowsModel();
var editCellProps = model[params.id][params.field];
if (typeof column.preProcessEditCellProps !== 'function') {
apiRef.current.unstable_setEditCellProps(_extends({}, params, {
props: newEditCellProps
}));
resolve(true);
return;
} // setEditCellProps runs the value parser and returns the updated props
newEditCellProps = apiRef.current.unstable_setEditCellProps(_extends({}, params, {
props: _extends({}, editCellProps, {
isValidating: true
})
}));
Promise.resolve(column.preProcessEditCellProps({
id: params.id,
row: row,
props: _extends({}, newEditCellProps, {
value: apiRef.current.unstable_parseValue(params.id, params.field, params.value)
})
})).then(function (newEditCellPropsProcessed) {
apiRef.current.unstable_setEditCellProps(_extends({}, params, {
props: _extends({}, newEditCellPropsProcessed, {
isValidating: false
})
}));
resolve(!newEditCellPropsProcessed.error);
});
});
}, [apiRef]);
var cellEditingApi = {
setCellMode: setCellMode,
getCellMode: getCellMode,
commitCellChange: commitCellChange,
unstable_setCellEditingEditCellValue: setCellEditingEditCellValue
};
useGridApiMethod(apiRef, cellEditingApi, 'EditRowApi');
var handleCellKeyDown = React.useCallback( /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(params, event) {
var id, field, cellMode, isEditable, isEditMode, isModifierKeyPressed, commitParams, isValid;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!(event.which === 229)) {
_context.next = 2;
break;
}
return _context.abrupt("return");
case 2:
id = params.id, field = params.field, cellMode = params.cellMode, isEditable = params.isEditable;
if (isEditable) {
_context.next = 5;
break;
}
return _context.abrupt("return");
case 5:
isEditMode = cellMode === GridCellModes.Edit;
isModifierKeyPressed = event.ctrlKey || event.metaKey || event.altKey;
if (!isEditMode && isCellEnterEditModeKeys(event) && !isModifierKeyPressed && !(event.key === ' ' && event.shiftKey)) {
apiRef.current.publishEvent('cellEditStart', params, event);
}
if (!isEditMode && isDeleteKeys(event.key)) {
apiRef.current.setEditCellValue({
id: id,
field: field,
value: ''
});
apiRef.current.commitCellChange({
id: id,
field: field
}, event);
apiRef.current.publishEvent('cellEditStop', params, event);
}
if (!(isEditMode && isCellEditCommitKeys(event.key))) {
_context.next = 16;
break;
}
commitParams = {
id: id,
field: field
};
_context.next = 13;
return apiRef.current.commitCellChange(commitParams, event);
case 13:
isValid = _context.sent;
if (isValid) {
_context.next = 16;
break;
}
return _context.abrupt("return");
case 16:
if (isEditMode && isCellExitEditModeKeys(event.key)) {
apiRef.current.publishEvent('cellEditStop', params, event);
}
case 17:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function (_x, _x2) {
return _ref.apply(this, arguments);
};
}(), [apiRef]);
var handleCellDoubleClick = React.useCallback(function (params, event) {
if (!params.isEditable) {
return;
}
apiRef.current.publishEvent('cellEditStart', params, event);
}, [apiRef]);
var commitPropsAndExit = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(params, event) {
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (!(params.cellMode === GridCellModes.View)) {
_context2.next = 2;
break;
}
return _context2.abrupt("return");
case 2:
_context2.next = 4;
return apiRef.current.commitCellChange(params, event);
case 4:
apiRef.current.publishEvent('cellEditStop', params, event);
case 5:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return function commitPropsAndExit(_x3, _x4) {
return _ref2.apply(this, arguments);
};
}();
var handleCellFocusOut = useEventCallback(function (params, event) {
commitPropsAndExit(params, event);
});
var handleColumnHeaderDragStart = useEventCallback(function () {
var cell = gridFocusCellSelector(apiRef);
if (!cell) {
return;
}
var params = apiRef.current.getCellParams(cell.id, cell.field);
commitPropsAndExit(params, {});
});
var handleCellEditStart = React.useCallback(function (params, event) {
if (!params.isEditable) {
return;
}
apiRef.current.setCellMode(params.id, params.field, GridCellModes.Edit);
if (isKeyboardEvent(event) && isPrintableKey(event)) {
apiRef.current.unstable_setEditCellProps({
id: params.id,
field: params.field,
props: {
value: ''
}
});
}
}, [apiRef]);
var handleCellEditStop = React.useCallback(function (params, event) {
apiRef.current.setCellMode(params.id, params.field, GridCellModes.View);
if (!isKeyboardEvent(event)) {
return;
}
if (isCellEditCommitKeys(event.key)) {
apiRef.current.publishEvent('cellNavigationKeyDown', params, event);
return;
}
if (event.key === 'Escape' || isDeleteKeys(event.key)) {
apiRef.current.setCellFocus(params.id, params.field);
}
}, [apiRef]);
var handleCellEditCommit = React.useCallback(function (params) {
var id = params.id,
field = params.field;
var model = apiRef.current.getEditRowsModel();
var value = model[id][field].value;
logger.debug("Setting cell id: ".concat(id, " field: ").concat(field, " to value: ").concat(value == null ? void 0 : value.toString()));
var row = apiRef.current.getRow(id);
if (row) {
var column = apiRef.current.getColumn(params.field);
var rowUpdate = _extends({}, row, _defineProperty({}, field, value));
if (column.valueSetter) {
rowUpdate = column.valueSetter({
row: row,
value: value
});
}
apiRef.current.updateRows([rowUpdate]);
}
}, [apiRef, logger]);
var handleEditCellPropsChange = React.useCallback(function (params) {
var row = apiRef.current.getRow(params.id);
var column = apiRef.current.getColumn(params.field);
var editCellProps = column.preProcessEditCellProps ? column.preProcessEditCellProps({
id: params.id,
row: row,
props: params.props
}) : params.props;
if (isPromise(editCellProps)) {
editCellProps.then(function (newEditCellProps) {
apiRef.current.unstable_setEditCellProps(_extends({}, params, {
props: newEditCellProps
}));
});
} else {
apiRef.current.unstable_setEditCellProps(_extends({}, params, {
props: editCellProps
}));
}
}, [apiRef]);
useGridApiEventHandler(apiRef, 'cellKeyDown', buildCallback(handleCellKeyDown));
useGridApiEventHandler(apiRef, 'cellDoubleClick', buildCallback(handleCellDoubleClick));
useGridApiEventHandler(apiRef, 'cellFocusOut', buildCallback(handleCellFocusOut));
useGridApiEventHandler(apiRef, 'columnHeaderDragStart', buildCallback(handleColumnHeaderDragStart));
useGridApiEventHandler(apiRef, 'cellEditStart', buildCallback(handleCellEditStart));
useGridApiEventHandler(apiRef, 'cellEditStop', buildCallback(handleCellEditStop));
useGridApiEventHandler(apiRef, 'cellEditCommit', buildCallback(handleCellEditCommit));
useGridApiEventHandler(apiRef, 'editCellPropsChange', buildCallback(handleEditCellPropsChange));
useGridApiOptionHandler(apiRef, 'cellEditCommit', props.onCellEditCommit);
useGridApiOptionHandler(apiRef, 'cellEditStart', props.onCellEditStart);
useGridApiOptionHandler(apiRef, 'cellEditStop', props.onCellEditStop);
};