Решено, добавив переменную в состоянии (inFocus) и изменив ее на основе событий mousedown и keydown.
import React from 'react';
import ReactDataGrid from 'fixed-react-data-grid';
import { range } from 'lodash';
const defaultParsePaste = str => str.split(/\r\n|\n|\r/).map(row => row.split('\t'));
// References -
// https://adazzle.github.io/react-data-grid/docs/examples/simple-grid
// https://gist.github.com/ZackKnopp/40fc0691feb03f0fba3e25e7353b73ae
// Props -
// columns = [
// { key: 'a', name: 'a', editable: true },
// { key: 'b', name: 'b', editable: true },
// { key: 'c', name: 'c', editable: true },
// { key: 'd', name: 'd', editable: true },
// ];
// rows = [{ a: 1, b: 2, c: 3, d: 4 }, { a: 5, b: 6, c: 7, d: 8 }];
// updateRows = rows => {
// this.setState({ rows });
// };
class CustomDataGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
topLeft: {},
botRight: {},
inFocus: false,
};
}
componentDidMount() {
document.addEventListener('mousedown', this.handleMousedown);
document.addEventListener('keydown', this.handleKeydown);
document.addEventListener('copy', this.handleCopy);
document.addEventListener('paste', this.handlePaste);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleMouseDown);
document.removeEventListener('keydown', this.handleKeydown);
document.removeEventListener('copy', this.handleCopy);
document.removeEventListener('paste', this.handlePaste);
}
handleMouseDown = e => {
if (this.wrapperRef.contains(e.target) && !this.state.inFocus) {
this.setState({ inFocus: true });
e.stopPropagation();
e.preventDefault();
}
if (!this.wrapperRef.contains(e.target) && this.state.inFocus) {
this.setState({ inFocus: false });
}
};
handleKeydown = e => {
if (this.wrapperRef.contains(e.target) && !this.state.inFocus) {
this.setState({ inFocus: true });
e.stopPropagation();
e.preventDefault();
}
if (!this.wrapperRef.contains(e.target) && this.state.inFocus) {
this.setState({ inFocus: false });
}
};
rowGetter = i => this.props.rows[i];
handleCopy = e => {
if (this.state.inFocus) {
e.preventDefault();
e.stopPropagation();
const { topLeft, botRight } = this.state;
const text = range(topLeft.rowIdx, botRight.rowIdx + 1)
.map(rowIdx =>
this.props.columns
.slice(topLeft.colIdx, botRight.colIdx + 1)
.map(col => this.rowGetter(rowIdx)[col.key])
.join('\t'),
)
.join('\n');
e.clipboardData.setData('text/plain', text);
}
};
updateRows = (startIdx, newRows) => {
const rows = this.props.rows.slice();
for (let i = 0; i < newRows.length; i += 1) {
rows[startIdx + i] = { ...rows[startIdx + i], ...newRows[i] };
}
this.props.updateRows(rows);
};
handlePaste = e => {
if (this.state.inFocus) {
e.preventDefault();
e.stopPropagation();
const { topLeft, botRight } = this.state;
const pasteData = defaultParsePaste(e.clipboardData.getData('text/plain'));
const newRows = [];
if (pasteData.length === 1 && pasteData[0] && pasteData[0].length === 1) {
range(topLeft.rowIdx, botRight.rowIdx + 1).forEach(() => {
const rowData = {};
this.props.columns.slice(topLeft.colIdx, botRight.colIdx + 1).forEach(col => {
rowData[col.key] = pasteData[0][0];
});
newRows.push(rowData);
});
} else {
pasteData.forEach(row => {
const rowData = {};
this.props.columns.slice(topLeft.colIdx, topLeft.colIdx + row.length).forEach((col, j) => {
rowData[col.key] = row[j];
});
newRows.push(rowData);
});
}
this.updateRows(topLeft.rowIdx, newRows);
}
};
onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
const rows = this.props.rows.slice();
for (let i = fromRow; i <= toRow; i += 1) {
rows[i] = { ...rows[i], ...updated };
}
this.props.updateRows(rows);
};
setSelection = async args => {
await this.setState({
topLeft: {
rowIdx: args.topLeft.rowIdx,
colIdx: args.topLeft.idx,
},
botRight: {
rowIdx: args.bottomRight.rowIdx,
colIdx: args.bottomRight.idx,
},
inFocus: true,
});
};
render() {
return (
<div ref={el => this.wrapperRef = el}>
<ReactDataGrid
columns={this.props.columns}
rowGetter={i => this.props.rows[i]}
rowsCount={this.props.rows.length}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect
minColumnWidth={40}
cellRangeSelection={{
onComplete: this.setSelection,
}}
onCellSelected={s => this.setSelection({ topLeft: s, bottomRight: s })}
/>
</div>
);
}
}
export default CustomDataGrid;
Если есть лучший способ решить эту проблему, дайте мне знать.