From b573117423420aba20199e1cf80b8ae525f345f2 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 11 Sep 2026 19:08:27 +0300 Subject: [PATCH] will i ever stop messing with scroll? --- src/components/conversation/conversation.js | 2 + src/components/status/status.js | 5 +- src/composables/useVirtualScrolling.js | 67 +++++++++------------ 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 55edb9a8d..305770131 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -235,6 +235,7 @@ export default { ? mutedStatusHeight : normalStatusHeight + const anchorIds = computed(() => new Set([mainStatus.value?.id, currentStatus.value?.id])) // # Linear style stuff const isLinearView = computed(() => displayStyle.value !== 'tree') const linearElement = useTemplateRef('linear') @@ -248,6 +249,7 @@ export default { body: linearElement, scrollPositionInstance: scroller, scrollCompensation: linearScrollCompensation, + anchorIds, getPlaceholderHeight, }) const changeSuspendStateLinearLocal = (e) => { diff --git a/src/components/status/status.js b/src/components/status/status.js index 277421c6e..c9b3b31c2 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -592,7 +592,7 @@ const Status = { const [entry] = e this.$emit('heightChange', { id: this.status.id, - height: entry.contentRect.height, + height: entry.contentRect.height + 1, element: this.$el, }) }, @@ -600,6 +600,9 @@ const Status = { mounted() { if (this.$refs.root) { this.resizeObserver.observe(this.$refs.root) + this.updateVirtualHeight([{ + contentRect: this.$refs.root.getBoundingClientRect() + }]) } }, unmounted() { diff --git a/src/composables/useVirtualScrolling.js b/src/composables/useVirtualScrolling.js index 5e3d8bb37..97ea87064 100644 --- a/src/composables/useVirtualScrolling.js +++ b/src/composables/useVirtualScrolling.js @@ -20,6 +20,8 @@ export function useVirtualScrolling({ // - false - don't do scroll compensation at all // - 'height' - compensate scroll according to list's height collapseMode, + // Anchor. Set of IDs of element relative to which do scroll compensation + anchorIds, // Placeholder height specification. Must be a function. // function will be called either: // - without arguments (for generic placeholder, i.e. buffer zone size) @@ -50,7 +52,7 @@ export function useVirtualScrolling({ } else { return getPlaceholderHeight(id).value } - })() + 1 //including border + })() const suspendable = !unsuspendibleIds.value.has(id) return { id, height, suspendable, item } }) @@ -74,50 +76,41 @@ export function useVirtualScrolling({ if (newVal.length === 0 && oldVal.length === 0) return pauseWatchers() - const oldTopElement = first(oldVal) - const newTopElement = first(newVal) - - const oldBottomElement = last(oldVal) - const newBottomElement = last(newVal) - - const expansion = oldTopElement == null && oldBottomElement == null - const collapse = newTopElement == null && newBottomElement == null - - if (expansion && collapse) throw new Error("List expanded and collapsed at the same time? How? Why? What??") - - const updatedTopElement = oldTopElement ? newVal.find(({ id }) => id === oldTopElement.id) : null - const updatedBottomElement = oldBottomElement ? newVal.find(({ id }) => id === oldBottomElement.id) : null - - const topDisappeared = updatedTopElement == null - const bottomDisappeared = updatedBottomElement == null - - const previousTopElement = newTopElement ? oldVal.find(({ id }) => id === newTopElement.id) : null - const previousBottomElement = newBottomElement ? oldVal.find(({ id }) => id === newBottomElement.id) : null + const expansion = oldVal.length === 0 && newVal.length !== 0 + const collapse = oldVal.length !== 0 && newVal.length === 0 const diff = (() => { - if (expansion) { - // List expanded + if (expansion || collapse) { if (toValue(collapseMode) === 'height') { - return newBottomElement.top + newBottomElement.height - } else { - return 0 + const oldBottomElement = last(oldVal) + const newBottomElement = last(newVal) + + if (expansion) { + return newBottomElement.top + newBottomElement.height + } else if (collapse) { + return 0 - oldBottomElement.top - oldBottomElement.height + } } - } else if (collapse) { - // List collapsed - if (toValue(collapseMode) === 'height') { - return 0 - oldBottomElement.top - oldBottomElement.height - } else { - return 0 + return 0 + } else if (toValue(anchorIds) != null) { + const anchorOld = oldVal.find(({ id }) => toValue(anchorIds).has(id)) + const anchorNew = newVal.find(({ id }) => toValue(anchorIds).has(id)) + if (anchorOld == null) { + throw new Error('Anchor not found!') } - } else if (oldTopElement && updatedTopElement) { - // Topmost element shifted - return updatedTopElement.top - oldTopElement.top - } else if (topDisappeared) { - // Topmost changed (and shifted) - return 0 - newTopElement.top - previousTopElement.top + + const disappeared = anchorOld != null && anchorNew == null + if (disappeared) { + throw new Error('Anchor disappeared!') + } + + return anchorNew.top - anchorOld.top + } else { + return 0 } })() + console.log(diff) if (diff !== 0) { // Scroll by amount offset changed to keep it in view topScrollBoundary.value += diff