From 69f0ef55b23e040ff5cffffdc1488a80ed2484bf Mon Sep 17 00:00:00 2001 From: scheinriese Date: Tue, 19 May 2026 13:20:49 +0200 Subject: [PATCH] fix(lightbox): clean up on PhotoSwipe init failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit attach! sets every Radix popper to inert=true and installs 5 window- capture listeners (pointerdown/mousedown/click/contextmenu/keydown). Cleanup was wired only to PhotoSwipe's "destroy" event, but if .init or .loadAndOpen threw, that event never fired — leaving the listeners attached and every popper permanently inert (soft-bricked app). Wrap init+loadAndOpen in try/catch: on failure synchronously call detach! to roll back inert + remove listeners, clear the window-global so mobile/navigation's later .destroy call doesn't act on a broken instance, and rethrow so the underlying error surfaces. Verified by stubbing PhotoSwipeLightbox to throw inside .init and calling preview-images!: caught exception bubbles up, inert restored to false on a probe popper, and window.photoLightbox is null. Co-Authored-By: Claude Opus 4.7 --- src/main/frontend/extensions/lightbox.cljs | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/extensions/lightbox.cljs b/src/main/frontend/extensions/lightbox.cljs index 100b4d115e..c773335eea 100644 --- a/src/main/frontend/extensions/lightbox.cljs +++ b/src/main/frontend/extensions/lightbox.cljs @@ -1,5 +1,6 @@ (ns frontend.extensions.lightbox - (:require [cljs-bean.core :as bean])) + (:require [cljs-bean.core :as bean] + [lambdaisland.glogi :as log])) (defn- swallow-outside-pswp! "Capture-phase listener that absorbs any pointer/mouse/click event whose @@ -67,7 +68,19 @@ (doseq [^js el roots] (set! (.-inert el) false)))] (attach!) (set! (.-photoLightbox js/window) lightbox) - (doto lightbox - (.on "destroy" detach!) - (.init) - (.loadAndOpen 0)))) + (.on lightbox "destroy" detach!) + ;; If PhotoSwipe `init`/`loadAndOpen` throws, the "destroy" event never + ;; fires, so `detach!` would never run — leaving the window listeners + ;; attached and every Radix popper permanently `inert=true` (soft-bricks + ;; the app). Synchronously roll back the attach! side effects, clear the + ;; window-global so mobile/navigation doesn't act on a broken instance, + ;; then rethrow so the failure surfaces. + (try + (doto lightbox + (.init) + (.loadAndOpen 0)) + (catch :default e + (detach!) + (set! (.-photoLightbox js/window) nil) + (log/error :lightbox/init-failed {:error e}) + (throw e)))))