{"version":3,"file":"BalancedTextColumns.DXucptMs.mjs","names":["useRef","useState","useCallback"],"sources":["https:/framerusercontent.com/modules/uhyEFZAz7bsJG06SsVqq/J6bWCvvV4AZZ4LH6jZyI/BalancedTextColumns.js"],"sourcesContent":["// User instructions:\n// \"create a component where the user enters text, and it splits it into two columns equally sized in terms of text lines they carry. i should be able to handle number of columns 1-3, their widths and more relevant features\"\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{addPropertyControls,ControlType}from\"framer\";import{startTransition,useCallback,useEffect,useLayoutEffect,useRef,useState}from\"react\";/**\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n */export default function BalancedTextColumns(props){const{text,columns,gap,textColor,font,edgeAlign,equalSpan,singleAlign,style}=props;const equalSpanActive=!!equalSpan;const edgeAlignActive=edgeAlign&&columns>1&&!equalSpanActive;const containerRef=useRef(null);const measureRef=useRef(null);const[containerWidth,setContainerWidth]=useState(0);const[parts,setParts]=useState(()=>{const initial=(text??\"\").trim();const safeCols=Math.max(1,Math.round(columns||1));return safeCols===1?[initial]:Array.from({length:safeCols},()=>\"\");});const tokenize=useCallback(input=>{// Keep newlines meaningful, and split on spaces/tabs while preserving them.\n// Tokens are either \"\\n\" (or repeated) or \"word\" including trailing whitespace.\nconst tokens=[];const s=input??\"\";const re=/(\\r\\n|\\n|\\r)|([^\\S\\r\\n]+)|([^\\s\\r\\n]+)/g;let match;while(match=re.exec(s)){const nl=match[1];const ws=match[2];const word=match[3];if(nl)tokens.push(nl);else if(ws)tokens.push(ws);else if(word)tokens.push(word);}return tokens;},[]);const joinTokens=useCallback((tokens,start,end)=>{if(end<=start)return\"\";return tokens.slice(start,end).join(\"\");},[]);const measureHeight=useCallback((content,widthPx)=>{if(typeof window===\"undefined\")return 0;const el=measureRef.current;if(!el)return 0;el.style.width=`${Math.max(0,widthPx)}px`;el.textContent=content;return el.scrollHeight||0;},[]);const computeSplitsBalanced=useCallback(()=>{if(typeof window===\"undefined\")return;if(!containerRef.current)return;if(!measureRef.current)return;if(containerWidth<=0)return;const input=text??\"\";const safeCols=Math.max(1,Math.round(columns||1));if(safeCols===1){startTransition(()=>setParts([input]));return;}const tokens=tokenize(input);const n=tokens.length;if(n===0){startTransition(()=>setParts(Array.from({length:safeCols},()=>\"\")));return;}// Calculate each column width in px (gap-aware)\nconst totalGap=gap*(safeCols-1);const usable=Math.max(0,containerWidth-totalGap);const colWidthPx=Math.max(1,usable/safeCols);const fullHeightAtAvgWidth=measureHeight(joinTokens(tokens,0,n),colWidthPx);const targetPerColumn=Math.max(1,fullHeightAtAvgWidth/safeCols);let remainingCols=safeCols;let startIndex=0;const out=[];for(let col=0;col<safeCols;col++){remainingCols=safeCols-col;const widthPx=colWidthPx;if(remainingCols===1){out.push(joinTokens(tokens,startIndex,n));break;}const remainingText=joinTokens(tokens,startIndex,n);const remainingHeight=measureHeight(remainingText,widthPx);const target=Math.max(1,Math.min(remainingHeight,targetPerColumn));// Binary search the largest end index that does not exceed target height.\nlet lo=startIndex+1;let hi=n-(remainingCols-1)// keep at least 1 token per remaining column\n;let best=lo;while(lo<=hi){const mid=lo+hi>>1;const candidate=joinTokens(tokens,startIndex,mid);const h=measureHeight(candidate,widthPx);if(h<=target){best=mid;lo=mid+1;}else{hi=mid-1;}}// If best is too small (e.g., first token already exceeds target), ensure progress.\nif(best<=startIndex)best=Math.min(startIndex+1,n-(remainingCols-1));out.push(joinTokens(tokens,startIndex,best));startIndex=best;}while(out.length<safeCols)out.push(\"\");startTransition(()=>setParts(out.slice(0,safeCols)));},[columns,containerWidth,gap,joinTokens,measureHeight,text,tokenize]);const updateContainerWidth=useCallback(()=>{if(typeof window===\"undefined\")return;const el=containerRef.current;if(!el)return;const rect=el.getBoundingClientRect();const w=rect.width||0;startTransition(()=>setContainerWidth(w));},[]);useLayoutEffect(()=>{updateContainerWidth();// eslint-disable-next-line react-hooks/exhaustive-deps\n},[style?.width,style?.height,columns,gap]);useEffect(()=>{if(typeof window===\"undefined\")return;const el=containerRef.current;if(!el)return;let ro=null;if(typeof ResizeObserver!==\"undefined\"){ro=new ResizeObserver(()=>updateContainerWidth());ro.observe(el);}else{const onResize=()=>updateContainerWidth();window.addEventListener(\"resize\",onResize);return()=>window.removeEventListener(\"resize\",onResize);}return()=>{if(ro)ro.disconnect();};},[updateContainerWidth]);useEffect(()=>{computeSplitsBalanced();},[computeSplitsBalanced]);const isFixedWidth=!!style&&style.width===\"100%\";const columnTextAlign=useCallback(index=>{if(equalSpanActive)return\"justify\";if(!edgeAlignActive)return undefined;const safeCols=Math.max(1,Math.round(columns||1));if(safeCols<=1)return undefined;if(index===0)return\"right\";if(index===safeCols-1)return\"left\";return\"center\";},[columns,edgeAlignActive,equalSpanActive]);return /*#__PURE__*/_jsxs(\"div\",{ref:containerRef,style:{...style,position:\"relative\",width:\"100%\",height:\"100%\",overflow:\"hidden\",display:\"flex\",flexDirection:\"row\",gap,color:textColor,...font,...isFixedWidth?{}:{minWidth:\"max-content\"}},\"aria-label\":\"Balanced text columns\",children:[/*#__PURE__*/_jsx(\"div\",{ref:measureRef,\"aria-hidden\":\"true\",style:{position:\"absolute\",left:-99999,top:0,visibility:\"hidden\",pointerEvents:\"none\",whiteSpace:\"pre-wrap\",wordBreak:\"break-word\",overflowWrap:\"anywhere\",color:textColor,...font}}),Array.from({length:Math.max(1,Math.round(columns||1))},(_,i)=>{const content=parts[i]??\"\";return /*#__PURE__*/_jsx(\"div\",{style:{flex:1,height:\"100%\",overflow:\"hidden\",whiteSpace:\"pre-wrap\",wordBreak:\"break-word\",overflowWrap:\"anywhere\",textAlign:columnTextAlign(i)??(Math.max(1,Math.round(columns||1))===1?singleAlign:undefined),textJustify:equalSpanActive?\"inter-word\":undefined},children:content},i);})]});}addPropertyControls(BalancedTextColumns,{text:{type:ControlType.String,title:\"Text\",defaultValue:\"Paste your text here. The component will split it into balanced columns.\\n\\nResize the component to rebalance.\",displayTextArea:true},columns:{type:ControlType.Number,title:\"Columns\",defaultValue:2,min:1,max:8,step:1,displayStepper:true},gap:{type:ControlType.Number,title:\"Gap\",defaultValue:16,min:0,max:80,step:1,unit:\"px\"},textColor:{type:ControlType.Color,title:\"Text\",defaultValue:\"#000000\"},font:{type:ControlType.Font,title:\"Font\",controls:\"extended\",defaultFontType:\"sans-serif\",defaultValue:{fontSize:\"15px\",variant:\"Medium\",letterSpacing:\"-0.01em\",lineHeight:\"1.3em\"}},edgeAlign:{type:ControlType.Boolean,title:\"Edge Align\",defaultValue:false,enabledTitle:\"On\",disabledTitle:\"Off\",hidden:({columns,equalSpan})=>columns===1||!!equalSpan},equalSpan:{type:ControlType.Boolean,title:\"Equal Span\",defaultValue:false,enabledTitle:\"On\",disabledTitle:\"Off\",hidden:({edgeAlign,columns})=>columns>1?!!edgeAlign:false},singleAlign:{type:ControlType.Enum,title:\"Align\",options:[\"left\",\"center\",\"right\"],optionTitles:[\"Left\",\"Center\",\"Right\"],defaultValue:\"left\",displaySegmentedControl:true,hidden:({columns,equalSpan})=>columns!==1||!!equalSpan}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"BalancedTextColumns\",\"slots\":[],\"annotations\":{\"framerSupportedLayoutWidth\":\"any-prefer-fixed\",\"framerSupportedLayoutHeight\":\"any-prefer-fixed\",\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./BalancedTextColumns.map"],"mappings":"kOAKG,SAAwB,EAAoB,EAAM,CAAC,GAAK,CAAC,OAAK,UAAQ,MAAI,YAAU,OAAK,YAAU,YAAU,cAAY,SAAO,EAAY,EAAgB,CAAC,CAAC,EAAgB,EAAgB,GAAW,EAAQ,GAAG,CAAC,EAAsB,EAAaA,EAAO,IAAI,EAAQ,EAAWA,EAAO,IAAI,EAAO,CAAC,EAAe,GAAmBC,EAAS,CAAC,EAAO,CAAC,EAAM,GAAUA,MAAa,CAAC,IAAM,GAAS,GAAM,GAAA,CAAI,KAAK,EAAQ,EAAS,KAAK,IAAI,EAAE,KAAK,MAAM,GAAS,CAAC,CAAC,EAAE,OAAO,IAAW,EAAE,CAAC,CAAO,EAAE,MAAM,KAAK,CAAC,OAAO,CAAQ,MAAM,EAAE,CAAE,CAAC,EAAQ,EAASC,EAAY,GAAO,CAExjB,IAAM,EAAO,CAAC,EAAQ,EAAE,GAAO,GAAS,EAAG,0CAA8C,EAAM,KAAM,EAAM,EAAG,KAAK,CAAC,GAAE,CAAC,IAAM,EAAG,EAAM,GAAS,EAAG,EAAM,GAAS,EAAK,EAAM,GAAM,EAAG,EAAO,KAAK,CAAE,EAAU,EAAG,EAAO,KAAK,CAAE,EAAU,GAAK,EAAO,KAAK,CAAI,CAAE,CAAC,OAAO,CAAO,EAAE,CAAC,CAAC,EAAQ,EAAWA,GAAa,EAAO,EAAM,IAAU,GAAK,EAAY,GAAU,EAAO,MAAM,EAAM,CAAG,CAAC,CAAC,KAAK,EAAE,EAAI,CAAC,CAAC,EAAQ,EAAcA,GAAa,EAAQ,IAAU,CAAC,GAAU,IAAS,OAAY,MAAO,GAAE,IAAM,EAAG,EAAW,QAAyF,OAA7E,GAAY,EAAG,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAO,EAAE,IAAI,EAAG,YAAY,EAAe,EAAG,cAAc,GAA3F,CAA6F,EAAE,CAAC,CAAC,EAAQ,EAAsBA,MAAgB,CAAqG,GAA1F,IAAS,QAAsB,CAAC,EAAa,SAAkB,CAAC,EAAW,SAAkB,GAAgB,EAAE,OAAO,IAAM,EAAM,GAAM,GAAS,EAAS,KAAK,IAAI,EAAE,KAAK,MAAM,GAAS,CAAC,CAAC,EAAE,GAAG,IAAW,EAAE,CAAC,MAAoB,EAAS,CAAC,CAAK,CAAC,CAAC,EAAE,MAAO,CAAC,IAAM,EAAO,EAAS,CAAK,EAAQ,EAAE,EAAO,OAAO,GAAG,IAAI,EAAE,CAAC,MAAoB,EAAS,MAAM,KAAK,CAAC,OAAO,CAAQ,MAAM,EAAE,CAAC,CAAC,EAAE,MAAO,CAChjC,IAAM,EAAS,GAAK,EAAS,GAAS,EAAO,KAAK,IAAI,EAAE,EAAe,CAAQ,EAAQ,EAAW,KAAK,IAAI,EAAE,EAAO,CAAQ,EAAQ,EAAqB,EAAc,EAAW,EAAO,EAAE,CAAC,EAAE,CAAU,EAAQ,EAAgB,KAAK,IAAI,EAAE,EAAqB,CAAQ,EAAM,EAAc,EAAa,EAAW,EAAQ,EAAI,CAAC,EAAE,IAAI,IAAI,EAAI,EAAE,EAAI,EAAS,IAAM,CAAC,EAAc,EAAS,EAAI,IAAM,EAAQ,EAAW,GAAG,IAAgB,EAAE,CAAC,EAAI,KAAK,EAAW,EAAO,EAAW,CAAC,CAAC,EAAE,KAAM,CAAC,IAAM,EAAc,EAAW,EAAO,EAAW,CAAC,EAAQ,EAAgB,EAAc,EAAc,CAAO,EAAQ,EAAO,KAAK,IAAI,EAAE,KAAK,IAAI,EAAgB,CAAe,CAAC,EAC5oB,EAAG,EAAW,EAAM,EAAG,GAAG,EAAc,GACvC,EAAK,EAAG,KAAM,GAAI,GAAG,CAAC,IAAM,EAAI,EAAG,GAAI,EAAQ,EAAU,EAAW,EAAO,EAAW,CAAG,EAAU,EAAc,EAAU,CAAY,GAAG,GAAQ,EAAK,EAAI,EAAG,EAAI,GAAQ,EAAG,EAAI,CAAG,CACtL,GAAM,IAAW,EAAK,KAAK,IAAI,EAAW,EAAE,GAAG,EAAc,EAAE,GAAE,EAAI,KAAK,EAAW,EAAO,EAAW,CAAI,CAAC,EAAE,EAAW,CAAK,CAAC,KAAM,EAAI,OAAO,GAAS,EAAI,KAAK,EAAE,EAAE,MAAoB,EAAS,EAAI,MAAM,EAAE,CAAQ,CAAC,CAAC,CAAE,EAAE,CAAC,EAAQ,EAAe,EAAI,EAAW,EAAc,EAAK,CAAQ,CAAC,EAAQ,EAAqBA,MAAgB,CAAC,GAAU,IAAS,OAAY,OAAO,IAAM,EAAG,EAAa,QAAQ,GAAG,CAAC,EAAG,OAA6C,IAAM,EAAjC,EAAG,sBAAmC,CAAC,CAAC,OAAO,EAAE,MAAoB,EAAkB,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC,EAAE,MAAoB,CAAC,EAAqB,CACzjB,EAAE,CAAC,GAAO,MAAM,GAAO,OAAO,EAAQ,CAAG,CAAC,EAAE,MAAc,CAAC,GAAU,IAAS,OAAY,OAAO,IAAM,EAAG,EAAa,QAAQ,GAAG,CAAC,EAAG,OAAO,IAAI,EAAG,KAAK,GAAG,OAAO,eAAiB,IAAa,EAAG,IAAI,mBAAmB,EAAqB,CAAC,EAAE,EAAG,QAAQ,CAAE,MAAO,CAAC,IAAM,MAAa,EAAqB,EAA6C,OAA3C,EAAO,iBAAiB,SAAS,CAAQ,MAAY,EAAO,oBAAoB,SAAS,CAAQ,CAAE,CAAC,UAAU,CAAI,GAAG,EAAG,WAAW,CAAE,CAAE,EAAE,CAAC,CAAoB,CAAC,EAAE,MAAc,CAAC,EAAsB,CAAE,EAAE,CAAC,CAAqB,CAAC,EAAE,IAAM,EAAa,CAAC,CAAC,GAAO,EAAM,QAAQ,OAAa,EAAgBA,EAAY,GAAO,CAAC,GAAG,EAAgB,MAAM,UAAU,GAAG,CAAC,EAAgB,OAAiB,IAAM,EAAS,KAAK,IAAI,EAAE,KAAK,MAAM,GAAS,CAAC,CAAC,EAAK,QAAU,GAAiF,OAA3D,IAAQ,EAAQ,QAAW,IAAQ,EAAS,EAAQ,OAAa,QAAS,EAAE,CAAC,EAAQ,EAAgB,CAAe,CAAC,EAAE,OAAoB,EAAM,MAAM,CAAC,IAAI,EAAa,MAAM,CAAC,GAAG,EAAM,SAAS,WAAW,MAAM,OAAO,OAAO,OAAO,SAAS,SAAS,QAAQ,OAAO,cAAc,MAAM,MAAI,MAAM,EAAU,GAAG,EAAK,GAAG,EAAa,CAAC,EAAE,CAAC,SAAS,aAAa,CAAC,EAAE,aAAa,wBAAwB,SAAS,CAAc,EAAK,MAAM,CAAC,IAAI,EAAW,cAAc,OAAO,MAAM,CAAC,SAAS,WAAW,KAAK,OAAO,IAAI,EAAE,WAAW,SAAS,cAAc,OAAO,WAAW,WAAW,UAAU,aAAa,aAAa,WAAW,MAAM,EAAU,GAAG,CAAI,CAAC,CAAC,EAAE,MAAM,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,KAAK,MAAM,GAAS,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,IAAM,EAAQ,EAAM,IAAI,GAAG,OAAoB,EAAK,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,OAAO,SAAS,SAAS,WAAW,WAAW,UAAU,aAAa,aAAa,WAAW,UAAU,EAAgB,CAAC,IAAI,KAAK,IAAI,EAAE,KAAK,MAAM,GAAS,CAAC,CAAC,IAAI,EAAE,EAAY,IAAA,IAAW,YAAY,EAAgB,aAAa,IAAA,EAAS,EAAE,SAAS,CAAO,EAAE,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAE,qBAVtvD,IAAoD,IAAyF,EAU0mD,EAAoB,EAAoB,CAAC,KAAK,CAAC,KAAK,EAAY,OAAO,MAAM,OAAO,aAAa;;oCAAiH,gBAAgB,EAAI,EAAE,QAAQ,CAAC,KAAK,EAAY,OAAO,MAAM,UAAU,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAI,EAAE,IAAI,CAAC,KAAK,EAAY,OAAO,MAAM,MAAM,aAAa,GAAG,IAAI,EAAE,IAAI,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU,CAAC,KAAK,EAAY,MAAM,MAAM,OAAO,aAAa,SAAS,EAAE,KAAK,CAAC,KAAK,EAAY,KAAK,MAAM,OAAO,SAAS,WAAW,gBAAgB,aAAa,aAAa,CAAC,SAAS,OAAO,QAAQ,SAAS,cAAc,UAAU,WAAW,OAAO,CAAC,EAAE,UAAU,CAAC,KAAK,EAAY,QAAQ,MAAM,aAAa,aAAa,GAAM,aAAa,KAAK,cAAc,MAAM,QAAQ,CAAC,UAAQ,eAAa,IAAU,GAAG,CAAC,CAAC,CAAS,EAAE,UAAU,CAAC,KAAK,EAAY,QAAQ,MAAM,aAAa,aAAa,GAAM,aAAa,KAAK,cAAc,MAAM,QAAQ,CAAC,YAAU,aAAW,EAAQ,GAAE,CAAC,CAAC,CAAe,EAAE,YAAY,CAAC,KAAK,EAAY,KAAK,MAAM,QAAQ,QAAQ,CAAC,OAAO,SAAS,OAAO,EAAE,aAAa,CAAC,OAAO,SAAS,OAAO,EAAE,aAAa,OAAO,wBAAwB,GAAK,QAAQ,CAAC,UAAQ,eAAa,IAAU,GAAG,CAAC,CAAC,CAAS,CAAC,CAAC"}