react-anchor-navigation
Version:
React lightweight library for anchor scrolling and navigation tied to URL hash.
7 lines (6 loc) • 3.51 kB
JavaScript
/**
* @license react-anchor-navigation 0.2.7
* MIT License
* License: MIT
*/
import e,{createContext as t,useContext as r,useState as n,useEffect as s,useRef as c}from"react";var o=()=>{},a=t({offset:0,sections:[],hash:"",registerSection:o,unregisterSection:o,setHash:o});function i(){return(i=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}function l(e,t){if(null==e)return{};var r,n,s=function(e,t){if(null==e)return{};var r,n,s={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(s[r]=e[r]);return s}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(s[r]=e[r])}return s}var u=["children","className","activeClassName"];function v(t){var{children:n,className:s,activeClassName:c}=t,o=l(t,u),{hash:v}=r(a),f=(s?"".concat(s," "):"")+(v===o.href?c:"");return e.createElement("a",i({},o,{className:f}),n)}var f="undefined"!=typeof addEventListener&&(()=>{var e=!1;try{var t=()=>{},r=Object.defineProperty({},"passive",{get:()=>e=!0});addEventListener("testPassive",t,r),removeEventListener("testPassive",t,r)}catch(e){}return e})();var h=(e,t)=>{var r=0,n=e;do{r+=n.offsetTop,n=n.offsetParent}while(n&&n!==t);return r},d=f&&{capture:!1,passive:!0};function p(e,t){s(()=>{var r=r=>{var{blockScrollEvent:n,sections:s,scroller:c,offset:o}=e.current;if(!n&&s.length){var a=(c?c.scrollTop:window.pageYOffset||document.documentElement.scrollTop)+o;if(h(s[0],c)>a)r&&t("#",!1);else{var i=s.findIndex(e=>h(e,c)>a),l=-1===i?s[s.length-1]:s[Math.max(i-1,0)];l&&t("#".concat(l.id),!1)}}},n=function(e,t){var r=null;function n(){r||(r=setTimeout(()=>{r=null,e()},t))}return n.cancel=()=>{r&&(clearTimeout(r),r=null)},n}(r,100);return addEventListener("scroll",n,d),r(),()=>{removeEventListener("scroll",n,d),n.cancel()}},[])}function m(t){var{children:r,getScroller:o,offset:i=0}=t,l=c({offset:i,sections:[],blockScrollEvent:!1,scroller:null});o&&(l.current.scroller=o());var[u,v]=function(e){var[t,r]=n("");return s(()=>{var t=t=>{r(location.hash),t&&"hashchange"===t.type&&(e.current.blockScrollEvent=!0,setTimeout(()=>{e.current.blockScrollEvent=!1},100))};return addEventListener("hashchange",t,!1),addEventListener("popstate",t,!1),t(),()=>{removeEventListener("hashchange",t,!1),removeEventListener("popstate",t,!1)}},[]),[t,function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];r(e),"undefined"!=typeof history&&"undefined"!=typeof location&&(t||!("pushState"in history)?location.hash=e:history.pushState(null,e.substr(1),e))}]}(l);p(l,v);return e.createElement(a.Provider,{value:{offset:i,hash:u,sections:l.current.sections,setHash:v,registerSection:e=>{var{sections:t,scroller:r}=l.current;if(!t.includes(e)){var n=h(e,r),s=t.findIndex(e=>h(e,r)>n);-1===s?t.push(e):t.splice(s,0,e)}},unregisterSection:e=>{var t=l.current.sections.indexOf(e);-1!==t&&l.current.sections.splice(t,1)}}},r)}var g=["children"];function b(t){var{children:n}=t,o=l(t,g),{registerSection:u,unregisterSection:v}=r(a),f=c(null);return s(()=>(f.current&&(u(f.current),o.id===location.hash.substr(1)&&f.current.scrollIntoView()),()=>{f.current&&v(f.current)}),[]),e.createElement(e.Fragment,null,e.createElement("b",i({},o,{ref:f})),n)}export{a as AnchorContext,v as AnchorLink,m as AnchorProvider,b as AnchorSection};