{"version":3,"file":"text_reveal_scroll_helper.CKvykqO2.mjs","names":["React.useRef","React.useState"],"sources":["https:/framerusercontent.com/modules/xDgp5el32fHNjPkyEMsb/zok9uz0Ll0JiGpdMPxWN/text_reveal_scroll_helper.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import*as React from\"react\";import{addPropertyControls,ControlType,RenderTarget}from\"framer\";// ─── Sibling DOM Traversal ────────────────────────────────────────────────────\n// Returns ALL .framer-text elements found in siblings (covers multi-para cases)\nfunction findTargetEls(overlayRef){if(!overlayRef.current)return[];let node=overlayRef.current;while(node){const parent=node.parentElement;if(!parent)break;const siblings=Array.from(parent.children);const selfIndex=siblings.indexOf(node);const results=[];for(let i=0;i<siblings.length;i++){if(i===selfIndex)continue;if(siblings[i].classList.contains(\"framer-text\")){results.push(siblings[i]);}// Collect ALL .framer-text descendants (covers multi-paragraph rich text)\nconst nested=Array.from(siblings[i].querySelectorAll(\".framer-text\"));results.push(...nested);}if(results.length>0)return results;node=parent;}return[];}// Returns the closest shared ancestor of all target els (for bounding rect)\nfunction findScrollAnchor(els){if(els.length===0)return null;let candidate=els[0].parentElement;while(candidate){if(els.every(el=>candidate.contains(el)))return candidate;candidate=candidate.parentElement;}return els[0];}// ─── MODE: Characters ─────────────────────────────────────────────────────────\nfunction wrapChars(el,dimOpacity){const spans=[];function walk(node){if(node.nodeType===Node.TEXT_NODE){const text=node.textContent||\"\";if(!text)return;const frag=document.createDocumentFragment();for(const char of text){const span=document.createElement(\"span\");span.textContent=char;span.style.cssText=`display:inline;opacity:${dimOpacity};will-change:opacity;`;spans.push(span);frag.appendChild(span);}node.parentNode?.replaceChild(frag,node);}else if(node.nodeType===Node.ELEMENT_NODE){Array.from(node.childNodes).forEach(walk);}}walk(el);return spans;}// ─── MODE: Words ──────────────────────────────────────────────────────────────\nfunction wrapWords(el,dimOpacity){const spans=[];const walker=document.createTreeWalker(el,NodeFilter.SHOW_TEXT);const textNodes=[];let n;while(n=walker.nextNode()){const t=n;if(t.textContent?.trim())textNodes.push(t);}textNodes.forEach(textNode=>{const raw=textNode.textContent||\"\";const tokens=raw.split(/(\\s+)/);const frag=document.createDocumentFragment();tokens.forEach(token=>{if(!token)return;if(/^\\s+$/.test(token)){frag.appendChild(document.createTextNode(token));return;}const span=document.createElement(\"span\");span.textContent=token;span.style.cssText=`display:inline;opacity:${dimOpacity};will-change:opacity;`;spans.push(span);frag.appendChild(span);});textNode.parentNode?.replaceChild(frag,textNode);});return spans;}/**\n * @framerDisableUnlink\n * @framerIntrinsicWidth 140\n * @framerIntrinsicHeight 24\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight any\n */export default function TextRevealScroll({revealMode=\"chars\",startOffset=90,endOffset=30,dimOpacity=.2,showCanvas=true,style}){const overlayRef=React.useRef(null);const segmentsRef=React.useRef([]);const splitDoneRef=React.useRef(false);// Track viewport visibility — scroll/resize work is skipped when false\nconst isVisibleRef=React.useRef(false);// Pending rAF handle — used to cancel any in-flight frame on cleanup\nconst rafRef=React.useRef(0);const startOffsetRef=React.useRef(startOffset);const endOffsetRef=React.useRef(endOffset);const dimOpacityRef=React.useRef(dimOpacity);const revealModeRef=React.useRef(revealMode);startOffsetRef.current=startOffset;endOffsetRef.current=endOffset;dimOpacityRef.current=dimOpacity;revealModeRef.current=revealMode;const isCanvas=RenderTarget.current()===RenderTarget.canvas;const[isClient,setIsClient]=React.useState(false);React.useEffect(()=>setIsClient(true),[]);// Reset split state whenever reveal mode changes\nReact.useEffect(()=>{splitDoneRef.current=false;segmentsRef.current=[];},[revealMode]);React.useEffect(()=>{if(!isClient||isCanvas)return;// ── All cleanup handles collected here so one return clears everything ──\nlet initTimer=null;let intersectionObserver=null;let mutationObserver=null;// Bound listener refs so removeEventListener gets the exact same fn\nlet scrollHandler=null;let resizeHandler=null;// ── Core reveal calculation (called inside rAF) ────────────────────────\nconst computeReveal=()=>{// Guard: skip entirely when scrolled out of the expanded viewport margin\nif(!isVisibleRef.current)return;const els=findTargetEls(overlayRef);const anchor=findScrollAnchor(els);if(!anchor)return;const rect=anchor.getBoundingClientRect();const vh=window.innerHeight;const startPx=vh*(startOffsetRef.current/100);const endPx=vh*(endOffsetRef.current/100);const totalRange=rect.height+(startPx-endPx);const scrolled=startPx-rect.top;const progress=Math.min(Math.max(scrolled/totalRange,0),1);const total=segmentsRef.current.length;const litCount=Math.floor(progress*total);segmentsRef.current.forEach((seg,i)=>{if(i<litCount){seg.style.opacity=\"1\";}else if(i===litCount){const frac=progress*total-litCount;seg.style.opacity=String(dimOpacityRef.current+frac*(1-dimOpacityRef.current));}else{seg.style.opacity=String(dimOpacityRef.current);}});};// ── rAF-throttled wrapper — deduplicates rapid scroll/resize bursts ───\nconst scheduleReveal=()=>{// Cancel any frame already queued this tick\nif(rafRef.current)cancelAnimationFrame(rafRef.current);rafRef.current=requestAnimationFrame(computeReveal);};initTimer=setTimeout(()=>{if(splitDoneRef.current)return;const textElements=findTargetEls(overlayRef);if(textElements.length===0)return;// Wrap every paragraph and accumulate spans into one flat array\nconst allSegments=[];for(const el of textElements){const segs=revealModeRef.current===\"words\"?wrapWords(el,dimOpacityRef.current):wrapChars(el,dimOpacityRef.current);allSegments.push(...segs);}if(allSegments.length===0)return;segmentsRef.current=allSegments;splitDoneRef.current=true;// ── IntersectionObserver — gates all scroll/resize work ────────────\n// rootMargin: 200px above/below viewport so reveal starts slightly\n// before the element fully enters, preventing a pop-in flash\nconst anchor=findScrollAnchor(findTargetEls(overlayRef));if(anchor){intersectionObserver=new IntersectionObserver(entries=>{// isIntersecting = true → element is near/in viewport\nisVisibleRef.current=entries[0].isIntersecting;// Run one immediate update when entering the zone\nif(isVisibleRef.current)scheduleReveal();},{rootMargin:\"200px 0px 200px 0px\",threshold:0});intersectionObserver.observe(anchor);}// ── Scroll & resize listeners (work is skipped when offscreen) ────\nscrollHandler=scheduleReveal;resizeHandler=scheduleReveal;window.addEventListener(\"scroll\",scrollHandler,{passive:true});window.addEventListener(\"resize\",resizeHandler,{passive:true});// MutationObserver handles late-rendering CMS content\nmutationObserver=new MutationObserver(scheduleReveal);mutationObserver.observe(document.body,{childList:true,subtree:true});// Initial paint\nscheduleReveal();},150);// ── Single unified cleanup — clears timer, listeners, observers, rAF ──\nreturn()=>{if(initTimer!==null)clearTimeout(initTimer);if(rafRef.current)cancelAnimationFrame(rafRef.current);if(scrollHandler)window.removeEventListener(\"scroll\",scrollHandler);if(resizeHandler)window.removeEventListener(\"resize\",resizeHandler);if(intersectionObserver)intersectionObserver.disconnect();if(mutationObserver)mutationObserver.disconnect();};},[isClient,isCanvas,revealMode]);// ── Canvas placeholder ────────────────────────────────────────────────────\nif(isCanvas){if(!showCanvas)return /*#__PURE__*/_jsx(\"div\",{style:{width:\"100%\",height:\"100%\"}});const modeLabel=revealMode===\"words\"?\"Words\":\"Chars\";return /*#__PURE__*/_jsx(\"div\",{style:{width:\"140px\",height:\"24px\",display:\"flex\",alignItems:\"center\",justifyContent:\"center\",background:\"rgba(99,102,241,0.08)\",border:\"1.5px dashed rgba(99,102,241,0.5)\",borderRadius:6,color:\"rgba(99,102,241,0.8)\",fontFamily:\"monospace\",pointerEvents:\"none\",userSelect:\"none\",padding:\"4px 2px\",overflow:\"hidden\",letterSpacing:\"-0.06em\"},children:/*#__PURE__*/_jsxs(\"span\",{style:{fontSize:11},children:[\"✦ Text Reveal \\xb7 \",modeLabel]})});}return /*#__PURE__*/_jsx(\"div\",{ref:overlayRef,style:{position:\"absolute\",inset:0,pointerEvents:\"none\",background:\"transparent\"}});}TextRevealScroll.displayName=\"Text Reveal Scroll - Helper\";addPropertyControls(TextRevealScroll,{revealMode:{type:ControlType.Enum,title:\"Reveal By\",defaultValue:\"chars\",options:[\"chars\",\"words\"],optionTitles:[\"Characters\",\"Words\"],displaySegmentedControl:true,segmentedControlDirection:\"vertical\",description:\"Reveal text character by character or word by word.\"},startOffset:{type:ControlType.Number,title:\"Start %\",defaultValue:90,min:0,max:100,step:1,unit:\"%\",description:\"Viewport % from top where reveal begins.\"},endOffset:{type:ControlType.Number,title:\"End %\",defaultValue:30,min:0,max:100,step:1,unit:\"%\",description:\"Viewport % from top where reveal completes.\"},dimOpacity:{type:ControlType.Number,title:\"Dim Opacity\",defaultValue:.2,min:0,max:1,step:.05,description:\"Opacity of unrevealed segments.\"},showCanvas:{type:ControlType.Boolean,title:\"Canvas Preview\",defaultValue:true,enabledTitle:\"Visible\",disabledTitle:\"Hidden\",description:\"Show or hide the component placeholder on the canvas.\\n\\nMade with ❤️ by [Soyeb](https://framer.link/project)\\n*Version:* 2.1.0\"}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"TextRevealScroll\",\"slots\":[],\"annotations\":{\"framerSupportedLayoutWidth\":\"any\",\"framerIntrinsicHeight\":\"24\",\"framerContractVersion\":\"1\",\"framerDisableUnlink\":\"* @framerIntrinsicWidth 140\",\"framerSupportedLayoutHeight\":\"any\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./text_reveal_scroll_helper.map"],"mappings":"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"}