fix(scrolling): prevent unwanted autofocus on scroll #46

Merged
eleith merged 1 commits from gemini/fix/autofocus-scroll-up into main 2025-08-19 04:54:24 +00:00
+35 -34
View File
@@ -27,12 +27,13 @@ document.addEventListener('DOMContentLoaded', () => {
activeEntry = entry;
if (activeEntry) {
activeEntry.classList.add('viewed');
activeEntry.classList.add('viewed'); // Mark as viewed immediately
activeEntry.classList.add('active');
if (!preventScroll) {
if (!preventScroll) { // Only focus if not preventing scroll
activeEntry.querySelector('summary')?.focus();
}
// Mark previous entries as read after a delay
markAsReadTimer = setTimeout(() => {
markAsRead(activeEntry);
}, 1000);
@@ -84,41 +85,41 @@ document.addEventListener('DOMContentLoaded', () => {
}
const observer = new IntersectionObserver((intersectionEntries) => {
const scrollDirection = window.scrollY > lastScrollY ? 'down' : 'up';
lastScrollY = window.scrollY;
const scrollDirection = window.scrollY > lastScrollY ? 'down' : 'up';
lastScrollY = window.scrollY;
const activeEntryIsVisible = entries.some(entry => {
if (entry === activeEntry) {
const rect = entry.getBoundingClientRect();
return rect.top >= 0 && rect.bottom <= window.innerHeight;
}
return false;
});
intersectionEntries.forEach(intersectionEntry => {
const {
target,
isIntersecting,
boundingClientRect
} = intersectionEntry;
if (activeEntryIsVisible) {
return;
}
intersectionEntries.forEach(intersectionEntry => {
const {
target,
isIntersecting,
boundingClientRect
} = intersectionEntry;
if (scrollDirection === 'down' && !isIntersecting && boundingClientRect.top < 0) {
clearTimeout(focusTimer);
focusTimer = setTimeout(() => {
const visibleEntries = getVisibleEntries();
const nextEntry = visibleEntries[visibleEntries.indexOf(target) + 1];
if (nextEntry) {
setActiveEntry(nextEntry, true);
// If an entry is no longer intersecting and we are scrolling down,
// mark it as viewed.
if (scrollDirection === 'down' && !isIntersecting && boundingClientRect.top < 0) {
target.classList.add('viewed');
}
}, 450);
}
});
}, {
threshold: 0.5
});
// If there's no active entry, or the active entry is no longer visible,
// try to set the first visible entry as active.
if (!activeEntry || (activeEntry && !intersectionEntries.some(e => e.target === activeEntry && e.isIntersecting))) {
for (const entry of getVisibleEntries()) {
const rect = entry.getBoundingClientRect();
// Set the first entry that is at or above the top of the viewport as active.
// Only set active if it's not already the active entry and it's not behind the current active entry.
if (rect.top >= 0) {
if (!activeEntry || entries.indexOf(entry) >= entries.indexOf(activeEntry)) {
setActiveEntry(entry, true); // Prevent scroll on auto-focus
}
return;
}
}
}
});
}, {
threshold: 0.01 // A very small threshold to detect entry entering/leaving the viewport
});
entries.forEach(entry => observer.observe(entry));