Add support for bulk selecting rows with shift click

This commit is contained in:
Andrew Kingston 2024-06-20 14:36:22 +01:00
parent 93e222036e
commit 42f781bb76
No known key found for this signature in database
2 changed files with 79 additions and 25 deletions

View File

@ -23,7 +23,15 @@
svelteDispatch("select")
const id = row?._id
if (id) {
selectedRows.actions.toggleRow(id)
if (e.shiftKey) {
if (rowSelected) {
e.preventDefault()
} else {
selectedRows.actions.bulkSelectRows(id)
}
} else {
selectedRows.actions.toggleRow(id)
}
}
}

View File

@ -23,19 +23,9 @@ export const createStores = context => {
const isDragging = writable(false)
const buttonColumnWidth = writable(0)
// Derive the current focused row ID
const focusedRowId = derived(
focusedCellId,
$focusedCellId => {
return parseCellID($focusedCellId)?.id
},
null
)
return {
focusedCellId,
focusedCellAPI,
focusedRowId,
previousFocusedRowId,
previousFocusedCellId,
hoveredRowId,
@ -49,25 +39,34 @@ export const createStores = context => {
}
export const deriveStores = context => {
const { focusedCellId, rows, rowLookupMap, rowHeight, stickyColumn, width } =
context
const {
focusedCellId,
rows,
rowLookupMap,
rowHeight,
stickyColumn,
width,
selectedRows,
} = context
// Derive the current focused row ID
const focusedRowId = derived(focusedCellId, $focusedCellId => {
return parseCellID($focusedCellId)?.id
})
// Derive the row that contains the selected cell
const focusedRow = derived(
[focusedCellId, rowLookupMap, rows],
([$focusedCellId, $rowLookupMap, $rows]) => {
const rowId = parseCellID($focusedCellId)?.id
[focusedRowId, rowLookupMap, rows],
([$focusedRowId, $rowLookupMap, $rows]) => {
// Edge case for new rows
if (rowId === NewRowID) {
if ($focusedRowId === NewRowID) {
return { _id: NewRowID }
}
// All normal rows
const index = $rowLookupMap[rowId]
const index = $rowLookupMap[$focusedRowId]
return $rows[index]
},
null
}
)
// Derive the amount of content lines to show in cells depending on row height
@ -85,15 +84,31 @@ export const deriveStores = context => {
return ($stickyColumn?.width || 0) + $width + GutterWidth < 800
})
// Derive we have any selected rows or not
const hasSelectedRows = derived(selectedRows, $selectedRows => {
return Object.keys($selectedRows).length
})
return {
focusedRowId,
focusedRow,
contentLines,
compact,
hasSelectedRows,
}
}
export const createActions = context => {
const { focusedCellId, hoveredRowId, selectedRows } = context
const {
focusedCellId,
hoveredRowId,
selectedRows,
rowLookupMap,
rows,
hasSelectedRows,
} = context
// Keep the last selected index to use with bulk selection
let lastSelectedIndex = null
// Callback when leaving the grid, deselecting all focussed or selected items
const blur = () => {
@ -110,11 +125,40 @@ export const createActions = context => {
}
if (!newState[id]) {
delete newState[id]
} else {
lastSelectedIndex = get(rowLookupMap)[id]
}
return newState
})
}
const bulkSelectRows = id => {
if (!get(hasSelectedRows)) {
toggleSelectedRow(id)
return
}
// There should always be a last selected index
if (lastSelectedIndex == null) {
throw "NO LAST SELECTED INDEX"
}
const thisIndex = get(rowLookupMap)[id]
// Skip if indices are the same
if (lastSelectedIndex === thisIndex) {
return
}
const from = Math.min(lastSelectedIndex, thisIndex)
const to = Math.max(lastSelectedIndex, thisIndex)
const $rows = get(rows)
selectedRows.update(state => {
for (let i = from; i <= to; i++) {
state[$rows[i]._id] = true
}
return state
})
}
return {
ui: {
actions: {
@ -125,6 +169,7 @@ export const createActions = context => {
...selectedRows,
actions: {
toggleRow: toggleSelectedRow,
bulkSelectRows,
},
},
}
@ -142,6 +187,7 @@ export const initialise = context => {
definition,
rowHeight,
fixedRowHeight,
hasSelectedRows,
} = context
// Ensure we clear invalid rows from state if they disappear
@ -199,7 +245,7 @@ export const initialise = context => {
}
// Clear row selection when focusing a cell
if (id && Object.keys(get(selectedRows)).length) {
if (id && get(hasSelectedRows)) {
selectedRows.set({})
}
})
@ -221,8 +267,8 @@ export const initialise = context => {
})
// Clear focused cell when selecting rows
selectedRows.subscribe(rows => {
if (get(focusedCellId) && Object.keys(rows).length) {
hasSelectedRows.subscribe(selected => {
if (get(focusedCellId) && selected) {
focusedCellId.set(null)
}
})