feat(frontend): add swipe-to-select for admin tables
Squash of all swipe-select commits for clean rebase.
This commit is contained in:
98
frontend/src/composables/useTableSelection.ts
Normal file
98
frontend/src/composables/useTableSelection.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { computed, ref, type Ref } from 'vue'
|
||||
|
||||
interface UseTableSelectionOptions<T> {
|
||||
rows: Ref<T[]>
|
||||
getId: (row: T) => number
|
||||
}
|
||||
|
||||
export function useTableSelection<T>({ rows, getId }: UseTableSelectionOptions<T>) {
|
||||
const selectedSet = ref<Set<number>>(new Set())
|
||||
|
||||
const selectedIds = computed(() => Array.from(selectedSet.value))
|
||||
const selectedCount = computed(() => selectedSet.value.size)
|
||||
|
||||
const isSelected = (id: number) => selectedSet.value.has(id)
|
||||
|
||||
const replaceSelectedSet = (next: Set<number>) => {
|
||||
selectedSet.value = next
|
||||
}
|
||||
|
||||
const setSelectedIds = (ids: number[]) => {
|
||||
selectedSet.value = new Set(ids)
|
||||
}
|
||||
|
||||
const select = (id: number) => {
|
||||
if (selectedSet.value.has(id)) return
|
||||
const next = new Set(selectedSet.value)
|
||||
next.add(id)
|
||||
replaceSelectedSet(next)
|
||||
}
|
||||
|
||||
const deselect = (id: number) => {
|
||||
if (!selectedSet.value.has(id)) return
|
||||
const next = new Set(selectedSet.value)
|
||||
next.delete(id)
|
||||
replaceSelectedSet(next)
|
||||
}
|
||||
|
||||
const toggle = (id: number) => {
|
||||
if (selectedSet.value.has(id)) {
|
||||
deselect(id)
|
||||
return
|
||||
}
|
||||
select(id)
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
if (selectedSet.value.size === 0) return
|
||||
replaceSelectedSet(new Set())
|
||||
}
|
||||
|
||||
const removeMany = (ids: number[]) => {
|
||||
if (ids.length === 0 || selectedSet.value.size === 0) return
|
||||
const next = new Set(selectedSet.value)
|
||||
let changed = false
|
||||
ids.forEach((id) => {
|
||||
if (next.delete(id)) changed = true
|
||||
})
|
||||
if (changed) replaceSelectedSet(next)
|
||||
}
|
||||
|
||||
const allVisibleSelected = computed(() => {
|
||||
if (rows.value.length === 0) return false
|
||||
return rows.value.every((row) => selectedSet.value.has(getId(row)))
|
||||
})
|
||||
|
||||
const toggleVisible = (checked: boolean) => {
|
||||
const next = new Set(selectedSet.value)
|
||||
rows.value.forEach((row) => {
|
||||
const id = getId(row)
|
||||
if (checked) {
|
||||
next.add(id)
|
||||
} else {
|
||||
next.delete(id)
|
||||
}
|
||||
})
|
||||
replaceSelectedSet(next)
|
||||
}
|
||||
|
||||
const selectVisible = () => {
|
||||
toggleVisible(true)
|
||||
}
|
||||
|
||||
return {
|
||||
selectedSet,
|
||||
selectedIds,
|
||||
selectedCount,
|
||||
allVisibleSelected,
|
||||
isSelected,
|
||||
setSelectedIds,
|
||||
select,
|
||||
deselect,
|
||||
toggle,
|
||||
clear,
|
||||
removeMany,
|
||||
toggleVisible,
|
||||
selectVisible
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user