68 lines
1.5 KiB
TypeScript
68 lines
1.5 KiB
TypeScript
import { computed, ref, watch, type Ref } from 'vue'
|
|
import type { MediaItem } from '@/composables/useMedia'
|
|
|
|
export type SelectAllState = 'none' | 'partial' | 'all'
|
|
|
|
export function useMediaSelection(items: Ref<MediaItem[]>) {
|
|
const selectedIds = ref<number[]>([])
|
|
|
|
const count = computed(() => selectedIds.value.length)
|
|
const selectedItems = computed(() =>
|
|
items.value.filter((item) => selectedIds.value.includes(item.id)),
|
|
)
|
|
const allState = computed<SelectAllState>(() => {
|
|
if (count.value === 0) {
|
|
return 'none'
|
|
}
|
|
return count.value >= items.value.length ? 'all' : 'partial'
|
|
})
|
|
|
|
function isSelected(id: number) {
|
|
return selectedIds.value.includes(id)
|
|
}
|
|
|
|
function select(id: number) {
|
|
if (!isSelected(id)) {
|
|
selectedIds.value = [...selectedIds.value, id]
|
|
}
|
|
}
|
|
|
|
function toggle(id: number) {
|
|
selectedIds.value = isSelected(id)
|
|
? selectedIds.value.filter((entry) => entry !== id)
|
|
: [...selectedIds.value, id]
|
|
}
|
|
|
|
function replace(ids: number[]) {
|
|
selectedIds.value = ids
|
|
}
|
|
|
|
function clear() {
|
|
selectedIds.value = []
|
|
}
|
|
|
|
function toggleAll() {
|
|
selectedIds.value = allState.value === 'all' ? [] : items.value.map((item) => item.id)
|
|
}
|
|
|
|
watch(items, (loaded) => {
|
|
const kept = selectedIds.value.filter((id) => loaded.some((item) => item.id === id))
|
|
if (kept.length !== selectedIds.value.length) {
|
|
selectedIds.value = kept
|
|
}
|
|
})
|
|
|
|
return {
|
|
selectedIds,
|
|
selectedItems,
|
|
count,
|
|
allState,
|
|
isSelected,
|
|
select,
|
|
toggle,
|
|
replace,
|
|
clear,
|
|
toggleAll,
|
|
}
|
|
}
|