diff --git a/tl/src/tl/views.cljs b/tl/src/tl/views.cljs index f8eb576..6050ea3 100644 --- a/tl/src/tl/views.cljs +++ b/tl/src/tl/views.cljs @@ -1095,15 +1095,19 @@ ;; Renders nothing: owns the active-annotation subscription and scrolls the active ;; card into view, so `commentary` itself no longer re-renders on every crossing. (defn- commentary-scroll [el] - (let [active @(rf/subscribe [::subs/active-annotation])] - (r/after-render - (fn [] (when-let [c @el] - (when-let [node (and active (.querySelector c (str "#ann-" (name active))))] - ;; scrollIntoView (not manual offsetTop math): a nested card's - ;; offsetParent is its parent .ann (position:relative), so offsetTop - ;; would be measured inside the parent, not the scroll container. - (.scrollIntoView node #js {:block "center" :behavior "smooth"}))))) - nil)) + ;; Form-3 so the scroll runs in component-did-update — reliably after the DOM is + ;; committed on every active-annotation change — and via scrollIntoView, which + ;; (unlike offsetTop math) is correct even when the active card is nested. + (letfn [(scroll! [& _] + (let [active @(rf/subscribe [::subs/active-annotation])] + (when-let [c @el] + (when-let [node (and active (.querySelector c (str "#ann-" (name active))))] + (.scrollIntoView node #js {:block "center" :behavior "smooth"})))))] + (r/create-class + {:display-name "commentary-scroll" + :component-did-mount scroll! + :component-did-update scroll! + :reagent-render (fn [_] @(rf/subscribe [::subs/active-annotation]) nil)}))) (defn commentary [] (let [el (atom nil) open (r/atom nil)]