@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
166 lines (150 loc) • 6.3 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import * as React from 'react';
import { GridCellModes } from '../../../models/gridEditRowModel';
import { useGridApiEventHandler, useGridApiOptionHandler } from '../../utils/useGridApiEventHandler';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { useGridLogger } from '../../utils/useGridLogger';
import { gridEditRowsStateSelector } from './gridEditRowsSelector';
import { useCellEditing } from './useGridCellEditing.old';
import { useGridRowEditing } from './useGridRowEditing.old';
export const editingStateInitializer = state => _extends({}, state, {
editRows: {}
});
/**
* @requires useGridFocus - can be after, async only
* @requires useGridParamsApi (method)
* @requires useGridColumns (state)
*/
export function useGridEditing(apiRef, props) {
var _props$experimentalFe2;
const logger = useGridLogger(apiRef, 'useGridEditRows');
useCellEditing(apiRef, props);
useGridRowEditing(apiRef, props);
const debounceMap = React.useRef({});
apiRef.current.unstable_registerControlState({
stateId: 'editRows',
propModel: props.editRowsModel,
propOnChange: props.onEditRowsModelChange,
stateSelector: gridEditRowsStateSelector,
changeEvent: 'editRowsModelChange'
});
const isCellEditable = React.useCallback(params => !params.rowNode.isAutoGenerated && !params.rowNode.isPinned && !!params.colDef.editable && !!params.colDef.renderEditCell && (!props.isCellEditable || props.isCellEditable(params)), // eslint-disable-next-line react-hooks/exhaustive-deps
[props.isCellEditable]);
const maybeDebounce = (id, field, debounceMs, callback) => {
if (!debounceMs) {
callback();
return;
}
if (!debounceMap.current[id]) {
debounceMap.current[id] = {};
}
if (debounceMap.current[id][field]) {
const [timeout] = debounceMap.current[id][field];
clearTimeout(timeout);
}
const callbackToRunImmediately = () => {
callback();
const [timeout] = debounceMap.current[id][field];
clearTimeout(timeout);
delete debounceMap.current[id][field];
};
const timeout = setTimeout(() => {
callback();
delete debounceMap.current[id][field];
}, debounceMs);
debounceMap.current[id][field] = [timeout, callbackToRunImmediately];
};
const runPendingEditCellValueMutation = React.useCallback((id, field) => {
if (!debounceMap.current[id]) {
return;
}
if (!field) {
Object.keys(debounceMap.current[id]).forEach(debouncedField => {
const [, callback] = debounceMap.current[id][debouncedField];
callback();
});
} else if (debounceMap.current[id][field]) {
const [, callback] = debounceMap.current[id][field];
callback();
}
}, []);
const setEditCellValue = React.useCallback((params, event = {}) => {
maybeDebounce(params.id, params.field, params.debounceMs, () => {
var _props$experimentalFe;
if ((_props$experimentalFe = props.experimentalFeatures) != null && _props$experimentalFe.preventCommitWhileValidating) {
if (props.editMode === 'row') {
return apiRef.current.unstable_setRowEditingEditCellValue(params);
}
return apiRef.current.unstable_setCellEditingEditCellValue(params);
}
const newParams = {
id: params.id,
field: params.field,
props: {
value: params.value
}
};
return apiRef.current.publishEvent('editCellPropsChange', newParams, event);
});
}, [apiRef, props.editMode, (_props$experimentalFe2 = props.experimentalFeatures) == null ? void 0 : _props$experimentalFe2.preventCommitWhileValidating]);
const parseValue = React.useCallback((id, field, value) => {
const column = apiRef.current.getColumn(field);
return column.valueParser ? column.valueParser(value, apiRef.current.getCellParams(id, field)) : value;
}, [apiRef]);
const setEditCellProps = React.useCallback(params => {
const {
id,
field,
props: editProps
} = params;
logger.debug(`Setting cell props on id: ${id} field: ${field}`);
apiRef.current.setState(state => {
const editRowsModel = _extends({}, state.editRows);
editRowsModel[id] = _extends({}, state.editRows[id]);
editRowsModel[id][field] = _extends({}, editProps, {
value: parseValue(id, field, editProps.value)
});
return _extends({}, state, {
editRows: editRowsModel
});
});
apiRef.current.forceUpdate();
const editRowsState = gridEditRowsStateSelector(apiRef.current.state);
return editRowsState[id][field];
}, [apiRef, logger, parseValue]);
const setEditRowsModel = React.useCallback(model => {
const currentModel = gridEditRowsStateSelector(apiRef.current.state);
if (currentModel !== model) {
logger.debug(`Setting editRows model`);
apiRef.current.setState(state => _extends({}, state, {
editRows: model
}));
apiRef.current.forceUpdate();
}
}, [apiRef, logger]);
const getEditRowsModel = React.useCallback(() => gridEditRowsStateSelector(apiRef.current.state), [apiRef]);
const preventTextSelection = React.useCallback((params, event) => {
const isMoreThanOneClick = event.detail > 1;
if (params.isEditable && params.cellMode === GridCellModes.View && isMoreThanOneClick) {
// If we click more than one time, then we prevent the default behavior of selecting the text cell.
event.preventDefault();
}
}, []);
useGridApiEventHandler(apiRef, 'cellMouseDown', preventTextSelection);
useGridApiOptionHandler(apiRef, 'editCellPropsChange', props.onEditCellPropsChange); // TODO v6: remove, use `preProcessEditCellProps` instead
const editingSharedApi = {
isCellEditable,
setEditRowsModel,
getEditRowsModel,
setEditCellValue,
unstable_setEditCellProps: setEditCellProps,
unstable_parseValue: parseValue,
unstable_runPendingEditCellValueMutation: runPendingEditCellValueMutation
};
useGridApiMethod(apiRef, editingSharedApi, 'EditRowApi');
React.useEffect(() => {
if (props.editRowsModel !== undefined) {
apiRef.current.setEditRowsModel(props.editRowsModel);
}
}, [apiRef, props.editRowsModel]);
}