UNPKG

raviger

Version:

React routing with hooks

3 lines (2 loc) 8.85 kB
import t,{createContext as e,useRef as n,useLayoutEffect as r,useContext as a,useState as o,useCallback as i,useMemo as s,forwardRef as u}from"react";const c=e(""),l=e(null);function RouterProvider({basePath:e="",path:n,children:r}){return t.createElement(c.Provider,{value:e},t.createElement(l.Provider,{value:null!=n?n:null},r))}let h=!0;try{h=void 0===window}catch(t){}const g=new Set;let d=!1,f=!1,P=[0,0];function shouldCancelNavigation(){return P=[window.scrollX,window.scrollY],d?f:Array.from(g).some((t=>{const e=t();return!!e&&(f=!window.confirm(e),d=!0,setTimeout((()=>{d=!1,f=!1}),0),f)}))}function usePath(t){const e=a(l),n=useBasePath();t=t||n;const[,r]=o(getFormattedPath(t));return useLocationChange(i((({path:t})=>r(t)),[]),{basePath:t,inheritBasePath:!t,onInitial:!0}),e||getFormattedPath(t)}function useBasePath(){return a(c)}function useFullPath(){const[t,e]=o(getCurrentPath());return useLocationChange(i((({path:t})=>e(t)),[]),{inheritBasePath:!1}),t||"/"}function useHash({stripHash:t=!0}={}){const[e,n]=o(window.location.hash),a=i((()=>{const t=window.location.hash;t!==e&&n(t)}),[n,e]);return r((()=>(window.addEventListener("hashchange",a,!1),()=>window.removeEventListener("hashchange",a))),[a]),useLocationChange(a),t?e.substring(1):e}function getCurrentPath(){return h?"/":window.location.pathname||"/"}function getCurrentHash(){if(h){const t="/",e=t.indexOf("#");return t.substring(e)}return window.location.hash}function useLocationChange(t,{inheritBasePath:e=!0,basePath:a="",isActive:o,onInitial:s=!1}={}){if(h)return;const u=useBasePath();e&&u&&(a=u);const c=n(t);r((()=>{c.current=t}));const l=i((()=>{(void 0===o||isPredicateActive(o))&&(shouldCancelNavigation()||c.current(getFormattedLocation(a)))}),[o,a]);r((()=>(window.addEventListener("popstate",l),()=>window.removeEventListener("popstate",l))),[l]),function useMountedLayout(t,e,{onInitial:a=!1}={}){const o=n(a);r((()=>{o.current?t():o.current=!0}),e)}((()=>{(void 0===o||isPredicateActive(o))&&c.current(getFormattedLocation(a))}),[a,o],{onInitial:s})}function useHistory(){const[t,e]=o(getRavigerHistory());return useLocationChange(i((()=>e(getRavigerHistory())),[e])),t}function getRavigerHistory(){return h?{scrollRestoration:"manual",state:null}:{scrollRestoration:window.history.scrollRestoration,state:window.history.state}}function getFormattedPath(t){const e=getCurrentPath(),n=t&&!function isPathInBase(t,e){return!!(t&&e&&e.toLowerCase().startsWith(t.toLowerCase()))}(t,e);return null===e||n?null:decodeURIComponent(t?e.replace(function basePathMatcher(t){return new RegExp("^"+t,"i")}(t),"")||"/":e)}function getFormattedLocation(t){const e=getFormattedPath(t);return{basePath:t,path:e,pathname:e,fullPath:getCurrentPath(),search:window.location.search,hash:getCurrentHash(),host:window.location.host,hostname:window.location.hostname,href:window.location.href,origin:window.location.origin}}function isPredicateActive(t){return function isFunction(t){return!!t&&"function"==typeof t}(t)?t():t}const w=[null,null];function useRoutes(e,{basePath:n="",routeProps:a={},overridePathParams:s=!0,matchTrailingSlash:u=!0}={}){const c=usePath(n)&&getFormattedPath(n);!function useRedirectDetection(t,e){const[,n]=o({}),a=i((()=>n({})),[]);r((()=>{e!==getFormattedPath(t)&&a()}),[a,t,e])}(n,usePath(n));const l=function useMatchRoute(t,e,{routeProps:n,overridePathParams:r,matchTrailingSlash:a}){e=trailingMatch(e,a);const o=useMatchers(Object.keys(t));if(null===e)return null;const[i,s]=getMatchParams(e,o);return i?t[i.path](r?{...s,...n}:{...n,...s}):null}(e,c,{routeProps:a,overridePathParams:s,matchTrailingSlash:u});return l&&null!==c?t.createElement(RouterProvider,{basePath:n,path:c},l):null}function usePathParams(t,e={}){const n=!Array.isArray(t),[r,a]=usePathOptions(t,e);if(null===r)return n?null:w;const[o,i]=getMatchParams(r,a);return o?n?i:[o.path,i]:n?null:w}function useMatch(t,e={}){var n;const[r,a]=usePathOptions(t,e),o=a.find((({regex:t})=>null==r?void 0:r.match(t)));return null!==(n=null==o?void 0:o.path)&&void 0!==n?n:null}function usePathOptions(t,{basePath:e,matchTrailingSlash:n=!0}){const r=useMatchers(Array.isArray(t)?t:[t]);return[trailingMatch(usePath(e),n),r]}function useMatchers(t){return s((()=>t.map(createRouteMatcher)),[(e=t,[...e].sort().join(":"))]);var e}function getMatchParams(t,e){let n=null;const r=e.find((({regex:e})=>(n=t.match(e),!!n)));if(!r||null===n)return w;const a=r.props.reduce(((t,e,r)=>(t[e]=n[r+1],t)),{});return[r,a]}function createRouteMatcher(t){var e,n;return{path:t,regex:new RegExp(`${"*"===t.substr(0,1)?"":"^"}${(n=t,n.replace(/[-\\^$+?.()|[\]{}]/g,"\\$&")).replace(/:[a-zA-Z]+/g,"([^/]+)").replace(/\*/g,"")}${"*"===t.substr(-1)?"":"$"}`,"i"),props:(null!==(e=t.match(/:[a-zA-Z]+/g))&&void 0!==e?e:[]).map((t=>t.substr(1)))}}function trailingMatch(t,e){return null===t||e&&t&&"/"===t[t.length-1]&&t.length>1&&(t=t.substring(0,t.length-1)),t}let v="";function navigate(t,e){if("string"!=typeof t)throw new Error('"url" must be a string, was provided a(n) '+typeof t);if(Array.isArray(null==e?void 0:e.query))throw new Error('"query" a serializable object or URLSearchParams');if(shouldCancelNavigation())return;if((null==e?void 0:e.query)&&(t+="?"+new URLSearchParams(e.query).toString()),v=t,function isAbsolute(t){return/^(?:[a-z]+:)?\/\//i.test(t)}(t)&&!function isCurrentOrigin(t){return window.location.origin===new URL(t).origin}(t))return void window.location.assign(t);(null==e?void 0:e.replace)?window.history.replaceState(null==e?void 0:e.state,"",t):window.history.pushState(null==e?void 0:e.state,"",t);const n=new PopStateEvent("popstate");n.__tag="raviger:navigation",dispatchEvent(n)}function useNavigationPrompt(t=!0,e="Are you sure you want to leave this page?"){h||(r((()=>{const onPopStateNavigation=()=>{shouldCancelNavigation()&&function undoNavigation(t){window.history.pushState(null,null,t),setTimeout((()=>{window.scrollTo(...P)}),0)}(v)};return window.addEventListener("popstate",onPopStateNavigation),()=>window.removeEventListener("popstate",onPopStateNavigation)}),[]),r((()=>{const handler=n=>{if(t)return n?function cancelNavigation(t,e){return t.preventDefault(),t.returnValue=e,e}(n,e):e};return function addInterceptor(t){window.addEventListener("beforeunload",t),g.add(t)}(handler),()=>function removeInterceptor(t){window.removeEventListener("beforeunload",t),g.delete(t)}(handler)}),[t,e]))}function useNavigate(t=""){const e=useBasePath();return i(((n,r)=>{const a=t||e;navigate(n.startsWith("/")?a+n:n,r)}),[e,t])}function useQueryParams(t=parseQuery,e=serializeQuery){const[n,r]=o(getQueryString()),a=i(((r,{replace:a=!0,historyReplace:o=!1}={})=>{let i=getCurrentPath();r=a?r:{...t(n),...r};const s=e(r).toString();s&&(i+="?"+s),a||(i+=getCurrentHash()),navigate(i,{replace:o})}),[n,t,e]);return useLocationChange(i((()=>r(getQueryString())),[])),[t(n),a]}function parseQuery(t){const e=new URLSearchParams(t);return Object.fromEntries(e.entries())}function serializeQuery(t){return new URLSearchParams(Object.entries(t).filter((([,t])=>null!==t))).toString()}function getQueryString(){if(h){const t="/",e=t.indexOf("?");return-1===e?"":t.substring(e+1)}return window.location.search}function Redirect({to:t,query:e,replace:n=!0,merge:r=!0}){return useRedirect(usePath(),t,{query:e,replace:n,merge:r}),null}function useRedirect(t,e,{query:n,replace:a=!0,merge:o=!0}={}){const i=usePath(),[s]=useQueryParams(),u=getCurrentHash();let c=e;const l=new URLSearchParams({...o?s:{},...n}).toString();l&&(c+="?"+l),o&&u&&u.length&&(c+=u),r((()=>{i===t&&navigate(c,{replace:a})}),[t,c,a,i])}const m=u((function Link({href:e,basePath:n,...r},a){e=getLinkHref(e,n=useLinkBasePath(n));const{onClick:o,target:s}=r,u=i((t=>{try{o&&o(t)}catch(e){throw t.preventDefault(),e}(function shouldTrap(t,e){return!t.defaultPrevented&&0===t.button&&!(e||"_self"===e)&&!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)})(t,s)&&(t.preventDefault(),navigate(t.currentTarget.href))}),[o,s]);return t.createElement("a",{...r,href:e,onClick:u,ref:a})}));const p=u((function ActiveLink({basePath:e,className:n,exactActiveClass:r,activeClass:a,...o},i){e=useLinkBasePath(e);const s=useFullPath();let{href:u}=o;return u=function absolutePathName(t){return t.startsWith("/")?t:new URL(t,document.baseURI).pathname}(getLinkHref(u,e)),r&&s===u&&(n=`${null!=n?n:""} ${r}`.trim()),a&&s.startsWith(u)&&(n=`${null!=n?n:""} ${a}`.trim()),t.createElement(m,{...o,basePath:e,className:n,ref:i})}));function useLinkBasePath(t){const e=useBasePath();return"/"===t?"":t||e}function getLinkHref(t,e=""){return t.startsWith("/")?e+t:t}export{p as ActiveLink,m as Link,Redirect,RouterProvider,navigate,useBasePath,useFullPath,useHash,useHistory,useLocationChange,useMatch,useNavigate,useNavigationPrompt,usePath,usePathParams,useQueryParams,useRedirect,useRoutes}; //# sourceMappingURL=module.js.map