Skip to content

Instantly share code, notes, and snippets.

@gargroh
Created December 12, 2019 11:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gargroh/8229b17c3dca3eecfdc7d5fc0e777f18 to your computer and use it in GitHub Desktop.
Save gargroh/8229b17c3dca3eecfdc7d5fc0e777f18 to your computer and use it in GitHub Desktop.
[React Table v7] [useCellRangeSelection] Excel like cell range selection in react table
import React from 'react';
import {
actions,
makePropGetter,
ensurePluginOrder,
functionalUpdate,
useConsumeHookGetter,
useGetLatest
} from '../../react-table/utils';
// Actions
actions.cellRangeSelectionStart = 'cellRangeSelectionStart';
actions.cellRangeSelecting = 'cellRangeSelecting';
actions.cellRangeSelectionEnd = 'cellRangeSelectionEnd';
const defaultgetCellRangeSelectionProps = (props, instance, row, cell) => {
const { dispatch } = instance;
const dispatchStart = (from) => dispatch({ type: actions.cellRangeSelectionStart, from });
const dispatchEnd = (to) => dispatch({ type: actions.cellRangeSelectionEnd, to });
return [
props,
{
onMouseDown: (e) => {
const from = [row.selectIndex, cell.column.selectIndex];
dispatchStart(from);
console.log(e, from);
console.log('row', row);
console.log('cell', cell);
},
onMouseUp: (e) => {
const to = [row.selectIndex, cell.column.selectIndex];
dispatchEnd(to);
}
}
];
};
export const useCellRangeSelection = (hooks) => {
hooks.getCellRangeSelectionProps = [defaultgetCellRangeSelectionProps];
hooks.stateReducers.push(reducer);
hooks.useInstance.push(useInstance);
};
useCellRangeSelection.pluginName = 'useCellRangeSelection';
// Reducer
function reducer(state, action) {
if (action.type === actions.init) {
return {
selectedCells: [],
...state
};
}
if (action.type === actions.cellRangeSelectionStart) {
// todo: use actions.from to derive selectedCells;
return {
...state,
selectedCells: []
};
}
if (action.type === actions.cellRangeSelecting) {
// todo: use actions.... to derive selectedCells;
return {
...state,
selectedCells: []
};
}
if (action.type === actions.cellRangeSelectionEnd) {
// todo: use actions.to to derive selectedCells;
return {
...state,
selectedCells: []
};
}
}
function useInstance(instance) {
const {
hooks,
plugins,
selectableCells = true,
state: { selectedCells },
dispatch
} = instance;
ensurePluginOrder(
plugins,
['useFilters', 'useGroupBy', 'useSortBy'],
'useCellRangeSelection',
[]
);
const cellRangeSelectionStart = React.useCallback(
(clickedRow) => {
return dispatch({ type: actions.cellRangeSelectionStart, clickedRow });
},
[dispatch]
);
const getInstance = useGetLatest(instance);
const getCellRangeSelectionProps = useConsumeHookGetter(
getInstance().hooks,
'getCellRangeSelectionProps'
);
hooks.prepareRow.push((row) => {
// todo: Get row index in final set of rows
row.selectIndex = 0;
if (selectableCells) {
row.cells.forEach((cell, index) => {
cell.selectIndex = index;
// todo: use selectedCells state to mark cell as selected
if (false) {
cell.selected = true;
}
cell.getCellRangeSelectionProps = makePropGetter(
getCellRangeSelectionProps(),
getInstance(),
row,
cell
);
});
}
});
Object.assign(instance, {
cellRangeSelectionStart
});
}
function getBetweenCells(r1, c1, r2, c2, data) {
const startRow = Math.min(r1, r2);
const endRow = Math.max(r1, r2);
const startCol = Math.min(c1, c2);
const endCol = Math.max(c1, c2);
const arr = [];
for (let i = startRow; i <= endRow; i++) {
for (let j = startCol; j <= endCol; j++) {
arr.push(data[i][j]);
}
}
return arr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment