firstRowUnderHeader?: boolean
onCellMouseDown: (rowIndex: number, colIndex: number, shiftKey: boolean) => void
onCellMouseEnter: (rowIndex: number, colIndex: number) => void
- onRowMouseDown: (rowIndex: number, shiftKey: boolean) => void
- onRowMouseEnter: (rowIndex: number) => void
+ onRowToggle: (rowIndex: number, shiftKey: boolean) => void
}
-const PositionGapRows = React.memo(function PositionGapRows({
- count,
- startPosition,
- columns,
- normalizedSelection,
- firstRowUnderHeader = false,
- onCellMouseDown,
- onCellMouseEnter,
- onRowMouseDown,
- onRowMouseEnter,
-}: PositionGapRowsProps) {
- const capped = Math.min(count, GAP_ROW_LIMIT)
- const sel = normalizedSelection
- const isMultiCell = sel !== null && (sel.startRow !== sel.endRow || sel.startCol !== sel.endCol)
+const PositionGapRows = React.memo(
+ function PositionGapRows({
+ count,
+ startPosition,
+ columns,
+ normalizedSelection,
+ checkedRows,
+ firstRowUnderHeader = false,
+ onCellMouseDown,
+ onCellMouseEnter,
+ onRowToggle,
+ }: PositionGapRowsProps) {
+ const capped = Math.min(count, GAP_ROW_LIMIT)
+ const sel = normalizedSelection
+ const isMultiCell = sel !== null && (sel.startRow !== sel.endRow || sel.startCol !== sel.endCol)
- return (
- <>
- {Array.from({ length: capped }).map((_, i) => {
- const position = startPosition + i
- return (
-
- | {
- if (e.button !== 0) return
- onRowMouseDown(position, e.shiftKey)
- }}
- onMouseEnter={() => onRowMouseEnter(position)}
- >
-
- {position + 1}
-
-
-
-
- |
- {columns.map((col, colIndex) => {
- const inRange =
- sel !== null &&
- position >= sel.startRow &&
- position <= sel.endRow &&
- colIndex >= sel.startCol &&
- colIndex <= sel.endCol
- const isAnchor =
- sel !== null && position === sel.anchorRow && colIndex === sel.anchorCol
-
- const isTopEdge = inRange && position === sel!.startRow
- const isBottomEdge = inRange && position === sel!.endRow
- const isLeftEdge = inRange && colIndex === sel!.startCol
- const isRightEdge = inRange && colIndex === sel!.endCol
- const belowHeader = firstRowUnderHeader && i === 0
-
- return (
- {
- if (e.button !== 0) return
- onCellMouseDown(position, colIndex, e.shiftKey)
- }}
- onMouseEnter={() => onCellMouseEnter(position, colIndex)}
+ return (
+ <>
+ {Array.from({ length: capped }).map((_, i) => {
+ const position = startPosition + i
+ const isGapChecked = checkedRows.has(position)
+ return (
+ |
+ | {
+ if (e.button !== 0) return
+ onRowToggle(position, e.shiftKey)
+ }}
+ >
+
- {inRange && isMultiCell && (
-
+ {position + 1}
+
+ }
-
- |
- )
- })}
+ >
+
+
+
+ {columns.map((col, colIndex) => {
+ const inRange =
+ sel !== null &&
+ position >= sel.startRow &&
+ position <= sel.endRow &&
+ colIndex >= sel.startCol &&
+ colIndex <= sel.endCol
+ const isAnchor =
+ sel !== null && position === sel.anchorRow && colIndex === sel.anchorCol
+ const isHighlighted = inRange || isGapChecked
+
+ const isTopEdge = inRange ? position === sel!.startRow : isGapChecked
+ const isBottomEdge = inRange ? position === sel!.endRow : isGapChecked
+ const isLeftEdge = inRange ? colIndex === sel!.startCol : colIndex === 0
+ const isRightEdge = inRange
+ ? colIndex === sel!.endCol
+ : colIndex === columns.length - 1
+ const belowHeader = firstRowUnderHeader && i === 0
+
+ return (
+ {
+ if (e.button !== 0) return
+ onCellMouseDown(position, colIndex, e.shiftKey)
+ }}
+ onMouseEnter={() => onCellMouseEnter(position, colIndex)}
+ >
+ {isHighlighted && (isMultiCell || isGapChecked) && (
+
+ )}
+ {isAnchor && }
+
+ |
+ )
+ })}
+
+ )
+ })}
+ {count > GAP_ROW_LIMIT && (
+
+ |
- )
- })}
- {count > GAP_ROW_LIMIT && (
-
- |
-
- )}
- >
- )
-})
+ )}
+ >
+ )
+ },
+ (prev, next) => {
+ if (
+ prev.count !== next.count ||
+ prev.startPosition !== next.startPosition ||
+ prev.columns !== next.columns ||
+ prev.normalizedSelection !== next.normalizedSelection ||
+ prev.firstRowUnderHeader !== next.firstRowUnderHeader ||
+ prev.onCellMouseDown !== next.onCellMouseDown ||
+ prev.onCellMouseEnter !== next.onCellMouseEnter ||
+ prev.onRowToggle !== next.onRowToggle
+ ) {
+ return false
+ }
+ const end = prev.startPosition + Math.min(prev.count, GAP_ROW_LIMIT)
+ for (let p = prev.startPosition; p < end; p++) {
+ if (prev.checkedRows.has(p) !== next.checkedRows.has(p)) return false
+ }
+ return true
+ }
+)
const TableColGroup = React.memo(function TableColGroup({
columns,
@@ -1655,10 +1898,8 @@ interface DataRowProps {
onContextMenu: (e: React.MouseEvent, row: TableRowType) => void
onCellMouseDown: (rowIndex: number, colIndex: number, shiftKey: boolean) => void
onCellMouseEnter: (rowIndex: number, colIndex: number) => void
- onRowMouseDown: (rowIndex: number, shiftKey: boolean) => void
- onRowMouseEnter: (rowIndex: number) => void
- onRowSelect: (rowIndex: number) => void
- onClearSelection: () => void
+ isRowChecked: boolean
+ onRowToggle: (rowIndex: number, shiftKey: boolean) => void
}
function rowSelectionChanged(
@@ -1707,10 +1948,8 @@ function dataRowPropsAreEqual(prev: DataRowProps, next: DataRowProps): boolean {
prev.onContextMenu !== next.onContextMenu ||
prev.onCellMouseDown !== next.onCellMouseDown ||
prev.onCellMouseEnter !== next.onCellMouseEnter ||
- prev.onRowMouseDown !== next.onRowMouseDown ||
- prev.onRowMouseEnter !== next.onRowMouseEnter ||
- prev.onRowSelect !== next.onRowSelect ||
- prev.onClearSelection !== next.onClearSelection
+ prev.isRowChecked !== next.isRowChecked ||
+ prev.onRowToggle !== next.onRowToggle
) {
return false
}
@@ -1738,6 +1977,7 @@ const DataRow = React.memo(function DataRow({
initialCharacter,
pendingCellValue,
normalizedSelection,
+ isRowChecked,
onClick,
onDoubleClick,
onSave,
@@ -1745,29 +1985,26 @@ const DataRow = React.memo(function DataRow({
onContextMenu,
onCellMouseDown,
onCellMouseEnter,
- onRowMouseDown,
- onRowMouseEnter,
- onRowSelect,
- onClearSelection,
+ onRowToggle,
}: DataRowProps) {
const sel = normalizedSelection
const isMultiCell = sel !== null && (sel.startRow !== sel.endRow || sel.startCol !== sel.endCol)
- const isRowSelected =
+ const isRowSelectedByRange =
sel !== null &&
rowIndex >= sel.startRow &&
rowIndex <= sel.endRow &&
sel.startCol === 0 &&
sel.endCol === columns.length - 1
+ const isRowSelected = isRowChecked || isRowSelectedByRange
return (
onContextMenu(e, row)}>
| {
- if (e.button !== 0 || isRowSelected) return
- onRowMouseDown(rowIndex, e.shiftKey)
+ if (e.button !== 0) return
+ onRowToggle(rowIndex, e.shiftKey)
}}
- onMouseEnter={() => onRowMouseEnter(rowIndex)}
>
{
- e.stopPropagation()
- if (e.button !== 0) return
- if (e.shiftKey) {
- onRowMouseDown(rowIndex, true)
- } else if (isRowSelected) {
- onClearSelection()
- } else {
- onRowSelect(rowIndex)
- }
- }}
>
@@ -1806,18 +2032,19 @@ const DataRow = React.memo(function DataRow({
colIndex <= sel.endCol
const isAnchor = sel !== null && rowIndex === sel.anchorRow && colIndex === sel.anchorCol
const isEditing = editingColumnName === column.name
+ const isHighlighted = inRange || isRowChecked
- const isTopEdge = inRange && rowIndex === sel!.startRow
- const isBottomEdge = inRange && rowIndex === sel!.endRow
- const isLeftEdge = inRange && colIndex === sel!.startCol
- const isRightEdge = inRange && colIndex === sel!.endCol
+ const isTopEdge = inRange ? rowIndex === sel!.startRow : isRowChecked
+ const isBottomEdge = inRange ? rowIndex === sel!.endRow : isRowChecked
+ const isLeftEdge = inRange ? colIndex === sel!.startCol : colIndex === 0
+ const isRightEdge = inRange ? colIndex === sel!.endCol : colIndex === columns.length - 1
return (
| {
if (e.button !== 0 || isEditing) return
onCellMouseDown(rowIndex, colIndex, e.shiftKey)
@@ -1826,7 +2053,7 @@ const DataRow = React.memo(function DataRow({
onClick={() => onClick(row.id, column.name)}
onDoubleClick={() => onDoubleClick(row.id, column.name)}
>
- {inRange && isMultiCell && (
+ {isHighlighted && (isMultiCell || isRowChecked) && (
|