{"version":3,"file":"Counter.Dx-R2KuC.mjs","names":["useState","useRef"],"sources":["https:/framerusercontent.com/modules/9Zaj5WOlsZ7mqvCsznr0/9mliSCWtCTsLMFWz0K74/Counter.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useState,useEffect,useRef}from\"react\";import{motion}from\"framer-motion\";import{addPropertyControls,ControlType}from\"framer\";/**\n * @framerDisableUnlink\n */export function Counter({start=\"0\",end=\"1000\",speedPercent=100,gapSize=4,prefixText=\"\",suffixText=\"\",prefixFont,suffixFont,prefixColor,suffixColor,loop=false,decimalSeparatorType=\"comma\",selectedFont={fontFamily:\"Inter\",fontWeight:500,fontSize:36,letterSpacing:0,lineHeight:1,textAlign:\"left\"},textColor=\"#D3D3D3\",restartOnViewport=false,incrementType=\"integer\"}){function parseNumber(value){if(typeof value===\"number\")return value;if(typeof value!==\"string\")return 0;const s=value.trim();if(s===\"\")return 0;const hasDot=s.indexOf(\".\")!==-1;const hasComma=s.indexOf(\",\")!==-1;let normalized=s;if(hasDot&&hasComma){// Assume comma is thousands separator\nnormalized=s.replace(/,/g,\"\");}else if(hasComma&&!hasDot){// Assume comma is decimal separator\nnormalized=s.replace(/,/g,\".\");}else{// Only dots or neither: strip commas as thousands separators\nnormalized=s.replace(/,/g,\"\");}const n=parseFloat(normalized);return Number.isFinite(n)?n:0;}const[count,setCount]=useState(()=>parseNumber(start));const[isVisible,setIsVisible]=useState(false);const containerRef=useRef(null);const rafRef=useRef(null);const startTimestampRef=useRef(null);const runningRef=useRef(false);const hasAnimatedRef=useRef(false)// tracks if we've already run once\n;// Observe viewport visibility\nuseEffect(()=>{if(!containerRef.current)return;const observer=new IntersectionObserver(([entry])=>{if(!entry)return;setIsVisible(entry.isIntersecting);});observer.observe(containerRef.current);return()=>{observer.disconnect();};},[]);// Keep internal number in sync with props when they change\nuseEffect(()=>{setCount(parseNumber(start));},[start]);// Animation effect: starts when element enters viewport\nuseEffect(()=>{if(!isVisible)return;// If we've already animated and replay is off, do nothing\nif(!restartOnViewport&&hasAnimatedRef.current){return;}const from=parseNumber(start);const to=parseNumber(end);if(from===to){setCount(to);hasAnimatedRef.current=true;return;}const safeSpeed=typeof speedPercent===\"number\"&&speedPercent>0?speedPercent:100;const durationMs=100/safeSpeed*1e3;const incrementPrecision=incrementType===\"integer\"?0:1;let cancel=false;runningRef.current=true;startTimestampRef.current=null;setCount(from)// reset to start on each run\n;const step=timestamp=>{if(cancel)return;if(!startTimestampRef.current){startTimestampRef.current=timestamp;}const elapsed=timestamp-startTimestampRef.current;const t=Math.min(1,elapsed/durationMs);const current=from+(to-from)*t;const fixed=incrementPrecision===0?Math.round(current):Math.round(current*10)/10;setCount(fixed>=to?to:fixed);if(t<1){rafRef.current=requestAnimationFrame(step);}else{runningRef.current=false;if(loop){// For looping, immediately start again from \"from\" to \"to\"\nstartTimestampRef.current=null;setCount(from);rafRef.current=requestAnimationFrame(step);}else{hasAnimatedRef.current=true;}}};rafRef.current=requestAnimationFrame(step);return()=>{cancel=true;if(rafRef.current!==null){cancelAnimationFrame(rafRef.current);}rafRef.current=null;runningRef.current=false;};// eslint-disable-next-line react-hooks/exhaustive-deps\n},[isVisible,restartOnViewport,speedPercent,incrementType,start,end,loop]);const formatNumber=number=>{if(decimalSeparatorType===\"comma\"){return number.toLocaleString(\"en-US\");}if(decimalSeparatorType===\"period\"){return number.toLocaleString(\"en-US\").replace(/,/g,\".\");}return number.toFixed(incrementType===\"integer\"?0:1);};// ---- FONT STYLES ----\nconst baseFontStyle=selectedFont||{};const align=baseFontStyle.textAlign||\"left\";const justifyContent=align===\"center\"?\"center\":align===\"right\"?\"flex-end\":align===\"justify\"?\"space-between\":\"flex-start\";const prefixStyle={...baseFontStyle,...prefixFont||{},color:prefixColor||textColor};const numberStyle={...baseFontStyle,color:textColor};const suffixStyle={...baseFontStyle,...suffixFont||{},color:suffixColor||textColor};return /*#__PURE__*/_jsxs(motion.div,{ref:containerRef,style:{display:\"flex\",gap:`${gapSize}px`,alignItems:\"end\",justifyContent,...baseFontStyle,color:textColor},children:[prefixText&&/*#__PURE__*/_jsx(\"span\",{style:prefixStyle,children:prefixText}),/*#__PURE__*/_jsx(\"span\",{style:numberStyle,children:formatNumber(count)}),suffixText&&/*#__PURE__*/_jsx(\"span\",{style:suffixStyle,children:suffixText})]});}addPropertyControls(Counter,{restartOnViewport:{type:ControlType.Boolean,title:\"Replay\",defaultValue:false},selectedFont:{title:\"Font\",type:ControlType.Font,controls:\"extended\",// optional, but nice to mirror your JS defaults\ndefaultValue:{fontFamily:\"Inter\",fontWeight:500,fontSize:36,letterSpacing:0,lineHeight:1.05,textAlign:\"left\"}},textColor:{type:ControlType.Color,title:\"Font Color\"},start:{type:ControlType.String,title:\"Start (text)\",defaultValue:\"0\"},end:{type:ControlType.String,title:\"End (text)\",defaultValue:\"10\"},decimalSeparatorType:{type:ControlType.Enum,title:\"Separator\",defaultValue:\"comma\",options:[\"comma\",\"period\",\"none\"]},incrementType:{type:ControlType.Enum,title:\"Increment Type\",defaultValue:\"integer\",options:[\"integer\",\"decimal\"]},prefixText:{type:ControlType.String,title:\"Prefix\",defaultValue:\"\"},prefixFont:{title:\"Prefix Font\",type:ControlType.Font,controls:\"extended\"},prefixColor:{type:ControlType.Color,title:\"Prefix Color\"},suffixText:{type:ControlType.String,title:\"Suffix\",defaultValue:\"\"},suffixFont:{title:\"Suffix Font\",type:ControlType.Font,controls:\"extended\"},suffixColor:{type:ControlType.Color,title:\"Suffix Color\"},gapSize:{type:ControlType.Number,title:\"Gap Size\",defaultValue:4,min:0,max:100},speedPercent:{type:ControlType.Number,title:\"Speed (%)\",defaultValue:100,min:1,max:1e3,step:1},loop:{type:ControlType.Boolean,title:\"Loop Animation\",defaultValue:false,description:\"Component from [Windaro](https://windaro.com?utm_source=codecomponent)\"}});\nexport const __FramerMetadata__ = {\"exports\":{\"Counter\":{\"type\":\"reactComponent\",\"name\":\"Counter\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerDisableUnlink\":\"\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./Counter.map"],"mappings":"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"}