brutalism design
This commit is contained in:
79
new-client/src/widgets/chat/composables/use-chat-scroll.ts
Normal file
79
new-client/src/widgets/chat/composables/use-chat-scroll.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { MaybeRefOrGetter, TemplateRef } from 'vue'
|
||||
import { useEventListener, useMutationObserver } from '@vueuse/core'
|
||||
import { computed, reactive, toValue, watch } from 'vue'
|
||||
|
||||
interface ChatScrollOptions {
|
||||
startOffset?: number
|
||||
endOffset?: number
|
||||
}
|
||||
|
||||
export function useChatScroll(target: TemplateRef<HTMLElement>, options?: MaybeRefOrGetter<ChatScrollOptions>) {
|
||||
const el = computed(() => toValue(target))
|
||||
|
||||
const arrivedState = reactive({
|
||||
start: true,
|
||||
end: false,
|
||||
})
|
||||
|
||||
watch(arrivedState, () => {
|
||||
console.log('arrived state', arrivedState)
|
||||
})
|
||||
|
||||
watch(el, (el) => {
|
||||
if (!el)
|
||||
return
|
||||
|
||||
scrollToStart(true)
|
||||
getArrivedState()
|
||||
}, { flush: 'post' })
|
||||
|
||||
useMutationObserver(el, () => {
|
||||
if (arrivedState.start) {
|
||||
scrollToStart(true)
|
||||
}
|
||||
|
||||
getArrivedState()
|
||||
}, {
|
||||
childList: true,
|
||||
// subtree: true,
|
||||
})
|
||||
|
||||
useEventListener(el, 'scroll', () => {
|
||||
getArrivedState()
|
||||
}, { passive: true })
|
||||
|
||||
useEventListener(el, 'scrollend', () => {
|
||||
getArrivedState()
|
||||
}, { passive: true })
|
||||
|
||||
function getArrivedState() {
|
||||
if (!el.value) {
|
||||
arrivedState.start = true
|
||||
arrivedState.end = false
|
||||
return
|
||||
}
|
||||
|
||||
const { startOffset = 0, endOffset = 0 } = toValue(options) ?? {}
|
||||
|
||||
const offsetHeight = el.value.offsetHeight
|
||||
const scrollHeight = el.value.scrollHeight
|
||||
const scrollTop = Math.abs(el.value.scrollTop)
|
||||
|
||||
arrivedState.start = scrollTop + offsetHeight >= scrollHeight - startOffset
|
||||
arrivedState.end = scrollTop <= endOffset
|
||||
}
|
||||
|
||||
function scrollToStart(instant = false) {
|
||||
if (!el.value)
|
||||
return
|
||||
|
||||
const offset = Math.ceil(el.value.scrollHeight - el.value.offsetHeight)
|
||||
|
||||
el.value.scrollTo({ top: offset, behavior: instant ? 'instant' : 'smooth' })
|
||||
}
|
||||
|
||||
return {
|
||||
arrivedState,
|
||||
scrollToStart,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user