export const computedItemsWithSize =
({ props, state }) =>
() => {
const result = []
const { items, keyField } = props
const { simpleArray, vscrollData } = state
const { sizes } = vscrollData
const l = items.length
for (let i = 0; i < l; i++) {
const item = items[i]
const id = simpleArray ? i : item[keyField]
let size = sizes[id]
if (typeof size === 'undefined' && !state.temporary.undefinedMap[id]) {
size = 0
}
result.push({ item, id, size })
}
return result
}
export const onScrollerResize =
({ api, emit, vm }) =>
() => {
const scroller = vm.$refs.scroller
if (scroller) {
api.forceUpdate()
}
emit('resize')
}
export const onScrollerVisible =
({ emit, state }) =>
() => {
state.temporary.events.emit('vscroll:update', { force: false })
emit('visible')
}
export const forceUpdate =
(state) =>
(clear = false) => {
if (clear || state.simpleArray) {
state.vscrollData.sizes = {}
}
state.temporary.events.emit('vscroll:update', { force: true })
}
export const prepareProvide = (state) => {
if (typeof ResizeObserver !== 'undefined') {
state.temporary.resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
if (!Array.isArray(entries)) return
for (const entry of entries) {
if (entry.target && entry.target._onResize) {
let width, height
if (entry.borderBoxSize) {
const resizeObserverSize = entry.borderBoxSize[0]
width = resizeObserverSize.inlineSize
height = resizeObserverSize.blockSize
} else {
width = entry.contentRect.width
height = entry.contentRect.height
}
entry.target._onResize(entry.target._id, width, height)
}
}
})
})
}
}
export const watchItemsWithSize =
({ props, vm }) =>
(next, prev) => {
const scrollTop = vm.$el.scrollTop
const length = Math.min(next.length, prev.length)
let prevActiveTop = 0
let activeTop = 0
for (let i = 0; i < length; i++) {
if (prevActiveTop >= scrollTop) break
prevActiveTop += prev[i].size || props.minItemSize
activeTop += next[i].size || props.minItemSize
}
const offset = activeTop - prevActiveTop
if (offset === 0) return
vm.$el.scrollTop += offset
}
export const scrollToItem = (vm) => (index) => {
const scroller = vm.$refs.scroller
if (scroller) scroller.scrollToItem(index)
}
export const getItemSize =
({ props, state }) =>
(item, index = undefined) => {
const id = state.simpleArray ? (index === 0 || index ? index : props.items.indexOf(item)) : item[props.keyField]
return state.vscrollData.sizes[id] || 0
}
export const scrollToBottom =
({ state, vm, nextTick }) =>
() => {
if (state.temporary.scrollingToBottom) return
state.temporary.scrollingToBottom = true
const el = vm.$el
const step = (el) => (el.scrollTop = el.scrollHeight + 5000)
nextTick(() => {
step(el)
const cb = () => {
step(el)
requestAnimationFrame(() => {
step(el)
if (state.temporary.undefinedSizes === 0) {
state.temporary.scrollingToBottom = false
} else {
requestAnimationFrame(cb)
}
})
}
requestAnimationFrame(cb)
})
}