UNPKG

react-active-menu

Version:

A React hook to build an active scrolling menu navigation.

3 lines (2 loc) 1.81 kB
import{jsx as e}from"react/jsx-runtime";import{createContext as t,useState as r,useRef as n,useEffect as o,useContext as s}from"react";const i=t({}),c=({children:t,menu:r})=>e(i.Provider,Object.assign({value:r},{children:t})),l=e=>{let t=0;for(;e;)t+=e.offsetTop,e=e.offsetParent;return t},a=(e={})=>{const{activeClassName:t="active",offset:s=0,smooth:i=!1}=e,[c,a]=r(),d=n(),f=n(new Map),u=n(new Map);return o((()=>{const e=d.current,t=f.current;if(t.size){const r=()=>{let r,n,o=-1/0;for(const[i,c]of t.entries()){const{top:t=0}=(null==e?void 0:e.getBoundingClientRect())||{},{top:l}=c.getBoundingClientRect();l<=0+t+s&&l>o&&(o=l,r=i),n||(n=i)}a(r||n)};return r(),window.addEventListener("resize",r),e?(e.addEventListener("scroll",r),()=>{window.removeEventListener("resize",r),e.removeEventListener("scroll",r)}):(window.addEventListener("scroll",r),()=>{window.removeEventListener("resize",r),window.removeEventListener("scroll",r)})}}),[s]),o((()=>{const e=d.current,t=f.current,r=u.current;if(t.size&&r.size){const n=r=>n=>{n.preventDefault();const o=t.get(r);if(o&&n.target instanceof HTMLElement)if(e){const{top:t}=e.getBoundingClientRect();e.scrollTo({behavior:i?"smooth":"auto",top:l(o)-t-s})}else window.scrollTo({behavior:i?"smooth":"auto",top:l(o)-s})};let o=[];for(const[e,t]of r.entries()){const r=n(e);t.addEventListener("click",r),o.push((()=>t.removeEventListener("click",r)))}return()=>{for(const e of o)e()}}}),[s,i]),o((()=>{const e=u.current;if(e.size)for(const[r,n]of e.entries())n.classList.remove(t),r===c&&n.classList.add(t)}),[t,c]),{activeId:c,registerContainer:e=>d.current=e,registerSection:e=>t=>f.current.set(e,t),registerTrigger:e=>t=>u.current.set(e,t)}},d=()=>s(i);export{c as ActiveMenuProvider,a as useActiveMenu,d as useActiveMenuContext}; //# sourceMappingURL=index.js.map