Skip to content

Commit ffc03de

Browse files
committed
Make cell selection optional
1 parent adb9d76 commit ffc03de

File tree

3 files changed

+33
-20
lines changed

3 files changed

+33
-20
lines changed

TODO

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- Extract out context menu
2-
- Extract out cell content
2+
- Extract out cell content
3+
- Lift cell component to top level?

src/table/Table.tsx

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface TableProps<K = string, T = string> {
3636
/** Height of cells in pixels. */
3737
cellHeight?: number
3838
/** The state of the selected cell or cells in the table. */
39-
activeRange: ActiveRange
39+
activeRange?: ActiveRange
4040
/** Sets the state of the selected cell or cells in the table. */
4141
setActiveRange?: (range: ActiveRange) => void
4242
/** Gets the value in a cell. */
@@ -89,11 +89,10 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
8989
// Row and column counts
9090
const numRows = () => props.numRows
9191
const numCols = () => props.columns.length
92-
const minCell = () => [0, 0] as const
93-
const maxCell = () => [numRows() - 1, numCols() - 1] as const
9492

9593
// The active cell range
9694
const activeRange = createMemo(() => {
95+
if (!props.activeRange) return undefined
9796
const { cell, range } = props.activeRange
9897
const maxRow = Math.max(numRows() - 1, 0)
9998
const maxCol = Math.max(numCols() - 1, 0)
@@ -114,13 +113,15 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
114113
})
115114

116115
// The active cell, which may be within a range
117-
const activeCell = () => activeRange().cell
116+
const activeCell = () => activeRange()?.cell
118117

119118
// Details about the active cell
120119
const activeCellData = createMemo(() => {
121-
const [rowIdx, colIdx] = activeCell()
122-
const column = props.columns[colIdx]
123-
if (rowIdx >= props.numRows || !column) return undefined
120+
const cell = activeCell()
121+
if (!cell) return undefined
122+
const rowIdx = cell[0]
123+
const column = props.columns[cell[1]]
124+
if (cell[0] >= props.numRows || !column) return undefined
124125
return { rowIdx, column }
125126
})
126127

@@ -316,7 +317,7 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
316317

317318
// Moves focus to the given cell without modifying the selected range
318319
const moveWithinRange = ([i, j]: CellIndex) => {
319-
const range = props.activeRange.range
320+
const range = props.activeRange?.range
320321
const min = range?.min ?? [0, 0]
321322
const max = range?.max ?? [numRows() - 1, numCols() - 1]
322323

@@ -334,6 +335,8 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
334335

335336
// Moves the cell range to the given cell
336337
const rangeToCell = (i?: number, j?: number) => {
338+
if (!props.activeRange) return
339+
337340
if (i != null) i = Math.max(Math.min(i, numRows() - 1), 0)
338341
if (j != null) j = Math.max(Math.min(j, numCols() - 1), 0)
339342

@@ -350,12 +353,14 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
350353

351354
// Moves focus to the given cell, but only if it is outside the active range
352355
const moveToCellIfOutside = (i: number, j: number) => {
356+
const range = activeRange()
357+
if (!range) return
358+
353359
i = Math.max(Math.min(i, numRows() - 1), 0)
354360
j = Math.max(Math.min(j, numCols() - 1), 0)
355361
const cell = [i, j] as const
356362

357-
const { min, max } = activeRange()
358-
if (i < min[0] || i > max[0] || j < min[1] || j > max[1]) {
363+
if (i < range.min[0] || i > range.max[0] || j < range.min[1] || j > range.max[1]) {
359364
props.setActiveRange?.({ cell })
360365
scrollToCell(i, j)
361366
focus()
@@ -433,6 +438,8 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
433438
ev?.preventDefault()
434439

435440
const range = activeRange()
441+
if (!range) return
442+
436443
props.onCopy?.(range.min, range.max)
437444
}
438445

@@ -441,13 +448,17 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
441448
if (!props.rowsEditable) return
442449

443450
const range = activeRange()
451+
if (!range) return
452+
444453
props.onPaste?.(range.min, range.max)
445454
}
446455

447456
// Handle keyboard events
448457
const handleKeyDown = (ev: KeyboardEvent) => {
449-
const { cell, shiftCell, min, max } = activeRange()
458+
const range = activeRange()
459+
if (!range) return
450460

461+
const { cell, shiftCell, min, max } = range
451462
const delta = ev[modifierKey] ? Infinity : 1
452463

453464
if (ev.key.startsWith('Arrow')) {
@@ -507,7 +518,8 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
507518
}
508519

509520
// Compute dimensions for active cell outline
510-
const calcOutline = (min: CellIndex, max: CellIndex) => {
521+
const calcOutline = (min?: CellIndex, max?: CellIndex) => {
522+
if (!min || !max) return undefined
511523
const left = columnSize(min[1])?.left ?? 0
512524
const right = columnSize(max[1])?.right ?? 0
513525
const width = right - left + px()
@@ -517,16 +529,18 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
517529
return { left, right, top, bottom, width, height }
518530
}
519531
const activeCellOutline = createMemo(() => calcOutline(activeCell(), activeCell()))
520-
const activeRangeOutline = createMemo(() => calcOutline(activeRange().min, activeRange().max))
532+
const activeRangeOutline = createMemo(() => calcOutline(activeRange()?.min, activeRange()?.max))
521533

522534
// Monitor scroll position
523535
const cellIntersectsLeft = createMemo(() => {
524536
const outline = activeRangeOutline()
537+
if (!outline) return false
525538
const x = viewport().left + rowHeaderWidth() - outline.left
526539
return x >= 0 && x <= outline.width
527540
})
528541
const cellIntersectsTop = createMemo(() => {
529542
const outline = activeRangeOutline()
543+
if (!outline) return false
530544
const y = viewport().top + colHeaderHeight() - outline.top
531545
return y >= 0 && y <= outline.height
532546
})
@@ -543,8 +557,8 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
543557
if (shouldRestoreScroll) return
544558
props.onScrollPositionChange?.(ev.currentTarget.scrollLeft, ev.currentTarget.scrollTop)
545559
}}
546-
onMouseMove={onCellMove}
547-
onMouseUp={onCellUp}
560+
onPointerMove={onCellMove}
561+
onPointerUp={onCellUp}
548562
tabIndex={-1}
549563
>
550564
<div ref={focusEl} class="solid-tabular/focus-proxy" tabIndex={-1} contentEditable />
@@ -626,7 +640,6 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
626640
rowIdx={item.index}
627641
top={item.start}
628642
height={item.size}
629-
isActive={item.index >= activeRange().min[0] && item.index <= activeRange().max[0]}
630643
getCellValue={props.getCellValue}
631644
setCellValue={props.setCellValue}
632645
onPointerDown={onCellDown}
@@ -641,7 +654,7 @@ export default function Table<K = string, T = unknown>(props: TableProps<K, T>)
641654
{({ rowIdx, column }) => (
642655
<CellInputContainer
643656
component={column.component}
644-
rect={activeCellOutline()}
657+
rect={activeCellOutline()!}
645658
value={props.getCellValue(rowIdx, column)}
646659
readonly={!props.cellsEditable || !!column.readonly}
647660
setValue={value => props.setCellValue?.(rowIdx, column.id, value)}

src/table/TableRow.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ export interface TableRowProps<K, T> {
88
rowIdx: number
99
top: number
1010
height: number
11-
isActive: boolean
1211
getCellValue: (row: number, column: PositionedColumn<K, T>) => T
1312
setCellValue?: (rowIdx: number, colId: K, value: T) => void
1413
onPointerDown: (ev: PointerEvent, i: number, j: number) => void
@@ -19,7 +18,7 @@ export interface TableRowProps<K, T> {
1918

2019
export function TableRow<K, T>(props: TableRowProps<K, T>) {
2120
return (
22-
<div class="solid-tabular/row" data-active={props.isActive}>
21+
<div class="solid-tabular/row">
2322
<For each={props.columns}>
2423
{col => (
2524
<div

0 commit comments

Comments
 (0)