{"version":3,"file":"CurvedLoopText_Prod.CnC6Wcrx.mjs","names":["useRef","useState","useMemo","_Fragment"],"sources":["https:/framerusercontent.com/modules/XjyaAMlQm1XKl2jNPVh7/1TBOywuUilFcHkd21E9P/CurvedLoopText_Prod.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from\"react/jsx-runtime\";import{useRef,useEffect,useState,useMemo}from\"react\";import{motion,useAnimationFrame,useMotionValue,useTransform}from\"framer-motion\";import{ControlType,addPropertyControls}from\"framer\";// ------------------------------------------------------------ //\n// MAIN COMPONENT\n// ------------------------------------------------------------ //\n/**\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n * @framerIntrinsicWidth 400\n * @framerIntrinsicHeight 200\n * @framerDisableUnlink\n */export default function CurvedLoop(props){const measureRef=useRef(null);const tspansRef=useRef([]);const pathRef=useRef(null);const[pathLength,setPathLength]=useState(0);const[spacing,setSpacing]=useState(0);// Use completely static IDs based on component props to ensure consistency\nconst staticId=useMemo(()=>{// Create a deterministic hash from props that will be consistent across SSR/client\nconst propsString=`${props.text.text}-${props.curveAmount}-${props.direction}-${props.baseVelocity}`;let hash=0;for(let i=0;i<propsString.length;i++){const char=propsString.charCodeAt(i);hash=(hash<<5)-hash+char;hash=hash&hash// Convert to 32-bit integer\n;}return Math.abs(hash).toString(36);},[props.text.text,props.curveAmount,props.direction,props.baseVelocity]);const pathId=`curve-${staticId}`;const fadeGradientId=`fadeGradient-${staticId}`;const fadeMaskId=`fadeMask-${staticId}`;const pathD=`M-100,400 Q720,${400+props.curveAmount} 1540,400`;const defaultVelocity=useMotionValue(1);const isDragging=useRef(false);const dragVelocity=useRef(0);// Transform scroll velocity into a factor that affects marquee speed\nconst velocityFactor=useTransform(defaultVelocity,[0,1e3],[0,5],{clamp:false});// Convert baseVelocity to the correct direction\nconst actualBaseVelocity=props.direction===\"left\"?-props.baseVelocity:props.baseVelocity;// Reference to track if mouse is hovering\nconst isHovered=useRef(false);// Direction factor for changing direction based on scroll or drag\nconst directionFactor=useRef(1);// Process text to ensure proper spacing\nconst processedText=useMemo(()=>{// Remove any trailing spaces first\nconst trimmedText=props.text.text.trim();// Add two non-breaking spaces to ensure visible gap\nreturn trimmedText+\"\\xa0\\xa0\";},[props]);// Measure text width and set up path\nuseEffect(()=>{if(measureRef.current){setSpacing(measureRef.current.getComputedTextLength());}},[props]);useEffect(()=>{if(pathRef.current){setPathLength(pathRef.current.getTotalLength());}},[props.curveAmount]);// Calculate number of repeats needed based on path length and text spacing\nconst calculatedRepeats=Math.ceil(pathLength/spacing)+2;const ready=pathLength>0&&spacing>0;useAnimationFrame((t,delta)=>{if(!ready||tspansRef.current.length===0)return;if(isDragging.current){// Apply drag velocity directly to text positions\ntspansRef.current.forEach(tspan=>{if(!tspan)return;let x=parseFloat(tspan.getAttribute(\"x\")||\"0\");x+=dragVelocity.current;// Wrap text around when it goes off screen\nconst maxX=(tspansRef.current.length-1)*spacing;if(x<-spacing)x=maxX;if(x>maxX)x=-spacing;tspan.setAttribute(\"x\",x.toString());});// Add decay to dragVelocity when not moving\ndragVelocity.current*=.9;// Stop completely if velocity is very small\nif(Math.abs(dragVelocity.current)<.01){dragVelocity.current=0;}return;}// Calculate regular movement\nlet moveBy=directionFactor.current*actualBaseVelocity*(delta/1e3);// Adjust movement based on scroll velocity\nif(!isDragging.current){if(velocityFactor.get()<0){directionFactor.current=-1;}else if(velocityFactor.get()>0){directionFactor.current=1;}}moveBy+=directionFactor.current*moveBy*velocityFactor.get();moveBy+=dragVelocity.current;// Gradually decay drag velocity back to zero\nif(!isDragging.current&&Math.abs(dragVelocity.current)>.01){dragVelocity.current*=.96;}else if(!isDragging.current){dragVelocity.current=0;}// Apply movement to each text span\ntspansRef.current.forEach(tspan=>{if(!tspan)return;let x=parseFloat(tspan.getAttribute(\"x\")||\"0\");x+=moveBy;// Wrap text around when it goes off screen\nconst maxX=(tspansRef.current.length-1)*spacing;if(x<-spacing)x=maxX;if(x>maxX)x=-spacing;tspan.setAttribute(\"x\",x.toString());});});const lastPointerPosition=useRef({x:0,y:0});const handlePointerDown=e=>{if(!props.draggable)return;e.currentTarget.setPointerCapture(e.pointerId);e.currentTarget.style.cursor=\"grabbing\";isDragging.current=true;lastPointerPosition.current={x:e.clientX,y:e.clientY};// Pause automatic animation by setting velocity to 0\ndragVelocity.current=0;};const handlePointerMove=e=>{if(!props.draggable)return;if(!isDragging.current)return;const currentPosition={x:e.clientX,y:e.clientY};// Calculate delta from last position\nconst deltaX=currentPosition.x-lastPointerPosition.current.x;// Update drag velocity based on horizontal movement\ndragVelocity.current=deltaX*.3;// Update last position\nlastPointerPosition.current=currentPosition;};const handlePointerUp=e=>{if(!props.draggable)return;e.currentTarget.releasePointerCapture(e.pointerId);e.currentTarget.style.cursor=\"grab\";isDragging.current=false;};const cursorStyle=props.draggable?isDragging.current?\"grabbing\":\"grab\":\"default\";return /*#__PURE__*/_jsx(motion.div,{onHoverStart:()=>isHovered.current=true,onHoverEnd:()=>isHovered.current=false,style:{visibility:ready?\"visible\":\"hidden\",minHeight:\"100vh\",width:\"100%\",height:\"100%\",display:\"flex\",alignItems:\"center\",justifyContent:\"center\"},children:/*#__PURE__*/_jsxs(\"svg\",{viewBox:\"0 0 1440 800\",style:{position:\"absolute\",top:\"50%\",left:\"50%\",transform:\"translate(-50%, -50%)\",userSelect:\"none\",width:\"100%\",aspectRatio:\"1440 / 800\",overflow:\"visible\",display:\"block\",fill:props.text.color,fontFamily:props.text.font.fontFamily,fontSize:props.text.font.fontSize,letterSpacing:props.text.font.letterSpacing,lineHeight:props.text.font.lineHeight},children:[/*#__PURE__*/_jsx(\"text\",{ref:measureRef,xmlSpace:\"preserve\",style:{visibility:\"hidden\",opacity:0,pointerEvents:\"none\",cursor:cursorStyle},children:processedText}),/*#__PURE__*/_jsxs(\"defs\",{children:[/*#__PURE__*/_jsx(\"path\",{ref:pathRef,id:pathId,d:pathD,fill:\"none\",stroke:\"transparent\"}),props.fade&&/*#__PURE__*/_jsxs(_Fragment,{children:[/*#__PURE__*/_jsxs(\"linearGradient\",{id:fadeGradientId,x1:\"0%\",y1:\"0%\",x2:\"100%\",y2:\"0%\",children:[/*#__PURE__*/_jsx(\"stop\",{offset:\"0%\",stopColor:\"white\",stopOpacity:\"0\"}),/*#__PURE__*/_jsx(\"stop\",{offset:\"15%\",stopColor:\"white\",stopOpacity:\"1\"}),/*#__PURE__*/_jsx(\"stop\",{offset:\"80%\",stopColor:\"white\",stopOpacity:\"1\"}),/*#__PURE__*/_jsx(\"stop\",{offset:\"100%\",stopColor:\"white\",stopOpacity:\"0\"})]}),/*#__PURE__*/_jsx(\"mask\",{id:fadeMaskId,children:/*#__PURE__*/_jsx(\"rect\",{width:\"100%\",height:\"100%\",fill:`url(#${fadeGradientId})`})})]})]}),ready&&/*#__PURE__*/_jsx(\"text\",{fontWeight:props.text.font.fontWeight,xmlSpace:\"preserve\",mask:props.fade?`url(#${fadeMaskId})`:undefined,onPointerDown:handlePointerDown,onPointerMove:handlePointerMove,onPointerUp:handlePointerUp,onPointerCancel:handlePointerUp,children:/*#__PURE__*/_jsx(\"textPath\",{href:`#${pathId}`,xmlSpace:\"preserve\",children:Array.from({length:calculatedRepeats}).map((_,i)=>/*#__PURE__*/_jsx(\"tspan\",{x:i*spacing,ref:el=>{if(el)tspansRef.current[i]=el;},children:processedText},i))})})]})});}// ------------------------------------------------------------ //\n// PROPERTY CONTROLS\n// ------------------------------------------------------------ //\naddPropertyControls(CurvedLoop,{text:{type:ControlType.Object,controls:{text:{type:ControlType.String},font:{type:ControlType.Font,defaultFontType:\"sans-serif\",controls:\"extended\",defaultValue:{letterSpacing:\"1px\",lineHeight:\"1.5em\",textAlign:\"left\",fontSize:64}},color:{type:ControlType.Color}}},direction:{type:ControlType.Enum,options:[\"left\",\"right\"],optionTitles:[\"Left\",\"Right\"],defaultValue:\"left\",optionIcons:[\"direction-left\",\"direction-right\"],displaySegmentedControl:true},baseVelocity:{type:ControlType.Number,title:\"Speed\",min:0,max:500,step:1,defaultValue:50},curveAmount:{type:ControlType.Number,title:\"Curve\",min:-1e3,max:1e3,step:1,defaultValue:300},draggable:{type:ControlType.Boolean,title:\"Draggable\",defaultValue:true},fade:{type:ControlType.Boolean,title:\"Fade\",defaultValue:true,description:\"More components at [Framer University](https://frameruni.link/cc).\"}});// ------------------------------------------------------------ //\n// DEFAULT PROPS\n// ------------------------------------------------------------ //\nCurvedLoop.defaultProps={text:{text:\"Framer University\",font:{fontFamily:\"sans-serif\",fontWeight:\"400\",fontSize:64},color:\"#999999\"},direction:\"left\",baseVelocity:50,curveAmount:300,draggable:true,fade:true};CurvedLoop.displayName=\"Curved Loop Text\";\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"CurvedLoop\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerSupportedLayoutWidth\":\"any-prefer-fixed\",\"framerSupportedLayoutHeight\":\"any-prefer-fixed\",\"framerDisableUnlink\":\"\",\"framerIntrinsicHeight\":\"200\",\"framerIntrinsicWidth\":\"400\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./CurvedLoopText_Prod.map"],"mappings":"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"}