UNPKG

react-vt-router

Version:

A tiny React router with View Transitions using native Web APIs.

11 lines (10 loc) 19.7 kB
import t,{createContext as e,useMemo as r,useContext as n,useCallback as a,useEffect as o,useState as i,useRef as s,Children as c,isValidElement as l}from"react";var u,f={exports:{}},d={};var h,m,p={}; /** * @license React * react-jsx-runtime.development.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */function y(){return h||(h=1,"production"!==process.env.NODE_ENV&&function(){function e(t){if(null==t)return null;if("function"==typeof t)return t.$$typeof===S?null:t.displayName||t.name||null;if("string"==typeof t)return t;switch(t){case h:return"Fragment";case y:return"Profiler";case m:return"StrictMode";case g:return"Suspense";case x:return"SuspenseList";case k:return"Activity"}if("object"==typeof t)switch("number"==typeof t.tag&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),t.$$typeof){case d:return"Portal";case w:return(t.displayName||"Context")+".Provider";case v:return(t._context.displayName||"Context")+".Consumer";case b:var r=t.render;return(t=t.displayName)||(t=""!==(t=r.displayName||r.name||"")?"ForwardRef("+t+")":"ForwardRef"),t;case R:return null!==(r=t.displayName||null)?r:e(t.type)||"Memo";case _:r=t._payload,t=t._init;try{return e(t(r))}catch(t){}}return null}function r(t){return""+t}function n(t){try{r(t);var e=!1}catch(t){e=!0}if(e){var n=(e=console).error,a="function"==typeof Symbol&&Symbol.toStringTag&&t[Symbol.toStringTag]||t.constructor.name||"Object";return n.call(e,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",a),r(t)}}function a(t){if(t===h)return"<>";if("object"==typeof t&&null!==t&&t.$$typeof===_)return"<...>";try{var r=e(t);return r?"<"+r+">":"<...>"}catch(t){return"<...>"}}function o(){return Error("react-stack-top-frame")}function i(){var t=e(this.type);return E[t]||(E[t]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),void 0!==(t=this.props.ref)?t:null}function s(t,r,a,o,s,u,d,h){var m,p=r.children;if(void 0!==p)if(o)if(T(p)){for(o=0;o<p.length;o++)c(p[o]);Object.freeze&&Object.freeze(p)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else c(p);if(j.call(r,"key")){p=e(t);var y=Object.keys(r).filter(function(t){return"key"!==t});o=0<y.length?"{key: someKey, "+y.join(": ..., ")+": ...}":"{key: someKey}",U[p+o]||(y=0<y.length?"{"+y.join(": ..., ")+": ...}":"{}",console.error('A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',o,p,y,p),U[p+o]=!0)}if(p=null,void 0!==a&&(n(a),p=""+a),function(t){if(j.call(t,"key")){var e=Object.getOwnPropertyDescriptor(t,"key").get;if(e&&e.isReactWarning)return!1}return void 0!==t.key}(r)&&(n(r.key),p=""+r.key),"key"in r)for(var v in a={},r)"key"!==v&&(a[v]=r[v]);else a=r;return p&&function(t,e){function r(){l||(l=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",e))}r.isReactWarning=!0,Object.defineProperty(t,"key",{get:r,configurable:!0})}(a,"function"==typeof t?t.displayName||t.name||"Unknown":t),function(t,e,r,n,a,o,s,c){return r=o.ref,t={$$typeof:f,type:t,key:e,props:o,_owner:a},null!==(void 0!==r?r:null)?Object.defineProperty(t,"ref",{enumerable:!1,get:i}):Object.defineProperty(t,"ref",{enumerable:!1,value:null}),t._store={},Object.defineProperty(t._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(t,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(t,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:s}),Object.defineProperty(t,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:c}),Object.freeze&&(Object.freeze(t.props),Object.freeze(t)),t}(t,p,u,0,null===(m=P.A)?null:m.getOwner(),a,d,h)}function c(t){"object"==typeof t&&null!==t&&t.$$typeof===f&&t._store&&(t._store.validated=1)}var l,u=t,f=Symbol.for("react.transitional.element"),d=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),m=Symbol.for("react.strict_mode"),y=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),w=Symbol.for("react.context"),b=Symbol.for("react.forward_ref"),g=Symbol.for("react.suspense"),x=Symbol.for("react.suspense_list"),R=Symbol.for("react.memo"),_=Symbol.for("react.lazy"),k=Symbol.for("react.activity"),S=Symbol.for("react.client.reference"),P=u.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,j=Object.prototype.hasOwnProperty,T=Array.isArray,L=console.createTask?console.createTask:function(){return null},E={},O=(u={react_stack_bottom_frame:function(t){return t()}}).react_stack_bottom_frame.bind(u,o)(),N=L(a(o)),U={};p.Fragment=h,p.jsx=function(t,e,r,n,o){var i=1e4>P.recentlyCreatedOwnerStacks++;return s(t,e,r,!1,0,o,i?Error("react-stack-top-frame"):O,i?L(a(t)):N)},p.jsxs=function(t,e,r,n,o){var i=1e4>P.recentlyCreatedOwnerStacks++;return s(t,e,r,!0,0,o,i?Error("react-stack-top-frame"):O,i?L(a(t)):N)}}()),p}var v=(m||(m=1,"production"===process.env.NODE_ENV?f.exports=function(){if(u)return d;u=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function r(e,r,n){var a=null;if(void 0!==n&&(a=""+n),void 0!==r.key&&(a=""+r.key),"key"in r)for(var o in n={},r)"key"!==o&&(n[o]=r[o]);else n=r;return r=n.ref,{$$typeof:t,type:e,key:a,ref:void 0!==r?r:null,props:n}}return d.Fragment=e,d.jsx=r,d.jsxs=r,d}():f.exports=y()),f.exports);let w=0;const b=t=>t.replace(/\/+$/,"")||"/",g=(t,e)=>b(`${"/"===t?"":t}/${e}`),x=(t,e)=>new URL(t,window.location.href),R=()=>{try{if(!0===(window.__REACT_VT_ROUTER_FORCE_STRING__??window.__TINY_ROUTER_FORCE_STRING__))return!1}catch{}return"function"==typeof window.URLPattern};function _(t,e="data-vt"){if(void 0!==t)return"boolean"==typeof t?!!t&&{}:"string"==typeof t?{name:t,attribute:e}:{attribute:e,...t}}const k=(t,e)=>{let r=t.startsWith("/")?t:`/${t}`;if("/*"===r)r="/:__splat(.*)";else if(r.endsWith("/*")){const t=r.slice(0,-2).replace(/\/+$/,"");r=(""===t?"/":t)+"/:__splat(.*)"}return r},S=(t,e)=>e?t:t.toLowerCase();function P(...t){try{(window.__REACT_VT_ROUTER_DEBUG__??window.__TINY_ROUTER_DEBUG__)&&console.log(...t)}catch{}}let j=!1;async function T(t,e){!function(){if(j)return;const t=document.createElement("style");t.setAttribute("data-react-vt-router","vt-presets"),t.textContent='\n/* react-vt-router: built-in view-transition presets */\nhtml[data-vt], html[data-vt]::view-transition-new(root), html[data-vt]::view-transition-old(root) { view-transition-name: root; }\n\n@keyframes art-fade-in { from { opacity: 0.01 } to { opacity: 1 } }\n@keyframes art-fade-out { from { opacity: 1 } to { opacity: 0.01 } }\nhtml[data-vt="fade"]::view-transition-new(root) { animation: art-fade-in 250ms ease-out both; }\nhtml[data-vt="fade"]::view-transition-old(root) { animation: art-fade-out 250ms ease-in both; }\n\n@keyframes art-slide-in { from { transform: translateX(100%); opacity: .01 } to { transform: translateX(0); opacity: 1 } }\n@keyframes art-slide-out { from { transform: translateX(0); opacity: 1 } to { transform: translateX(-20%); opacity: .01 } }\nhtml[data-vt="slide"] { overflow-x: clip; }\nhtml[data-vt="slide"]::view-transition-new(root) { animation: art-slide-in 500ms cubic-bezier(.2,.8,.2,1) both; }\nhtml[data-vt="slide"]::view-transition-old(root) { animation: art-slide-out 500ms cubic-bezier(.2,.8,.2,1) both; }\n\n@keyframes art-slide-left-in { from { transform: translateX(-100%); opacity: .01 } to { transform: translateX(0); opacity: 1 } }\n@keyframes art-slide-left-out { from { transform: translateX(0); opacity: 1 } to { transform: translateX(20%); opacity: .01 } }\nhtml[data-vt="slide-left"] { overflow-x: clip; }\nhtml[data-vt="slide-left"]::view-transition-new(root) { animation: art-slide-left-in 500ms cubic-bezier(.2,.8,.2,1) both; }\nhtml[data-vt="slide-left"]::view-transition-old(root) { animation: art-slide-left-out 500ms cubic-bezier(.2,.8,.2,1) both; }\n\n@keyframes art-slide-right-in { from { transform: translateX(100%); opacity: .01 } to { transform: translateX(0); opacity: 1 } }\n@keyframes art-slide-right-out { from { transform: translateX(0); opacity: 1 } to { transform: translateX(-100%); opacity: .01 } }\nhtml[data-vt="slide-right"] { overflow-x: clip; }\nhtml[data-vt="slide-right"]::view-transition-new(root) { animation: art-slide-right-in 500ms cubic-bezier(.2,.8,.2,1) both; }\nhtml[data-vt="slide-right"]::view-transition-old(root) { animation: art-slide-right-out 500ms cubic-bezier(.2,.8,.2,1) both; }\n\n@keyframes art-zoom-in { from { transform: scale(.96); opacity: .01 } to { transform: scale(1); opacity: 1 } }\n@keyframes art-zoom-out { from { transform: scale(1); opacity: 1 } to { transform: scale(1.04); opacity: .01 } }\nhtml[data-vt="zoom"]::view-transition-new(root) { animation: art-zoom-in 300ms ease-out both; }\nhtml[data-vt="zoom"]::view-transition-old(root) { animation: art-zoom-out 300ms ease-in both; }\n\n@media (prefers-reduced-motion: reduce) { html[data-vt]::view-transition-new(root), html[data-vt]::view-transition-old(root) { animation: none !important; }}',document.head.appendChild(t),j=!0}();const r=e?.attribute||"data-vt",n=document.documentElement,a=()=>{e?.name&&n.setAttribute(r,String(e.name)),e?.className&&n.classList.add(e.className)},o=()=>{e?.name&&n.removeAttribute(r),e?.className&&n.classList.remove(e.className)};if(e?.onStart?.(),"function"==typeof document.startViewTransition)try{a();const r=document.startViewTransition(t);Promise.resolve(r?.ready).then(()=>e?.onReady?.()).catch(()=>{});try{await(r?.finished)}finally{o(),e?.onFinished?.()}return}catch{}a();try{t()}finally{o(),e?.onFinished?.()}}const L=e(null),E=e(null),O=e(void 0);let N=0;const U=()=>"r"+ ++N;function C(t,e,r="/"){const n=[];for(const a of t){const t=U(),o=a.index?"":a.path??"",i=a.index?b(r):o.startsWith("/")?b(o):b(g(r,o||""));a.caseSensitive;let s=null;if(R()){const t=k(i);try{s=new(0,window.URLPattern)({pathname:t})}catch{s=null}}const c={...a,id:t,fullPath:i,pattern:s,parent:e,children:void 0};a.children?.length&&(c.children=C(a.children,c,i)),n.push(c)}return n}function $(t,e){const r=e.pathname||"/";try{P("[react-vt-router] matchRoutes start",{url:e.toString(),pathnameRaw:r,supportsURLPattern:R()})}catch{}const n=(t,a)=>{for(const o of t){const t=o.caseSensitive,i=S(r,t);let s=!1,c={};try{P("[react-vt-router] try node",{fullPath:o.fullPath,index:!!o.index,hasChildren:!(!o.children||!o.children.length)})}catch{}if(o.index){const e=S(o.fullPath,t);s=i===e;try{P("[react-vt-router] index check",{expected:e,pathname:i,isMatch:s})}catch{}}else if(o.pattern)try{if(o.children?.length){let r=o.__deepPattern;if(!r&&R())try{const t=window.URLPattern,e="/"===o.fullPath?"/*":`${o.fullPath}/*`;r=new t({pathname:k(e,o.caseSensitive)}),o.__deepPattern=r}catch{}const n=new URL(e.toString());t||(n.pathname=n.pathname.toLowerCase());try{const t=o.pattern.exec(n);t&&(s=!0,c={...t.pathname.groups})}catch{}if(!s&&r)try{const t=r.exec(n);if(t){s=!0;const e=t.pathname.groups||{},{__splat:r,...n}=e;c=n}}catch{}try{P("[react-vt-router] pattern parent",{fullPath:o.fullPath,exactTried:!0,deepTried:!!r,isMatch:s,params:c})}catch{}if(!s){const e=S(o.fullPath,t);s=i===e||i.startsWith("/"===e?"/":e+"/");try{P("[react-vt-router] string parent fallback",{full:e,pathname:i,isMatch:s})}catch{}}}else{const r=new URL(e.toString());t||(r.pathname=r.pathname.toLowerCase());try{const t=o.pattern.exec(r);t&&(s=!0,c={...t.pathname.groups})}catch{}if(!s){const e=S(o.fullPath,t);s=i===e;try{P("[react-vt-router] string leaf fallback",{full:e,pathname:i,isMatch:s})}catch{}}}}catch{}else{const e=S(o.fullPath,t);if(o.children?.length){s=i===e||i.startsWith("/"===e?"/":e+"/");try{P("[react-vt-router] no-pattern parent fallback",{full:e,pathname:i,isMatch:s})}catch{}}else{s=i===e;try{P("[react-vt-router] no-pattern leaf fallback",{full:e,pathname:i,isMatch:s})}catch{}}}if(!s)continue;const l=[...a,{route:o,params:c}];try{P("[react-vt-router] matched",{fullPath:o.fullPath,params:c,depth:l.length})}catch{}if(o.children?.length){const t=n(o.children,l);if(t)return t;continue}return l}return null};return n(t,[])}function A(t){return{pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,state:t??window.history.state?.usr??null,key:"k"+ ++w}}function z({children:t,enableNavigationAPI:e=!1,defaultViewTransition:n}){const[c,l]=i(()=>A()),u=s(c.state);o(()=>{u.current=c.state},[c.state]),o(()=>{const t=()=>{const t=A();try{P("[react-vt-router] popstate",t)}catch{}const e=_(n);!1!==e?T(()=>l(t),e||void 0):l(t)},e=()=>{const t=A();try{P("[react-vt-router] hashchange",t)}catch{}const e=_(n);!1!==e?T(()=>l(t),e||void 0):l(t)};return window.addEventListener("popstate",t),window.addEventListener("hashchange",e),()=>{window.removeEventListener("popstate",t),window.removeEventListener("hashchange",e)}},[n]),o(()=>{if(!e)return;const t=window.navigation;if(!t?.addEventListener)return;const r=t=>{if(!t.canIntercept)return;new URL(t.destination.url).origin===window.location.origin&&t.intercept({handler:()=>{T(()=>{l(A(t.info?.state)),!1!==t.info?.scroll&&window.scrollTo({top:0,behavior:"auto"})},_(n)||void 0)}})};return t.addEventListener("navigate",r),()=>t.removeEventListener("navigate",r)},[e]);const f=a((t,e={})=>{const{replace:r,state:a,viewTransition:o=n??!0,scroll:i="auto"}=e;if("number"==typeof t)return void window.history.go(t);const s=x(t);if(s.origin!==window.location.origin)return void(window.location.href=s.toString());const c=new URL(window.location.href);if(c.pathname===s.pathname&&c.search===s.search&&c.hash===s.hash){try{P("[react-vt-router] navigate no-op (same URL)",s.toString())}catch{}return}const u=()=>{try{P("[react-vt-router] navigate",{to:s.toString(),replace:r,state:a,scroll:i,viewTransition:o})}catch{}r?window.history.replaceState({usr:a??null},"",s):window.history.pushState({usr:a??null},"",s);const t=A(a);try{P("[react-vt-router] location set",t)}catch{}l(t),window.scrollTo({top:0,behavior:i})},f=_(o);!1!==f?T(u,f||void 0):u()},[n]),d=r(()=>{const t=(t,e)=>f(t,e);return t.back=()=>t(-1),t.forward=()=>t(1),t.go=e=>t(e),t},[f]),h=r(()=>({location:c,navigate:d}),[c,d]);return v.jsx(L.Provider,{value:h,children:t})}function X(){const t=n(L);if(!t)throw new Error("useRouterState must be used within <BrowserRouter>");return{location:t.location}}function F(){return X().location}function W(){const t=n(L);if(!t)throw new Error("useNavigate must be used within <BrowserRouter>");return t.navigate}function V(){const t=n(E);if(!t)return{};return r(()=>t.matches.reduce((t,e)=>Object.assign(t,e.params),{}),[t.matches])}function I(){const{location:t}=X(),e=W(),n=a((t,r)=>{let n;n=t instanceof URLSearchParams?t:"string"==typeof t||Array.isArray(t)?new URLSearchParams(t):new URLSearchParams(Object.entries(t));const a=new URL(window.location.href);a.search=n.toString(),e(a.toString(),{replace:r?.replace})},[e]);return[r(()=>new URLSearchParams(t.search),[t.search]),n]}function D(t){return null}function M(t){const e=[];c.forEach(t,t=>{if(!l(t))return;const r=t.type,n=r===D||!0===r?.$$reactVtRouterRoute||"ReactVtRouterRoute"===r?.displayName,a=t.props;if(!n&&!(a&&"object"==typeof a&&("path"in a||"index"in a)))return;const o=t.props,i={path:o.path,index:o.index,caseSensitive:o.caseSensitive,element:o.redirectTo?v.jsx(J,{to:o.redirectTo,replace:!0}):o.element};o.children&&(i.children=M(o.children)),e.push(i)});try{P("[react-vt-router] createRoutesFromChildren:",e)}catch{}return e}function K({children:t}){const{location:e}=X(),n=r(()=>M(t),[t]),a=r(()=>C(n),[n]),o=r(()=>new URL(window.location.href),[e.key]),i=r(()=>$(a,o),[a,o]);try{P("[react-vt-router] Routes snapshot",{location:e,url:o.toString(),routes:n,compiled:a.map(t=>({id:t.id,fullPath:t.fullPath,index:t.index,children:!(!t.children||!t.children.length)})),matches:i})}catch{}return i?v.jsx(E.Provider,{value:{matches:i,index:0},children:v.jsx(B,{})}):null}function B(){const t=n(E);if(!t)return null;const{matches:e,index:r}=t,a=e[r];if(!a)return null;const o=v.jsx(E.Provider,{value:{matches:e,index:r+1},children:v.jsx(G,{})}),i=a.route.element;return i?v.jsx(E.Provider,{value:{matches:e,index:r+1},children:v.jsx(v.Fragment,{children:i})}):o}function G(t){const e=n(E);if(!e)return null;const{matches:r,index:a}=e,o=r[a];if(!o)return null;const i=o.route.element;return i?v.jsx(O.Provider,{value:t?.context,children:v.jsx(E.Provider,{value:{matches:r,index:a+1},children:v.jsx(v.Fragment,{children:i})})}):v.jsx(O.Provider,{value:t?.context,children:v.jsx(E.Provider,{value:{matches:r,index:a+1},children:v.jsx(G,{})})})}function Y({to:t,replace:e,onClick:n,target:a,rel:o,viewTransition:i,scroll:s,...c}){const l=W(),u=r(()=>x(t).toString(),[t]);return v.jsx("a",{...c,href:u,onClick:t=>{if(n&&n(t),!t.defaultPrevented&&!(a&&"_self"!==a||0!==t.button||t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)){try{if(new URL(u).origin!==window.location.origin)return}catch{return}t.preventDefault();try{P("[react-vt-router] Link intercept",{href:u,replace:e,viewTransition:i,scroll:s})}catch{}l(u,{replace:e,viewTransition:i,scroll:s})}},target:a,rel:o})}function J({to:t,replace:e,state:r,viewTransition:n=!0}){const a=W();return o(()=>{a(t,{replace:e,state:r,viewTransition:n})},[a,t,e,r,n]),null}function H(t){const{location:e}=X(),n=r(()=>C(t),[t]),a=r(()=>new URL(window.location.href),[e.key]),o=r(()=>$(n,a),[n,a]);return o?v.jsx(E.Provider,{value:{matches:o,index:0},children:v.jsx(B,{})}):null}function q(t){return M(t)}function Q(t){const{location:e}=X(),n=r(()=>new URL(window.location.href),[e.key]);if(R())try{const e=window.URLPattern,r=k(t),a=new e({pathname:r}).exec(n);if(a){return{params:a.pathname.groups||{},pathname:n.pathname,pattern:t}}}catch{}const a=t.endsWith("/*")?t.slice(0,-2):t,o=n.pathname;return o===a||t.endsWith("/*")&&(o===a||o.startsWith(a+"/"))?{params:{},pathname:o,pattern:t}:null}function Z({className:t,style:e,end:r,...n}){const a=rt(n.to),o=F(),i=b(a),s=b(o.pathname),c=r?s===i:s===i||s.startsWith(i+"/"),l="function"==typeof t?t({isActive:c,isPending:!1}):t,u="function"==typeof e?e({isActive:c,isPending:!1}):e;return v.jsx(Y,{...n,className:l,style:u})}function tt(){return n(O)}function et({context:t}){const e=n(E);if(!e)return null;const{matches:r,index:a}=e,o=r[a];if(!o)return null;const i=o.route.element;return v.jsx(O.Provider,{value:t,children:v.jsx(E.Provider,{value:{matches:r,index:a+1},children:i??v.jsx(et,{})})})}function rt(t){return r(()=>x(t).pathname+x(t).search+x(t).hash,[t])}D.$$reactVtRouterRoute=!0,D.displayName="ReactVtRouterRoute";var nt={BrowserRouter:z,Routes:K,Route:D,Link:Y,NavLink:Z,Navigate:J,Outlet:G,OutletWithContext:et,useNavigate:W,useLocation:F,useParams:V,useSearchParams:I,useMatch:Q,useOutletContext:tt,useRoutes:H,createRoutesFromElements:q};export{z as BrowserRouter,Y as Link,Z as NavLink,J as Navigate,G as Outlet,et as OutletWithContext,D as Route,K as Routes,q as createRoutesFromElements,nt as default,F as useLocation,Q as useMatch,W as useNavigate,tt as useOutletContext,V as useParams,rt as useResolvedPath,X as useRouterState,H as useRoutes,I as useSearchParams};