Files
ComfyUI_frontend/src/composables/useLazyPagination.ts
Alexander Brown f6405e9125 Knip: More Pruning (#5374)
* knip: Don't ignore exports that are only used within a given file

* knip: More pruning after rebase

* knip: Vite plugin config fix

* knip: vitest plugin config

* knip: Playwright config, remove unnecessary ignores.

* knip: Simplify project file enumeration.

* knip: simplify the config file patterns ?(.optional_segment)

* knip: tailwind v4 fix

* knip: A little more, explain some of the deps.
Should be good for this PR.

* knip: remove unused disabling of classMembers.
It's opt-in, which we should probably do.

* knip: floating comments
We should probably delete _one_ of these parallell trees, right?

* knip: Add additional entrypoints

* knip: Restore UserData that's exposed via the types for now.

* knip: Add as an entry file even though knip says it's not necessary.

* knip: re-export functions used by nodes (h/t @christian-byrne)
2025-09-07 01:10:32 -07:00

108 lines
2.7 KiB
TypeScript

import { type Ref, computed, ref, shallowRef, watch } from 'vue'
interface LazyPaginationOptions {
itemsPerPage?: number
initialPage?: number
}
export function useLazyPagination<T>(
items: Ref<T[]> | T[],
options: LazyPaginationOptions = {}
) {
const { itemsPerPage = 12, initialPage = 1 } = options
const currentPage = ref(initialPage)
const isLoading = ref(false)
const loadedPages = shallowRef(new Set<number>([]))
// Get reactive items array
const itemsArray = computed(() => {
const itemData = 'value' in items ? items.value : items
return Array.isArray(itemData) ? itemData : []
})
// Simulate pagination by slicing the items
const paginatedItems = computed(() => {
const itemData = itemsArray.value
if (itemData.length === 0) {
return []
}
const loadedPageNumbers = Array.from(loadedPages.value).sort(
(a, b) => a - b
)
const maxLoadedPage = Math.max(...loadedPageNumbers, 0)
const endIndex = maxLoadedPage * itemsPerPage
return itemData.slice(0, endIndex)
})
const hasMoreItems = computed(() => {
const itemData = itemsArray.value
if (itemData.length === 0) {
return false
}
const loadedPagesArray = Array.from(loadedPages.value)
const maxLoadedPage = Math.max(...loadedPagesArray, 0)
return maxLoadedPage * itemsPerPage < itemData.length
})
const totalPages = computed(() => {
const itemData = itemsArray.value
if (itemData.length === 0) {
return 0
}
return Math.ceil(itemData.length / itemsPerPage)
})
const loadNextPage = async () => {
if (isLoading.value || !hasMoreItems.value) return
isLoading.value = true
const loadedPagesArray = Array.from(loadedPages.value)
const nextPage = Math.max(...loadedPagesArray, 0) + 1
// Simulate network delay
// await new Promise((resolve) => setTimeout(resolve, 5000))
const newLoadedPages = new Set(loadedPages.value)
newLoadedPages.add(nextPage)
loadedPages.value = newLoadedPages
currentPage.value = nextPage
isLoading.value = false
}
// Initialize with first page
watch(
() => itemsArray.value.length,
(length) => {
if (length > 0 && loadedPages.value.size === 0) {
loadedPages.value = new Set([1])
}
},
{ immediate: true }
)
const reset = () => {
currentPage.value = initialPage
loadedPages.value = new Set([])
isLoading.value = false
// Immediately load first page if we have items
const itemData = itemsArray.value
if (itemData.length > 0) {
loadedPages.value = new Set([1])
}
}
return {
paginatedItems,
isLoading,
hasMoreItems,
currentPage,
totalPages,
loadNextPage,
reset
}
}