table.onCellDown(rowIndex, columnIndex, event)}
onMouseUp={(event) => table.onCellUp(rowIndex, columnIndex, event)}
onMouseEnter={(event) => table.onCellEnter(rowIndex, columnIndex, event)}
onMouseLeave={(event) => table.onCellLeave(rowIndex, columnIndex, event)}
onDoubleClick={(event) => table.onCellDoubleClick(rowIndex, columnIndex, event)}
onKeyDown={(event) => {
if (event.key === "Enter" && !event.shiftKey) {
table.onCellCompleteEditing(rowIndex, columnIndex);
}
}}
/>;
}
function Row({ columns, index }) {
return columns.map((cell, columnIndex) => {
return
{cell} |
});
}
let TableContext = React.createContext();
module.exports = function Table({ sheet }) {
let [ selectedRowStart, setSelectedRowStart ] = React.useState();
let [ selectedRowEnd, setSelectedRowEnd ] = React.useState();
let [ selectedColumnStart, setSelectedColumnStart ] = React.useState();
let [ selectedColumnEnd, setSelectedColumnEnd ] = React.useState();
let [ isSelecting, setIsSelecting ] = React.useState(false);
let [ isEditing, setIsEditing ] = React.useState(false);
// FIXME: Ensure that in editing mode, there's always just *one* cell selected, including when editing mode is activated by eg. pressing Enter (at least until we have multi-cell editing implemented!)
React.useEffect(() => {
function mouseupListener(event) {
if (event.button === MOUSE_PRIMARY) {
setIsSelecting(false);
}
};
function mousedownListener(event) {
if (event.button === MOUSE_PRIMARY) {
stopEditing();
deselect();
}
}
document.addEventListener("mouseup", mouseupListener);
document.addEventListener("mousedown", mousedownListener);
return function () {
document.removeEventListener("mouseup", mouseupListener);
document.removeEventListener("mousedown", mousedownListener);
}
}, []);
function deselect() {
setSelectedRowStart(null);
setSelectedRowEnd(null);
setSelectedColumnStart(null);
setSelectedColumnEnd(null);
}
function select(rowIndex, columnIndex) {
setSelectedRowStart(rowIndex);
setSelectedRowEnd(rowIndex);
setSelectedColumnStart(columnIndex);
setSelectedColumnEnd(columnIndex);
}
function selectCellStart(rowIndex, columnIndex) {
setSelectedRowStart(rowIndex);
setSelectedColumnStart(columnIndex);
}
// FIXME: Swap when end < start
function selectCellEnd(rowIndex, columnIndex) {
setSelectedRowEnd(rowIndex);
setSelectedColumnEnd(columnIndex);
}
function startEditing() {
setIsEditing(true);
}
function stopEditing() {
setIsEditing(false);
}
let flippedSelection = asExpression(() => {
let [ rowStart, rowEnd ] = (selectedRowStart < selectedRowEnd)
? [ selectedRowStart, selectedRowEnd ]
: [ selectedRowEnd, selectedRowStart ];
let [ columnStart, columnEnd ] = (selectedColumnStart < selectedColumnEnd)
? [ selectedColumnStart, selectedColumnEnd ]
: [ selectedColumnEnd, selectedColumnStart ];
return { rowStart, rowEnd, columnStart, columnEnd };
});
// TODO: Also stop selecting on focus blur and document mouseleave? Or is this not necessary?
let tableAPI = {
selection: flippedSelection,
isEditing: isEditing,
onCellDown: function (rowIndex, columnIndex, event) {
if (event.button === MOUSE_PRIMARY) {
stopEditing();
setIsSelecting(true);
selectCellStart(rowIndex, columnIndex);
selectCellEnd(rowIndex, columnIndex);
event.stopPropagation();
}
},
onCellUp: function (rowIndex, columnIndex, event) {
if (event.button === MOUSE_PRIMARY) {
setIsSelecting(false);
event.stopPropagation();
}
},
onCellEnter: function (rowIndex, columnIndex, event) {
if (isSelecting) {
selectCellEnd(rowIndex, columnIndex);
}
},
onCellLeave: function (rowIndex, columnIndex, event) {
},
onCellDoubleClick: function (rowIndex, columnIndex, event) {
if (event.button === MOUSE_PRIMARY) {
startEditing();
select(rowIndex, columnIndex);
event.stopPropagation();
}
},
onCellContentsChange: function (rowIndex, columnIndex, contents) {
// FIXME: Properly run this through a state management cycle?
sheet.cells[rowIndex][columnIndex] = contents;
},
onCellCompleteEditing: function (rowIndex, columnIndex) {
stopEditing();
}
};
return (
{sheet.cells.map((columns, rowIndex) => {
return
;
})}
);
}