Compare commits

..

3 Commits

Author SHA1 Message Date
Jürgen Mummert 5d3905632d Fix SlimSelect dropdown scrolling regression 2026-02-23 20:03:08 +01:00
Jürgen Mummert fce467fa87 Harden SlimSelect scroll lock on macOS browsers 2026-02-23 20:00:36 +01:00
Jürgen Mummert f08406ec12 Fix SlimSelect scroll chaining in sticky event filter 2026-02-23 19:57:54 +01:00
@@ -81,6 +81,11 @@
#eventfilters .eventfilter-reset[hidden] { #eventfilters .eventfilter-reset[hidden] {
display: none; display: none;
} }
#eventfilters .ss-content,
#eventfilters .ss-list {
overscroll-behavior: contain;
}
</style> </style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/slim-select@3/dist/slimselect.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/slim-select@3/dist/slimselect.css">
@@ -332,5 +337,110 @@
applyFilter({ type: 'all', value: 'all' }); applyFilter({ type: 'all', value: 'all' });
}); });
const getDropdownFromTarget = (target) => {
if (!(target instanceof Element)) {
return null;
}
return target.closest('.ss-content, .ss-list');
};
const getScrollContainer = (targetDropdown) => {
if (!targetDropdown) {
return null;
}
if (targetDropdown.scrollHeight > targetDropdown.clientHeight) {
return targetDropdown;
}
const contentContainer = targetDropdown.closest('.ss-content') || targetDropdown;
const listContainer = contentContainer.querySelector('.ss-list');
if (listContainer && listContainer.scrollHeight > listContainer.clientHeight) {
return listContainer;
}
if (contentContainer.scrollHeight > contentContainer.clientHeight) {
return contentContainer;
}
return null;
};
const shouldBlockBoundaryScroll = (scrollContainer, delta) => {
if (!scrollContainer || delta === 0) {
return false;
}
const top = scrollContainer.scrollTop;
const height = scrollContainer.clientHeight;
const scrollHeight = scrollContainer.scrollHeight;
const atTop = top <= 0;
const atBottom = top + height >= scrollHeight - 1;
return (atTop && delta < 0) || (atBottom && delta > 0);
};
let lastTouchY = null;
document.addEventListener('wheel', (event) => {
const dropdown = getDropdownFromTarget(event.target);
if (!dropdown) {
return;
}
const scrollContainer = getScrollContainer(dropdown);
if (shouldBlockBoundaryScroll(scrollContainer, event.deltaY)) {
event.preventDefault();
}
event.stopPropagation();
}, { passive: false, capture: true });
document.addEventListener('touchstart', (event) => {
const dropdown = getDropdownFromTarget(event.target);
if (!dropdown || event.touches.length === 0) {
lastTouchY = null;
return;
}
lastTouchY = event.touches[0].clientY;
}, { passive: true, capture: true });
document.addEventListener('touchmove', (event) => {
const dropdown = getDropdownFromTarget(event.target);
if (!dropdown || event.touches.length === 0 || lastTouchY === null) {
return;
}
const scrollContainer = getScrollContainer(dropdown);
if (!scrollContainer) {
return;
}
const currentTouchY = event.touches[0].clientY;
const delta = lastTouchY - currentTouchY;
if (shouldBlockBoundaryScroll(scrollContainer, delta)) {
event.preventDefault();
}
event.stopPropagation();
lastTouchY = currentTouchY;
}, { passive: false, capture: true });
document.addEventListener('touchend', () => {
lastTouchY = null;
}, { passive: true, capture: true });
document.addEventListener('touchcancel', () => {
lastTouchY = null;
}, { passive: true, capture: true });
applyFilter(currentFilter); applyFilter(currentFilter);
</script> </script>