fix(kami-deck): sync deck transform with host-driven .active changes

The previous fix added a local od:slide listener but the host bridge in
apps/web/src/runtime/srcdoc.ts also listens for the same message and
calls setActive() (toggles .slide.active) without driving the deck
transform. Both listeners fired, the bridge re-read the just-toggled
active class, and overshot by one — and the bridge's restoreInitialSlide
path could move .active without a message at all, leaving the deck on
the original transform.

Stop the bridge from double-handling by calling stopImmediatePropagation
in the local listener (registered first because the bridge script is
appended to </body>), and add a MutationObserver that pulls the deck
transform onto whichever slide currently carries .active so the bridge's
direct setActive calls (notably the initial-slide restore) move the deck
too.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
This commit is contained in:
pftom
2026-05-04 17:08:56 +08:00
parent 96b255b223
commit 8cbca303d6
+23 -2
View File
@@ -1051,11 +1051,19 @@ strong { font-weight: 500; }
/* Host-driven navigation: Open Design's host bridge classifies this deck
as class-driven (because go() toggles .slide.active) but the visible
slide is moved by deck.style.transform, which the bridge can't drive.
Route od:slide messages through the local go()/jump so toolbar
next/prev and initialSlideIndex restore actually shift the deck. */
Two cooperating handlers keep the deck in sync with the host:
1. An od:slide message listener routes host nav through go() and
calls stopImmediatePropagation() so the bridge's own listener
(registered after this one) doesn't run a second time and
overshoot by re-reading the freshly-toggled .active class.
2. A MutationObserver on each slide watches .active and pulls the
deck transform onto the active index for class changes that
don't come through a message — chiefly the bridge's
restoreInitialSlide path, which calls setActive() directly. */
addEventListener('message', function (e) {
var data = e && e.data;
if (!data || data.type !== 'od:slide') return;
if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
if (data.action === 'go' && typeof data.index === 'number') go(data.index);
else if (data.action === 'next') go(idx + 1);
else if (data.action === 'prev') go(idx - 1);
@@ -1063,6 +1071,19 @@ strong { font-weight: 500; }
else if (data.action === 'last') go(total - 1);
});
if (typeof MutationObserver !== 'undefined') {
var syncFromActiveClass = function () {
for (var i = 0; i < slides.length; i++) {
if (slides[i].classList && slides[i].classList.contains('active') && i !== idx) {
go(i);
return;
}
}
};
var mo = new MutationObserver(syncFromActiveClass);
slides.forEach(function (s) { mo.observe(s, { attributes: true, attributeFilter: ['class'] }); });
}
go(0);
})();
</script>