@mui/x-data-grid
Version:
The Community plan edition of the Data Grid components (MUI X).
123 lines (121 loc) • 4.35 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import * as React from 'react';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { useGridCellEditing } from './useGridCellEditing';
import { GridCellModes, GridEditModes } from '../../../models/gridEditRowModel';
import { useGridRowEditing } from './useGridRowEditing';
import { gridEditRowsStateSelector } from './gridEditingSelectors';
import { isAutoGeneratedRow } from '../rows/gridRowsUtils';
export const editingStateInitializer = state => _extends({}, state, {
editRows: {}
});
export const useGridEditing = (apiRef, props) => {
useGridCellEditing(apiRef, props);
useGridRowEditing(apiRef, props);
const debounceMap = React.useRef({});
const {
isCellEditable: isCellEditableProp
} = props;
const isCellEditable = React.useCallback(params => {
if (isAutoGeneratedRow(params.rowNode)) {
return false;
}
if (!params.colDef.editable) {
return false;
}
if (!params.colDef.renderEditCell) {
return false;
}
if (isCellEditableProp) {
return isCellEditableProp(params);
}
return true;
}, [isCellEditableProp]);
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);
}
// To run the callback immediately without waiting the timeout
const runImmediately = () => {
const [timeout] = debounceMap.current[id][field];
clearTimeout(timeout);
callback();
delete debounceMap.current[id][field];
};
const timeout = setTimeout(() => {
callback();
delete debounceMap.current[id][field];
}, debounceMs);
debounceMap.current[id][field] = [timeout, runImmediately];
};
React.useEffect(() => {
const debounces = debounceMap.current;
return () => {
Object.entries(debounces).forEach(([id, fields]) => {
Object.keys(fields).forEach(field => {
const [timeout] = debounces[id][field];
clearTimeout(timeout);
delete debounces[id][field];
});
});
};
}, []);
const runPendingEditCellValueMutation = React.useCallback((id, field) => {
if (!debounceMap.current[id]) {
return;
}
if (!field) {
Object.keys(debounceMap.current[id]).forEach(debouncedField => {
const [, runCallback] = debounceMap.current[id][debouncedField];
runCallback();
});
} else if (debounceMap.current[id][field]) {
const [, runCallback] = debounceMap.current[id][field];
runCallback();
}
}, []);
const setEditCellValue = React.useCallback(params => {
const {
id,
field,
debounceMs
} = params;
return new Promise(resolve => {
maybeDebounce(id, field, debounceMs, async () => {
const setEditCellValueToCall = props.editMode === GridEditModes.Row ? apiRef.current.setRowEditingEditCellValue : apiRef.current.setCellEditingEditCellValue;
// Check if the cell is in edit mode
// By the time this callback runs the user may have cancelled the editing
if (apiRef.current.getCellMode(id, field) === GridCellModes.Edit) {
const result = await setEditCellValueToCall(params);
resolve(result);
}
});
});
}, [apiRef, props.editMode]);
const getRowWithUpdatedValues = React.useCallback((id, field) => {
return props.editMode === GridEditModes.Cell ? apiRef.current.getRowWithUpdatedValuesFromCellEditing(id, field) : apiRef.current.getRowWithUpdatedValuesFromRowEditing(id);
}, [apiRef, props.editMode]);
const getEditCellMeta = React.useCallback((id, field) => {
const editingState = gridEditRowsStateSelector(apiRef.current.state);
return editingState[id]?.[field] ?? null;
}, [apiRef]);
const editingSharedApi = {
isCellEditable,
setEditCellValue,
getRowWithUpdatedValues,
unstable_getEditCellMeta: getEditCellMeta
};
const editingSharedPrivateApi = {
runPendingEditCellValueMutation
};
useGridApiMethod(apiRef, editingSharedApi, 'public');
useGridApiMethod(apiRef, editingSharedPrivateApi, 'private');
};