UNPKG

raviger

Version:

React routing with hooks

3 lines (2 loc) 9.51 kB
"use strict";var t=require("react");const e=t.createContext(""),n=t.createContext(null);function RouterProvider({basePath:r="",path:a,children:o}){return t.createElement(e.Provider,{value:r},t.createElement(n.Provider,{value:null!=a?a:null},o))}let r=!0;try{r=void 0===window}catch{}const a=new Set;let o=!1,s=!1,u=[0,0];function shouldCancelNavigation(){return u=[window.scrollX,window.scrollY],o?s:Array.from(a).some((t=>{const e=t();return!!e&&(s=!window.confirm(e),o=!0,setTimeout((()=>{o=!1,s=!1}),0),s)}))}function usePath(e){const r=t.useContext(n),a=useBasePath();e=e||a;const[,o]=t.useState(getFormattedPath(e));return useLocationChange(t.useCallback((({path:t})=>o(t)),[]),{basePath:e,inheritBasePath:!e,onInitial:!0}),r||getFormattedPath(e)}function useBasePath(){return t.useContext(e)}function useFullPath(){const[e,n]=t.useState(getCurrentPath());return useLocationChange(t.useCallback((({path:t})=>n(t)),[]),{inheritBasePath:!1}),e||"/"}function getCurrentPath(){return r?"/":window.location.pathname||"/"}function getCurrentHash(){if(r){const t="/",e=t.indexOf("#");return t.substring(e)}return window.location.hash}function useLocationChange(e,{inheritBasePath:n=!0,basePath:a="",isActive:o,onInitial:s=!1}={}){if(r)return;const u=useBasePath();n&&u&&(a=u);const i=t.useRef(e);t.useLayoutEffect((()=>{i.current=e}));const c=t.useCallback((()=>{(void 0===o||isPredicateActive(o))&&(shouldCancelNavigation()||i.current(getFormattedLocation(a)))}),[o,a]);t.useLayoutEffect((()=>(window.addEventListener("popstate",c),()=>window.removeEventListener("popstate",c))),[c]),function useMountedLayout(e,n,{onInitial:r=!1}={}){const a=t.useRef(r);t.useLayoutEffect((()=>{a.current?e():a.current=!0}),n)}((()=>{(void 0===o||isPredicateActive(o))&&i.current(getFormattedLocation(a))}),[a,o],{onInitial:s})}function getRavigerHistory(){return r?{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 i=[null,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(e){return t.useMemo((()=>e.map(createRouteMatcher)),[(n=e,[...n].sort().join(":"))]);var n}function getMatchParams(t,e){let n=null;const r=e.find((({regex:e})=>(n=t.match(e),!!n)));if(!r||null===n)return i;const a=r.props.reduce(((t,e,r)=>(t[e]=n[r+1],t)),{});return[r,a]}const c=/:[a-zA-Z_]+/g;function createRouteMatcher(t){var e,n;return{path:t,regex:new RegExp(`${"*"===t.substr(0,1)?"":"^"}${(n=t,n.replace(/[-\\^$+?.()|[\]{}]/g,"\\$&")).replace(c,"([^/]+)").replace(/\*/g,"")}${"*"===t.substr(-1)?"":"$"}`,"i"),props:(null!==(e=t.match(c))&&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 l="";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()),l=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 useQueryParams(e=parseQuery,n=serializeQuery){const[r,a]=t.useState(getQueryString()),o=t.useCallback(((t,{overwrite:a=!0,replace:o=!1}={})=>{let s=getCurrentPath();t=a?t:{...e(r),...t};const u=n(t).toString();u&&(s+="?"+u),a||(s+=getCurrentHash()),navigate(s,{replace:o})}),[r,e,n]);return useLocationChange(t.useCallback((()=>a(getQueryString())),[])),[e(r),o]}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(r){const t="/",e=t.indexOf("?");return-1===e?"":t.substring(e+1)}return window.location.search}function useRedirect(e,n,{query:r,replace:a=!0,merge:o=!0}={}){const s=usePath(),[u]=useQueryParams(),i=getCurrentHash();let c=n;const l=new URLSearchParams({...o?u:{},...r}).toString();l&&(c+="?"+l),o&&i&&i.length&&(c+=i),t.useLayoutEffect((()=>{s===e&&navigate(c,{replace:a})}),[e,c,a,s])}const h=t.forwardRef((function Link({href:e,basePath:n,...r},a){e=getLinkHref(e,n=useLinkBasePath(n));const{onClick:o,target:s}=r,u=t.useCallback((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 f=t.forwardRef((function ActiveLink({basePath:e,className:n,exactActiveClass:r,activeClass:a,...o},s){e=useLinkBasePath(e);const u=useFullPath();let{href:i}=o;return i=function absolutePathName(t){return t.startsWith("/")?t:new URL(t,document.baseURI).pathname}(getLinkHref(i,e)),r&&u===i&&(n=`${null!=n?n:""} ${r}`.trim()),a&&u.startsWith(i)&&(n=`${null!=n?n:""} ${a}`.trim()),t.createElement(h,{...o,basePath:e,className:n,ref:s})}));function useLinkBasePath(t){const e=useBasePath();return"/"===t?"":t||e}function getLinkHref(t,e=""){return t.startsWith("/")?e+t:t}exports.ActiveLink=f,exports.Link=h,exports.Redirect=function Redirect({to:t,query:e,replace:n=!0,merge:r=!0}){return useRedirect(usePath(),t,{query:e,replace:n,merge:r}),null},exports.RouterProvider=RouterProvider,exports.navigate=navigate,exports.useBasePath=useBasePath,exports.useFullPath=useFullPath,exports.useHash=function useHash({stripHash:e=!0}={}){const[n,r]=t.useState(window.location.hash),a=t.useCallback((()=>{const t=window.location.hash;t!==n&&r(t)}),[r,n]);return t.useLayoutEffect((()=>(window.addEventListener("hashchange",a,!1),()=>window.removeEventListener("hashchange",a))),[a]),useLocationChange(a),e?n.substring(1):n},exports.useHistory=function useHistory(){const[e,n]=t.useState(getRavigerHistory());return useLocationChange(t.useCallback((()=>n(getRavigerHistory())),[n])),e},exports.useLocationChange=useLocationChange,exports.useMatch=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},exports.useNavigate=function useNavigate(e=""){const n=useBasePath();return t.useCallback(((t,r)=>{const a=e||n;navigate(t.startsWith("/")?a+t:t,r)}),[n,e])},exports.useNavigationPrompt=function useNavigationPrompt(e=!0,n="Are you sure you want to leave this page?"){r||(t.useLayoutEffect((()=>{const onPopStateNavigation=()=>{shouldCancelNavigation()&&function undoNavigation(t){window.history.pushState(null,null,t),setTimeout((()=>{window.scrollTo(...u)}),0)}(l)};return window.addEventListener("popstate",onPopStateNavigation),()=>window.removeEventListener("popstate",onPopStateNavigation)}),[]),t.useLayoutEffect((()=>{const handler=t=>{if(e)return t?function cancelNavigation(t,e){return t.preventDefault(),t.returnValue=e,e}(t,n):n};return function addInterceptor(t){window.addEventListener("beforeunload",t),a.add(t)}(handler),()=>function removeInterceptor(t){window.removeEventListener("beforeunload",t),a.delete(t)}(handler)}),[e,n]))},exports.usePath=usePath,exports.usePathParams=function usePathParams(t,e={}){const n=!Array.isArray(t),[r,a]=usePathOptions(t,e);if(null===r)return n?null:i;const[o,s]=getMatchParams(r,a);return o?n?s:[o.path,s]:n?null:i},exports.useQueryParams=useQueryParams,exports.useRedirect=useRedirect,exports.useRoutes=function useRoutes(e,{basePath:n="",routeProps:r={},overridePathParams:a=!0,matchTrailingSlash:o=!0}={}){const s=usePath(n)&&getFormattedPath(n);!function useRedirectDetection(e,n){const[,r]=t.useState({}),a=t.useCallback((()=>r({})),[]);t.useLayoutEffect((()=>{n!==getFormattedPath(e)&&a()}),[a,e,n])}(n,usePath(n));const u=function useMatchRoute(t,e,{routeProps:n,overridePathParams:r,matchTrailingSlash:a}){e=trailingMatch(e,a);const o=Array.isArray(t)?t:Object.entries(t).reduce(((t,[e,n])=>(t.push({path:e,fn:n}),t)),[]),s=useMatchers(o.map((t=>t.path)));if(null===e)return null;const[u,i]=getMatchParams(e,s);if(!u)return null;const c=o.find((t=>t.path==u.path));return c?c.fn(r?{...i,...n}:{...n,...i}):null}(e,s,{routeProps:r,overridePathParams:a,matchTrailingSlash:o});return u&&null!==s?t.createElement(RouterProvider,{basePath:n,path:s},u):null}; //# sourceMappingURL=main.js.map