{"version":3,"file":"useIntersectionCommentLoader-457f17cc.js","sources":["../../../app/javascript/vuecomponents/SurfaceLazy.vue","../../../app/javascript/vuecomposables/usePostActionMenuTrigger.ts","../../../app/javascript/vuecomposables/useIntersectionCommentLoader.ts"],"sourcesContent":["\n\n\n","// @file encapsulates opening the post action menu + setting the anchor for position the resulting popover\nimport { createDomElement } from '@@/native_bridge/ui'\nimport { useSurfacePostActionStore } from '@@/pinia/surface_post_action'\nimport type { Post } from '@@/types'\n\ninterface PostActionMenuTrigger {\n showPostActionMenuWithTriggerRect: (buttonEl: HTMLElement | null, post: Post) => void\n}\n\nexport function usePostActionMenuTrigger(): PostActionMenuTrigger {\n const surfacePostActionStore = useSurfacePostActionStore()\n const { showPostActionMenu, setPostActionMenuTriggerRect } = surfacePostActionStore\n\n function showPostActionMenuWithTriggerRect(buttonEl: HTMLElement | null | undefined, post: Post): void {\n if (buttonEl == null) return\n\n // Trigger rect is calculated for mobile app to render post action menu at the correct position.\n // ASSUMPTION: buttonEl is a button element with centered content! See SurfacePostMoreActions.vue for example.\n // https://github.com/padlet/mozart/pull/23494\n const buttonRect = createDomElement(buttonEl)\n const buttonContentRect = createDomElement(buttonEl.firstElementChild as HTMLElement)\n\n const buttonContentCenter = {\n x: buttonContentRect.x + buttonContentRect.width / 2,\n y: buttonContentRect.y + buttonContentRect.height / 2,\n }\n\n const topOffset = buttonContentCenter.y - buttonRect.y\n\n // Calculate trigger rect based on button content center and offset\n const minX = buttonContentCenter.x - topOffset\n const minY = buttonRect.y\n const maxX = buttonContentCenter.x + topOffset\n const maxY = buttonContentCenter.y + topOffset\n const triggerRect = new DOMRect(minX, minY, maxX - minX, maxY - minY)\n\n setPostActionMenuTriggerRect({ postActionMenuTriggerRect: triggerRect })\n showPostActionMenu({ postCid: post.cid })\n }\n\n return {\n showPostActionMenuWithTriggerRect,\n }\n}\n","// @file Composable that loads comments for posts when they enter the viewport using intersection observer.\nimport device from '@@/bits/device'\nimport { isAppUsing } from '@@/bits/flip'\nimport { canObserveIntersection, observeElementIntersection } from '@@/bits/intersection'\nimport { useCommentsStore } from '@@/pinia/surface_comments'\nimport type { Post } from '@@/types'\nimport type { Ref } from 'vue'\nimport { onBeforeUnmount, onMounted } from 'vue'\n\n/**\n * Composable that automatically loads comments for a post when it enters the viewport.\n * Uses IntersectionObserver when available, with fallbacks for unsupported browsers.\n *\n * Features:\n * - Lazy loads comments only when post becomes visible\n * - Avoids duplicate fetches if comments are already loaded\n * - Handles cleanup on component unmount\n * - Special handling for Safari in iframes\n *\n * @param {Object} params - Parameters object\n * @param {Post} params.post - The post object to load comments for\n * @param {Ref} params.postElement - Vue ref to the post DOM element to observe\n * @returns {void}\n */\nexport function useIntersectionCommentLoader({\n post,\n postElement,\n}: {\n post: Post\n postElement: Ref\n}): void {\n if (!isAppUsing('surfaceCommentsPerPost')) return\n\n const commentsStore = useCommentsStore()\n const { fetchComments } = commentsStore\n\n let observer: IntersectionObserver | null = null\n\n const isDisplayedInIframe = window.self !== window.top\n const isIframeInSafari = isDisplayedInIframe && (device.safari || device.ios)\n\n // Helper to cleanup observer\n const cleanupObserver = (): void => {\n if (observer != null) {\n observer.disconnect()\n observer = null\n }\n }\n\n onMounted(() => {\n if (post.id == null || post.hashid == null || postElement.value == null) return\n\n // Early return if we already have comments for this post\n if (commentsStore.commentIdsByPost[post.id]?.length > 0) return\n\n // For browsers that don't support IntersectionObserver or Safari iframes, fetch immediately\n if (!canObserveIntersection || isIframeInSafari) {\n fetchComments({ wishId: post.id, wishHashid: post.hashid })\n return\n }\n\n observer = observeElementIntersection(postElement.value, () => {\n if (post.id == null || post.hashid == null) return\n fetchComments({ wishId: post.id, wishHashid: post.hashid })\n cleanupObserver()\n })\n })\n\n onBeforeUnmount(() => {\n cleanupObserver()\n })\n}\n"],"names":["isVisible","ref","props","renderImmediately","rootElement","onMounted","value","requestIdleCallback","observeElementIntersection","rootMargin","usePostActionMenuTrigger","surfacePostActionStore","useSurfacePostActionStore","showPostActionMenu","setPostActionMenuTriggerRect","showPostActionMenuWithTriggerRect","buttonEl","post","buttonRect","createDomElement","buttonContentRect","firstElementChild","buttonContentCenter","x","width","y","height","topOffset","minX","minY","maxX","maxY","triggerRect","DOMRect","postActionMenuTriggerRect","postCid","cid","useIntersectionCommentLoader","postElement","isAppUsing","commentsStore","useCommentsStore","fetchComments","observer","isIframeInSafari","window","self","top","device","safari","ios","cleanupObserver","disconnect","id","hashid","commentIdsByPost","length","canObserveIntersection","wishId","wishHashid","onBeforeUnmount"],"mappings":"y1BAoBMA,EAAYC,EAAIC,EAAMC,iBAAiB,EACvCC,EAAcH,EAAwB,IAAI,EAEhDI,OAAAA,EAAU,IAAM,CACVL,EAAUM,OACdC,EAAoB,IAAM,CACpBH,EAAYE,QAAU,MAC1BE,EACEJ,EAAYE,MACZ,IAAM,CACJC,EAAoB,IAAM,CACxBP,EAAUM,MAAQ,EACpB,CAAC,CACH,EACA,CAEEG,WAAY,GAAGP,EAAMO,UAAU,IACjC,CACF,CACF,CAAC,CACH,CAAC,sVC/BM,SAASC,GAAkD,CAChE,MAAMC,EAAyBC,IACzB,CAAEC,mBAAAA,EAAoBC,6BAAAA,CAAiC,EAAAH,EAEpD,SAAAI,EAAkCC,EAA0CC,EAAkB,CACrG,GAAID,GAAY,KAAM,OAKhB,MAAAE,EAAaC,EAAiBH,CAAQ,EACtCI,EAAoBD,EAAiBH,EAASK,iBAAgC,EAE9EC,EAAsB,CAC1BC,EAAGH,EAAkBG,EAAIH,EAAkBI,MAAQ,EACnDC,EAAGL,EAAkBK,EAAIL,EAAkBM,OAAS,GAGhDC,EAAYL,EAAoBG,EAAIP,EAAWO,EAG/CG,EAAON,EAAoBC,EAAII,EAC/BE,EAAOX,EAAWO,EAClBK,EAAOR,EAAoBC,EAAII,EAC/BI,EAAOT,EAAoBG,EAAIE,EAC/BK,EAAc,IAAIC,QAAQL,EAAMC,EAAMC,EAAOF,EAAMG,EAAOF,CAAI,EAEvCf,EAAA,CAAEoB,0BAA2BF,CAAY,CAAC,EACvEnB,EAAmB,CAAEsB,QAASlB,EAAKmB,GAAI,CAAC,CAC1C,CAEO,MAAA,CACLrB,kCAAAA,EAEJ,CCnBO,SAASsB,EAA6B,CAC3CpB,KAAAA,EACAqB,YAAAA,CACF,EAGS,CACH,GAAA,CAACC,EAAW,wBAAwB,EAAG,OAE3C,MAAMC,EAAgBC,IAChB,CAAEC,cAAAA,CAAkB,EAAAF,EAE1B,IAAIG,EAAwC,KAG5C,MAAMC,EADsBC,OAAOC,OAASD,OAAOE,MACFC,EAAOC,QAAUD,EAAOE,KAGnEC,EAAkBA,IAAY,CAC9BR,GAAY,OACdA,EAASS,WAAW,EACTT,EAAA,OAIftC,EAAU,IAAM,OACd,GAAIY,EAAAA,EAAKoC,IAAM,MAAQpC,EAAKqC,QAAU,MAAQhB,EAAYhC,OAAS,OAG/DkC,IAAAA,EAAAA,EAAce,iBAAiBtC,EAAKoC,EAAE,IAAtCb,YAAAA,EAAyCgB,QAAS,GAGlD,IAAA,CAACC,GAA0Bb,EAAkB,CAC/CF,EAAc,CAAEgB,OAAQzC,EAAKoC,GAAIM,WAAY1C,EAAKqC,MAAO,CAAC,EAC1D,MACF,CAEWX,EAAAnC,EAA2B8B,EAAYhC,MAAO,IAAM,CACzDW,EAAKoC,IAAM,MAAQpC,EAAKqC,QAAU,OACtCZ,EAAc,CAAEgB,OAAQzC,EAAKoC,GAAIM,WAAY1C,EAAKqC,MAAO,CAAC,EAC1CH,IAClB,CAAC,EACH,CAAC,EAEDS,EAAgB,IAAM,CACJT,GAClB,CAAC,CACH"}