{"version":3,"file":"TableOfContent.CUdB0bzy.mjs","names":["React","useState","_Fragment","root"],"sources":["https:/framerusercontent.com/modules/lu5jarNNIR0m5HQds7hZ/f3nChf9MZ8WnddWgAiVv/TableOfContent.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from\"react/jsx-runtime\";import React,{useEffect,useState}from\"react\";// ❌ 기존 createStore는 더 이상 사용 안 함\n// import { createStore } from \"https://framer.com/m/framer/store.js@^1.0.0\"\n// h2 / h3만 TOC에 표시\nconst HEADING_TO_DISPLAY=[\"h2\",\"h3\"];// 상단 고정 헤더 높이 (스크롤 시 여유)\nconst HEADER_OFFSET=120;const SCROLL_MARGIN_TOP=120;/* -----------------------------------------\n *  ✅ useSyncExternalStore 기반 커스텀 store\n * ----------------------------------------*/// 실제 상태\nlet storeState={headingsByPath:{}};// 구독자 리스트\nconst storeListeners=new Set;function subscribeStore(listener){storeListeners.add(listener);return()=>storeListeners.delete(listener);}function getStoreSnapshot(){return storeState;}// 상태 업데이트 + 구독자 통지\nfunction setStoreState(updater){const next=typeof updater===\"function\"?updater(storeState):updater;// 얕은 비교로 동일하면 패스\nif(next===storeState)return;storeState=next;storeListeners.forEach(fn=>fn());}// 🔧 이 훅 안에서 useSyncExternalStore 사용\nfunction useStore(){const state=React.useSyncExternalStore(subscribeStore,getStoreSnapshot,getStoreSnapshot);return[state,setStoreState];}// 텍스트를 id로 변환 (한글 포함)\nfunction slugify(text,index){let id=text.trim().toLowerCase().replace(RegExp(\"[^\\\\p{L}\\\\p{N}]+\",\"gu\"),\"-\").replace(/^-+|-+$/g,\"\");if(!id)id=`section-${index}`;return id;}function equalHeadingLists(a=[],b=[]){if(a.length!==b.length)return false;for(let i=0;i<a.length;i++){const x=a[i];const y=b[i];if(!x||!y)return false;if(x.id!==y.id||x.text!==y.text||x.type!==y.type)return false;}return true;}function getCurrentPathKey(){if(typeof window===\"undefined\")return\"default\";return window.location.pathname||\"default\";}// -----------------------------------------\n// 오른쪽 목차용 HOC\n// -----------------------------------------\nexport function withTableOfContent(Component){return props=>{const[store]=useStore();const pathKey=getCurrentPathKey();const headings=store.headingsByPath[pathKey]||[];const[mount,setMount]=useState(false);const[activeId,setActiveId]=useState(null);useEffect(()=>{setMount(true);return()=>setMount(false);},[]);const scrollToId=id=>{if(typeof document===\"undefined\")return;const element=document.getElementById(id);if(!element)return;const rect=element.getBoundingClientRect();const targetY=rect.top+window.scrollY-HEADER_OFFSET;// ✅ 스무스 스크롤 제거: 즉시 이동\nwindow.scrollTo({top:targetY});// 클릭 시 바로 active 표시\nsetActiveId(id);};// 🔥 스크롤 위치 기준으로 active heading 계산 (모바일 대응 강화)\nuseEffect(()=>{if(typeof window===\"undefined\")return;if(!headings.length)return;const getScrollY=()=>window.scrollY??window.pageYOffset??document.documentElement.scrollTop??0;const handleScroll=()=>{const scrollY=getScrollY();const viewportTop=scrollY+HEADER_OFFSET+10;let currentId=null;for(let i=0;i<headings.length;i++){const h=headings[i];const el=document.getElementById(h.id);if(!el)continue;const rect=el.getBoundingClientRect();const elTop=rect.top+getScrollY();if(elTop<=viewportTop){currentId=h.id;}else{break;}}if(!currentId&&headings[0]){currentId=headings[0].id;}setActiveId(prev=>prev===currentId?prev:currentId);};// 기본 한 번 계산\nhandleScroll();const isTouchDevice=\"ontouchstart\"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0;// 👇 iOS / 모바일용 폴링 루프\nlet rafId=null;let lastScrollY=getScrollY();const loop=()=>{const current=getScrollY();if(current!==lastScrollY){lastScrollY=current;handleScroll();}rafId=window.requestAnimationFrame(loop);};if(isTouchDevice){rafId=window.requestAnimationFrame(loop);}// 기본 이벤트 리스너 (데스크톱 + 대부분 브라우저)\nwindow.addEventListener(\"scroll\",handleScroll,{passive:true});window.addEventListener(\"resize\",handleScroll);window.addEventListener(\"orientationchange\",handleScroll);window.addEventListener(\"touchmove\",handleScroll,{passive:true});return()=>{window.removeEventListener(\"scroll\",handleScroll);window.removeEventListener(\"resize\",handleScroll);window.removeEventListener(\"orientationchange\",handleScroll);window.removeEventListener(\"touchmove\",handleScroll);if(rafId!=null){window.cancelAnimationFrame(rafId);}};},[headings,pathKey]);if(!mount)return null;if(headings.length===0||typeof window===\"undefined\"){return /*#__PURE__*/_jsx(Component,{...props});}return /*#__PURE__*/_jsx(_Fragment,{children:headings.slice().sort((a,b)=>a.index-b.index).map(({id,text,type,index})=>{const isActive=id===activeId;const level=type===\"h2\"?2:3;const variant=type===\"h2\"?isActive?\"h2 active\":\"h2\":isActive?\"h3 active\":\"h3\";return /*#__PURE__*/_jsx(\"div\",{style:{marginLeft:type===\"h3\"?16:0},children:/*#__PURE__*/_jsx(Component,{...props,h2:text,h3:text,level:level,variant:variant,onClick:()=>scrollToId(id)})},id||`${index}-${text}`);})});};}export function LabelComponent(props){return null;}// -----------------------------------------\n// 본문 래퍼용 HOC (DOM 기반 Collector)\n//  → ✅ display: contents 로 레이아웃 깨지지 않게 수정\n// -----------------------------------------\nexport function withContent(Component){return props=>{const[store]=useStore();const pathKey=getCurrentPathKey();useEffect(()=>{if(typeof document===\"undefined\")return;const collectFromDOM=()=>{const root=document.getElementById(\"toc-content-root\")??document.body;if(!root)return;const nodes=Array.from(root.querySelectorAll(\"h2, h3\"));const headings=nodes.map((node,index)=>{const text=(node.textContent||\"\").trim();const type=node.tagName.toLowerCase();const id=node.id&&node.id.length>0?node.id:slugify(text||`section-${index}`,index);if(!node.id)node.id=id;return{id,text,type,index};});const prev=store.headingsByPath?.[pathKey]||[];if(equalHeadingLists(prev,headings))return;setStoreState(prevState=>({...prevState,headingsByPath:{...prevState.headingsByPath||{},[pathKey]:headings}}));};collectFromDOM();const timer=setTimeout(collectFromDOM,0);const root=document.getElementById(\"toc-content-root\")??document.body;const observer=new MutationObserver(()=>{collectFromDOM();});if(root){observer.observe(root,{childList:true,subtree:true,characterData:true});}return()=>{clearTimeout(timer);observer.disconnect();};},[pathKey,store.headingsByPath]);return /*#__PURE__*/_jsxs(_Fragment,{children:[/*#__PURE__*/_jsx(\"style\",{children:`\n                    h1[id], h2[id], h3[id], h4[id], h5[id], h6[id] {\n                        scroll-margin-top: ${SCROLL_MARGIN_TOP}px;\n                    }\n                `}),/*#__PURE__*/_jsx(\"div\",{id:\"toc-content-root\",// ✅ 레이아웃에 박스를 만들지 않게 해서\n//    Rich Text + Table 구조 안 깨지도록\nstyle:{display:\"contents\"},children:/*#__PURE__*/_jsx(Component,{...props})})]});};}// 아래 두 함수는 지금은 안 써도 되지만, 혹시 children 기반 파싱으로 돌아갈 때를 위해 남겨둔 상태\nfunction formatTableOfContent(children){const result=[];const list=Array.isArray(children)?children:[children];list.filter(item=>item&&typeof item.type===\"string\"&&[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"].includes(item.type)).forEach((item,index)=>{const{id,text}=extractHeadingTextAndId(item.props?.children,index);result.push({id,text,type:item.type,index});});return result;}function extractHeadingTextAndId(children,index){let text=\"\";if(typeof children===\"string\"){text=children;}else if(Array.isArray(children)){text=children.map(item=>{if(typeof item===\"string\")return item.trim();if(item?.type===\"br\")return\"\";return(item?.props?.children||\"\").toString().trim();}).join(\" \");}else if(children?.props?.children){text=children.props.children.toString();}else{text=`section-${index}`;}const id=slugify(text,index);return{id,text};}\nexport const __FramerMetadata__ = {\"exports\":{\"LabelComponent\":{\"type\":\"function\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withContent\":{\"type\":\"reactHoc\",\"name\":\"withContent\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withTableOfContent\":{\"type\":\"reactHoc\",\"name\":\"withTableOfContent\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./TableOfContent.map"],"mappings":"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"}