Scope view transitions to event list and prevent page shift

This commit is contained in:
Jürgen Mummert
2026-04-05 13:55:44 +02:00
parent 11b927b91f
commit 5f652530ed
@@ -38,12 +38,65 @@
</div> </div>
<style> <style>
.event-filter-target-list {
view-transition-name: event-filter-list;
contain: layout paint;
}
html {
scrollbar-gutter: stable both-edges;
}
body {
overflow-y: scroll;
}
@keyframes event-filter-vt-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes event-filter-vt-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@media (prefers-reduced-motion: no-preference) { @media (prefers-reduced-motion: no-preference) {
::view-transition-group(root),
::view-transition-old(root), ::view-transition-old(root),
::view-transition-new(root) { ::view-transition-new(root) {
animation: none;
}
::view-transition-group(event-filter-list) {
animation-duration: 240ms; animation-duration: 240ms;
animation-timing-function: ease; animation-timing-function: ease;
} }
::view-transition-old(event-filter-list),
::view-transition-new(event-filter-list) {
animation-duration: 240ms;
animation-timing-function: ease;
mix-blend-mode: normal;
}
::view-transition-old(event-filter-list) {
animation-name: event-filter-vt-fade-out;
}
::view-transition-new(event-filter-list) {
animation-name: event-filter-vt-fade-in;
}
} }
</style> </style>
@@ -130,6 +183,7 @@
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
let activeViewTransition = null; let activeViewTransition = null;
let isViewTransitionMutation = false; let isViewTransitionMutation = false;
let hasAppliedInitialFilter = false;
let currentFilter = { type: 'all', value: '' }; let currentFilter = { type: 'all', value: '' };
let suppressedChangeEvents = 0; let suppressedChangeEvents = 0;
@@ -437,8 +491,9 @@
setActiveControl(filterState); setActiveControl(filterState);
const immediateVisibility = shouldMutateVisibilityImmediately(); const immediateVisibility = shouldMutateVisibilityImmediately();
const shouldAnimateLayout = immediateVisibility && hasAppliedInitialFilter;
runWithLayoutTransition(() => { const mutateVisibility = () => {
events.forEach((eventItem) => { events.forEach((eventItem) => {
if (matches(eventItem, filterState)) { if (matches(eventItem, filterState)) {
showEvent(eventItem, { immediateVisibility }); showEvent(eventItem, { immediateVisibility });
@@ -446,7 +501,15 @@
hideEvent(eventItem, { immediateVisibility }); hideEvent(eventItem, { immediateVisibility });
} }
}); });
}); };
if (shouldAnimateLayout) {
runWithLayoutTransition(mutateVisibility);
} else {
mutateVisibility();
}
hasAppliedInitialFilter = true;
updateStatus(filterState); updateStatus(filterState);
syncState(filterState); syncState(filterState);