@tanstack/router
Advanced tools
Comparing version 0.0.1-beta.83 to 0.0.1-beta.84
@@ -16,3 +16,3 @@ /** | ||
var invariant = require('tiny-invariant'); | ||
var tinyWarning = require('tiny-warning'); | ||
var warning = require('tiny-warning'); | ||
var history = require('./history.js'); | ||
@@ -26,2 +26,4 @@ var path = require('./path.js'); | ||
var utils = require('./utils.js'); | ||
var react = require('./react.js'); | ||
var reactStore = require('@tanstack/react-store'); | ||
@@ -31,3 +33,3 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var invariant__default = /*#__PURE__*/_interopDefaultLegacy(invariant); | ||
var tinyWarning__default = /*#__PURE__*/_interopDefaultLegacy(tinyWarning); | ||
var warning__default = /*#__PURE__*/_interopDefaultLegacy(warning); | ||
@@ -42,3 +44,3 @@ | ||
enumerable: true, | ||
get: function () { return tinyWarning__default["default"]; } | ||
get: function () { return warning__default["default"]; } | ||
}); | ||
@@ -78,2 +80,27 @@ exports.createBrowserHistory = history.createBrowserHistory; | ||
exports.replaceEqualDeep = utils.replaceEqualDeep; | ||
exports.Block = react.Block; | ||
exports.ErrorComponent = react.ErrorComponent; | ||
exports.Link = react.Link; | ||
exports.MatchRoute = react.MatchRoute; | ||
exports.Navigate = react.Navigate; | ||
exports.Outlet = react.Outlet; | ||
exports.RouterProvider = react.RouterProvider; | ||
exports.lazy = react.lazy; | ||
exports.matchesContext = react.matchesContext; | ||
exports.routerContext = react.routerContext; | ||
exports.useBlocker = react.useBlocker; | ||
exports.useLinkProps = react.useLinkProps; | ||
exports.useLoader = react.useLoader; | ||
exports.useMatch = react.useMatch; | ||
exports.useMatchRoute = react.useMatchRoute; | ||
exports.useMatches = react.useMatches; | ||
exports.useNavigate = react.useNavigate; | ||
exports.useParams = react.useParams; | ||
exports.useRouter = react.useRouter; | ||
exports.useRouterContext = react.useRouterContext; | ||
exports.useSearch = react.useSearch; | ||
Object.defineProperty(exports, 'useStore', { | ||
enumerable: true, | ||
get: function () { return reactStore.useStore; } | ||
}); | ||
//# sourceMappingURL=index.js.map |
@@ -17,2 +17,3 @@ /** | ||
var path = require('./path.js'); | ||
var react = require('./react.js'); | ||
@@ -72,30 +73,27 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
}; | ||
// generate = ( | ||
// options: Omit< | ||
// RouteOptions< | ||
// TParentRoute, | ||
// TCustomId, | ||
// TPath, | ||
// InferFullSearchSchema<TParentRoute>, | ||
// TSearchSchema, | ||
// TFullSearchSchema, | ||
// TParentRoute['__types']['allParams'], | ||
// TParams, | ||
// TAllParams, | ||
// TParentContext, | ||
// TAllParentContext, | ||
// TRouteContext, | ||
// TContext | ||
// >, | ||
// 'path' | ||
// >, | ||
// ) => { | ||
// invariant( | ||
// false, | ||
// `route.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `, | ||
// ) | ||
// } | ||
useMatch = opts => { | ||
return react.useMatch({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
useLoader = opts => { | ||
return react.useLoader({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
useContext = opts => { | ||
return react.useMatch({ | ||
...opts, | ||
from: this.id | ||
}).context; | ||
}; | ||
useSearch = opts => { | ||
return react.useSearch({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
} | ||
class RootRoute extends Route { | ||
@@ -102,0 +100,0 @@ constructor(options) { |
@@ -15,3 +15,3 @@ /** | ||
var store = require('@tanstack/store'); | ||
var reactStore = require('@tanstack/react-store'); | ||
var router = require('./router.js'); | ||
@@ -30,7 +30,8 @@ var utils = require('./utils.js'); | ||
params: opts.params, | ||
__store: new store.Store({ | ||
__store: new reactStore.Store({ | ||
updatedAt: 0, | ||
routeSearch: {}, | ||
search: {}, | ||
status: 'idle' | ||
status: 'idle', | ||
loader: undefined | ||
}, { | ||
@@ -45,5 +46,3 @@ onUpdate: next => { | ||
const component = this.route.options[type]; | ||
if (typeof this[type] !== 'function') { | ||
this[type] = component; | ||
} | ||
this[type] = component; | ||
}); | ||
@@ -58,3 +57,3 @@ if (this.state.status === 'idle' && !this.#hasLoaders()) { | ||
#hasLoaders = () => { | ||
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload)); | ||
return !!(this.route.options.loader || componentTypes.some(d => this.route.options[d]?.preload)); | ||
}; | ||
@@ -170,4 +169,2 @@ __commit = () => { | ||
} | ||
// TODO: Should load promises be tracked based on location? | ||
this.__loadPromise = Promise.resolve().then(async () => { | ||
@@ -196,10 +193,10 @@ const loadId = '' + Date.now() + Math.random(); | ||
const component = this.route.options[type]; | ||
if (this[type]?.preload) { | ||
this[type] = await this.router.options.loadComponent(component); | ||
if (component?.preload) { | ||
await component.preload(); | ||
} | ||
})); | ||
})(); | ||
const dataPromise = Promise.resolve().then(() => { | ||
if (this.route.options.onLoad) { | ||
return this.route.options.onLoad({ | ||
const loaderPromise = Promise.resolve().then(() => { | ||
if (this.route.options.loader) { | ||
return this.route.options.loader({ | ||
params: this.params, | ||
@@ -217,3 +214,3 @@ routeSearch, | ||
try { | ||
await Promise.all([componentsPromise, dataPromise]); | ||
const [_, loader] = await Promise.all([componentsPromise, loaderPromise]); | ||
if (latestPromise = checkLatest()) return await latestPromise; | ||
@@ -224,3 +221,4 @@ this.__store.setState(s => ({ | ||
status: 'success', | ||
updatedAt: Date.now() | ||
updatedAt: Date.now(), | ||
loader | ||
})); | ||
@@ -227,0 +225,0 @@ } catch (err) { |
@@ -15,3 +15,3 @@ /** | ||
var store = require('@tanstack/store'); | ||
var reactStore = require('@tanstack/react-store'); | ||
var invariant = require('tiny-invariant'); | ||
@@ -63,3 +63,3 @@ var path = require('./path.js'); | ||
}; | ||
this.__store = new store.Store(getInitialRouterState(), { | ||
this.__store = new reactStore.Store(getInitialRouterState(), { | ||
onUpdate: state => { | ||
@@ -70,7 +70,3 @@ this.state = state; | ||
this.state = this.__store.state; | ||
this.basepath = ''; | ||
this.update(options); | ||
// Allow frameworks to hook into the router creation | ||
this.options.Router?.(this); | ||
const next = this.buildNext({ | ||
@@ -102,4 +98,15 @@ hash: true, | ||
}; | ||
hydrate = async __do_not_use_server_ctx => { | ||
let ctx = __do_not_use_server_ctx; | ||
// Client hydrates from window | ||
if (typeof document !== 'undefined') { | ||
ctx = window.__DEHYDRATED__; | ||
invariant__default["default"](ctx, 'Expected to find a __DEHYDRATED__ property on window... but we did not. THIS IS VERY BAD'); | ||
} | ||
this.options.hydrate?.(ctx); | ||
return await this.load(); | ||
}; | ||
update = opts => { | ||
Object.assign(this.options, opts); | ||
this.context = this.options.context; | ||
if (!this.history || this.options.history && this.options.history !== this.history) { | ||
@@ -573,36 +580,53 @@ if (this.#unsubHistory) { | ||
}; | ||
dehydrate = () => { | ||
return { | ||
state: { | ||
...utils.pick(this.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']), | ||
currentMatches: this.state.currentMatches.map(match => ({ | ||
id: match.id, | ||
state: { | ||
status: match.state.status | ||
} | ||
})) | ||
} | ||
}; | ||
}; | ||
hydrate = dehydratedRouter => { | ||
this.__store.setState(s => { | ||
// Match the routes | ||
const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, { | ||
strictParseParams: true | ||
}); | ||
currentMatches.forEach((match, index) => { | ||
const dehydratedMatch = dehydratedRouter.state.currentMatches[index]; | ||
invariant__default["default"](dehydratedMatch && dehydratedMatch.id === match.id, 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬'); | ||
match.__store.setState(s => ({ | ||
...s, | ||
...dehydratedMatch.state | ||
})); | ||
}); | ||
return { | ||
...s, | ||
...dehydratedRouter.state, | ||
currentMatches | ||
}; | ||
}); | ||
}; | ||
// dehydrate = (): DehydratedRouter => { | ||
// return { | ||
// state: { | ||
// ...pick(this.state, [ | ||
// 'latestLocation', | ||
// 'currentLocation', | ||
// 'status', | ||
// 'lastUpdated', | ||
// ]), | ||
// // currentMatches: this.state.currentMatches.map((match) => ({ | ||
// // id: match.id, | ||
// // state: { | ||
// // status: match.state.status, | ||
// // // status: 'idle', | ||
// // }, | ||
// // })), | ||
// }, | ||
// } | ||
// } | ||
// hydrate = (dehydratedRouter: DehydratedRouter) => { | ||
// this.__store.setState((s) => { | ||
// // Match the routes | ||
// // const currentMatches = this.matchRoutes( | ||
// // dehydratedRouter.state.latestLocation.pathname, | ||
// // { | ||
// // strictParseParams: true, | ||
// // }, | ||
// // ) | ||
// // currentMatches.forEach((match, index) => { | ||
// // const dehydratedMatch = dehydratedRouter.state.currentMatches[index] | ||
// // invariant( | ||
// // dehydratedMatch && dehydratedMatch.id === match.id, | ||
// // 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬', | ||
// // ) | ||
// // match.__store.setState((s) => ({ | ||
// // ...s, | ||
// // ...dehydratedMatch.state, | ||
// // })) | ||
// // }) | ||
// return { | ||
// ...s, | ||
// ...dehydratedRouter.state, | ||
// // currentMatches, | ||
// } | ||
// }) | ||
// } | ||
#buildRouteTree = routeTree => { | ||
@@ -609,0 +633,0 @@ const recurseRoutes = (routes, parentRoute) => { |
@@ -13,4 +13,7 @@ /** | ||
export { default as invariant } from 'tiny-invariant'; | ||
import warning from 'tiny-warning'; | ||
export { default as warning } from 'tiny-warning'; | ||
import { Store } from '@tanstack/store'; | ||
import * as React from 'react'; | ||
import { useStore, Store } from '@tanstack/react-store'; | ||
export { useStore } from '@tanstack/react-store'; | ||
@@ -524,2 +527,433 @@ // While the public API was clearly inspired by the "history" npm package, | ||
function _extends() { | ||
_extends = Object.assign ? Object.assign.bind() : function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
return _extends.apply(this, arguments); | ||
} | ||
// | ||
function lazy(importer) { | ||
const lazyComp = /*#__PURE__*/React.lazy(importer); | ||
const finalComp = lazyComp; | ||
finalComp.preload = async () => { | ||
{ | ||
await importer(); | ||
} | ||
}; | ||
return finalComp; | ||
} | ||
// | ||
function useLinkProps(options) { | ||
const router = useRouterContext(); | ||
const { | ||
// custom props | ||
type, | ||
children, | ||
target, | ||
activeProps = () => ({ | ||
className: 'active' | ||
}), | ||
inactiveProps = () => ({}), | ||
activeOptions, | ||
disabled, | ||
// fromCurrent, | ||
hash, | ||
search, | ||
params, | ||
to = '.', | ||
preload, | ||
preloadDelay, | ||
replace, | ||
// element props | ||
style, | ||
className, | ||
onClick, | ||
onFocus, | ||
onMouseEnter, | ||
onMouseLeave, | ||
onTouchStart, | ||
...rest | ||
} = options; | ||
const linkInfo = router.buildLink(options); | ||
if (linkInfo.type === 'external') { | ||
const { | ||
href | ||
} = linkInfo; | ||
return { | ||
href | ||
}; | ||
} | ||
const { | ||
handleClick, | ||
handleFocus, | ||
handleEnter, | ||
handleLeave, | ||
handleTouchStart, | ||
isActive, | ||
next | ||
} = linkInfo; | ||
const reactHandleClick = e => { | ||
if (React.startTransition) { | ||
// This is a hack for react < 18 | ||
React.startTransition(() => { | ||
handleClick(e); | ||
}); | ||
} else { | ||
handleClick(e); | ||
} | ||
}; | ||
const composeHandlers = handlers => e => { | ||
if (e.persist) e.persist(); | ||
handlers.filter(Boolean).forEach(handler => { | ||
if (e.defaultPrevented) return; | ||
handler(e); | ||
}); | ||
}; | ||
// Get the active props | ||
const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {}; | ||
// Get the inactive props | ||
const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {}; | ||
return { | ||
...resolvedActiveProps, | ||
...resolvedInactiveProps, | ||
...rest, | ||
href: disabled ? undefined : next.href, | ||
onClick: composeHandlers([onClick, reactHandleClick]), | ||
onFocus: composeHandlers([onFocus, handleFocus]), | ||
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]), | ||
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]), | ||
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]), | ||
target, | ||
style: { | ||
...style, | ||
...resolvedActiveProps.style, | ||
...resolvedInactiveProps.style | ||
}, | ||
className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined, | ||
...(disabled ? { | ||
role: 'link', | ||
'aria-disabled': true | ||
} : undefined), | ||
['data-status']: isActive ? 'active' : undefined | ||
}; | ||
} | ||
const Link = /*#__PURE__*/React.forwardRef((props, ref) => { | ||
const linkProps = useLinkProps(props); | ||
return /*#__PURE__*/React.createElement("a", _extends({ | ||
ref: ref | ||
}, linkProps, { | ||
children: typeof props.children === 'function' ? props.children({ | ||
isActive: linkProps['data-status'] === 'active' | ||
}) : props.children | ||
})); | ||
}); | ||
function Navigate(props) { | ||
const router = useRouterContext(); | ||
React.useLayoutEffect(() => { | ||
router.navigate(props); | ||
}, []); | ||
return null; | ||
} | ||
const matchesContext = /*#__PURE__*/React.createContext(null); | ||
const routerContext = /*#__PURE__*/React.createContext(null); | ||
function RouterProvider({ | ||
router, | ||
...rest | ||
}) { | ||
router.update(rest); | ||
const currentMatches = useStore(router.__store, s => s.currentMatches); | ||
React.useEffect(router.mount, [router]); | ||
return /*#__PURE__*/React.createElement(routerContext.Provider, { | ||
value: { | ||
router: router | ||
} | ||
}, /*#__PURE__*/React.createElement(matchesContext.Provider, { | ||
value: [undefined, ...currentMatches] | ||
}, /*#__PURE__*/React.createElement(CatchBoundary, { | ||
errorComponent: ErrorComponent, | ||
onCatch: () => { | ||
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`); | ||
} | ||
}, /*#__PURE__*/React.createElement(Outlet, null)))); | ||
} | ||
function useRouterContext() { | ||
const value = React.useContext(routerContext); | ||
warning(value, 'useRouter must be used inside a <Router> component!'); | ||
useStore(value.router.__store); | ||
return value.router; | ||
} | ||
function useRouter(track) { | ||
const router = useRouterContext(); | ||
useStore(router.__store, track); | ||
return router; | ||
} | ||
function useMatches() { | ||
return React.useContext(matchesContext); | ||
} | ||
function useMatch(opts) { | ||
const router = useRouterContext(); | ||
const nearestMatch = useMatches()[0]; | ||
const match = opts?.from ? router.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch; | ||
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`); | ||
if (opts?.strict ?? true) { | ||
invariant(nearestMatch.route.id == match?.route.id, `useMatch("${match?.route.id}") is being called in a component that is meant to render the '${nearestMatch.route.id}' route. Did you mean to 'useMatch("${match?.route.id}", { strict: false })' or 'useRoute("${match?.route.id}")' instead?`); | ||
} | ||
useStore(match.__store, d => opts?.track?.(match) ?? match); | ||
return match; | ||
} | ||
// export function useRoute< | ||
// TId extends keyof RegisteredRoutesInfo['routesById'] = '/', | ||
// >(routeId: TId): RegisteredRoutesInfo['routesById'][TId] { | ||
// const router = useRouterContext() | ||
// const resolvedRoute = router.getRoute(routeId as any) | ||
// invariant( | ||
// resolvedRoute, | ||
// `Could not find a route for route "${ | ||
// routeId as string | ||
// }"! Did you forget to add it to your route?`, | ||
// ) | ||
// return resolvedRoute as any | ||
// } | ||
// export function useRoute<TRouteOrId>( | ||
// route: TRouteOrId extends string | ||
// ? keyof RegisteredRoutesInfo['routeIds'] | ||
// : RegisteredRoutesInfo['routeUnion'], | ||
// ): RouteFromIdOrRoute<TRouteOrId> { | ||
// return null as any | ||
// } | ||
function useLoader(opts) { | ||
const { | ||
track, | ||
...matchOpts | ||
} = opts; | ||
const match = useMatch(matchOpts); | ||
useStore(match.__store, d => opts?.track?.(d.loader) ?? d.loader); | ||
return match.state.loader; | ||
} | ||
function useSearch(opts) { | ||
const { | ||
track, | ||
...matchOpts | ||
} = opts; | ||
const match = useMatch(matchOpts); | ||
useStore(match.__store, d => opts?.track?.(d.search) ?? d.search); | ||
return match.state.search; | ||
} | ||
function useParams(opts) { | ||
const router = useRouterContext(); | ||
useStore(router.__store, d => { | ||
const params = last(d.currentMatches)?.params; | ||
return opts?.track?.(params) ?? params; | ||
}); | ||
return last(router.state.currentMatches)?.params; | ||
} | ||
function useNavigate(defaultOpts) { | ||
const router = useRouterContext(); | ||
return React.useCallback(opts => { | ||
return router.navigate({ | ||
...defaultOpts, | ||
...opts | ||
}); | ||
}, []); | ||
} | ||
function useMatchRoute() { | ||
const router = useRouterContext(); | ||
return React.useCallback(opts => { | ||
const { | ||
pending, | ||
caseSensitive, | ||
...rest | ||
} = opts; | ||
return router.matchRoute(rest, { | ||
pending, | ||
caseSensitive | ||
}); | ||
}, []); | ||
} | ||
function MatchRoute(props) { | ||
const matchRoute = useMatchRoute(); | ||
const params = matchRoute(props); | ||
if (!params) { | ||
return null; | ||
} | ||
if (typeof props.children === 'function') { | ||
return props.children(params); | ||
} | ||
return params ? props.children : null; | ||
} | ||
function Outlet() { | ||
const matches = useMatches().slice(1); | ||
const match = matches[0]; | ||
if (!match) { | ||
return null; | ||
} | ||
return /*#__PURE__*/React.createElement(SubOutlet, { | ||
matches: matches, | ||
match: match | ||
}); | ||
} | ||
function SubOutlet({ | ||
matches, | ||
match | ||
}) { | ||
const router = useRouterContext(); | ||
useStore(match.__store, store => [store.status, store.error]); | ||
const defaultPending = React.useCallback(() => null, []); | ||
const PendingComponent = match.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending; | ||
const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent; | ||
const ResolvedSuspenseBoundary = match.route.options.wrapInSuspense ?? true ? React.Suspense : SafeFragment; | ||
const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment; | ||
return /*#__PURE__*/React.createElement(matchesContext.Provider, { | ||
value: matches | ||
}, /*#__PURE__*/React.createElement(ResolvedSuspenseBoundary, { | ||
fallback: /*#__PURE__*/React.createElement(PendingComponent, null) | ||
}, /*#__PURE__*/React.createElement(ResolvedCatchBoundary, { | ||
key: match.route.id, | ||
errorComponent: errorComponent, | ||
onCatch: () => { | ||
warning(false, `Error in route match: ${match.id}`); | ||
} | ||
}, /*#__PURE__*/React.createElement(Inner, { | ||
match: match | ||
})))); | ||
} | ||
function Inner(props) { | ||
const router = useRouterContext(); | ||
if (props.match.state.status === 'error') { | ||
throw props.match.state.error; | ||
} | ||
if (props.match.state.status === 'pending') { | ||
throw props.match.__loadPromise; | ||
} | ||
if (props.match.state.status === 'success') { | ||
return /*#__PURE__*/React.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet, { | ||
useLoader: props.match.route.useLoader, | ||
useMatch: props.match.route.useMatch, | ||
useContext: props.match.route.useContext, | ||
useSearch: props.match.route.useSearch | ||
}); | ||
} | ||
invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!'); | ||
} | ||
function SafeFragment(props) { | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
} | ||
// This is the messiest thing ever... I'm either seriously tired (likely) or | ||
// there has to be a better way to reset error boundaries when the | ||
// router's location key changes. | ||
class CatchBoundary extends React.Component { | ||
state = { | ||
error: false, | ||
info: undefined | ||
}; | ||
componentDidCatch(error, info) { | ||
this.props.onCatch(error, info); | ||
console.error(error); | ||
this.setState({ | ||
error, | ||
info | ||
}); | ||
} | ||
render() { | ||
return /*#__PURE__*/React.createElement(CatchBoundaryInner, _extends({}, this.props, { | ||
errorState: this.state, | ||
reset: () => this.setState({}) | ||
})); | ||
} | ||
} | ||
function CatchBoundaryInner(props) { | ||
const [activeErrorState, setActiveErrorState] = React.useState(props.errorState); | ||
const router = useRouterContext(); | ||
const errorComponent = props.errorComponent ?? ErrorComponent; | ||
const prevKeyRef = React.useRef(''); | ||
React.useEffect(() => { | ||
if (activeErrorState) { | ||
if (router.state.currentLocation.key !== prevKeyRef.current) { | ||
setActiveErrorState({}); | ||
} | ||
} | ||
prevKeyRef.current = router.state.currentLocation.key; | ||
}, [activeErrorState, router.state.currentLocation.key]); | ||
React.useEffect(() => { | ||
if (props.errorState.error) { | ||
setActiveErrorState(props.errorState); | ||
} | ||
// props.reset() | ||
}, [props.errorState.error]); | ||
if (props.errorState.error && activeErrorState.error) { | ||
return /*#__PURE__*/React.createElement(errorComponent, activeErrorState); | ||
} | ||
return props.children; | ||
} | ||
function ErrorComponent({ | ||
error | ||
}) { | ||
return /*#__PURE__*/React.createElement("div", { | ||
style: { | ||
padding: '.5rem', | ||
maxWidth: '100%' | ||
} | ||
}, /*#__PURE__*/React.createElement("strong", { | ||
style: { | ||
fontSize: '1.2rem' | ||
} | ||
}, "Something went wrong!"), /*#__PURE__*/React.createElement("div", { | ||
style: { | ||
height: '.5rem' | ||
} | ||
}), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("pre", { | ||
style: { | ||
fontSize: '.7em', | ||
border: '1px solid red', | ||
borderRadius: '.25rem', | ||
padding: '.5rem', | ||
color: 'red', | ||
overflow: 'auto' | ||
} | ||
}, error.message ? /*#__PURE__*/React.createElement("code", null, error.message) : null))); | ||
} | ||
function useBlocker(message, condition = true) { | ||
const router = useRouter(); | ||
React.useEffect(() => { | ||
if (!condition) return; | ||
let unblock = router.history.block((retry, cancel) => { | ||
if (window.confirm(message)) { | ||
unblock(); | ||
retry(); | ||
} else { | ||
cancel(); | ||
} | ||
}); | ||
return unblock; | ||
}); | ||
} | ||
function Block({ | ||
message, | ||
condition, | ||
children | ||
}) { | ||
useBlocker(message, condition); | ||
return children ?? null; | ||
} | ||
const rootRouteId = '__root__'; | ||
@@ -574,30 +1008,27 @@ class Route { | ||
}; | ||
// generate = ( | ||
// options: Omit< | ||
// RouteOptions< | ||
// TParentRoute, | ||
// TCustomId, | ||
// TPath, | ||
// InferFullSearchSchema<TParentRoute>, | ||
// TSearchSchema, | ||
// TFullSearchSchema, | ||
// TParentRoute['__types']['allParams'], | ||
// TParams, | ||
// TAllParams, | ||
// TParentContext, | ||
// TAllParentContext, | ||
// TRouteContext, | ||
// TContext | ||
// >, | ||
// 'path' | ||
// >, | ||
// ) => { | ||
// invariant( | ||
// false, | ||
// `route.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `, | ||
// ) | ||
// } | ||
useMatch = opts => { | ||
return useMatch({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
useLoader = opts => { | ||
return useLoader({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
useContext = opts => { | ||
return useMatch({ | ||
...opts, | ||
from: this.id | ||
}).context; | ||
}; | ||
useSearch = opts => { | ||
return useSearch({ | ||
...opts, | ||
from: this.id | ||
}); | ||
}; | ||
} | ||
class RootRoute extends Route { | ||
@@ -744,7 +1175,3 @@ constructor(options) { | ||
this.state = this.__store.state; | ||
this.basepath = ''; | ||
this.update(options); | ||
// Allow frameworks to hook into the router creation | ||
this.options.Router?.(this); | ||
const next = this.buildNext({ | ||
@@ -776,4 +1203,15 @@ hash: true, | ||
}; | ||
hydrate = async __do_not_use_server_ctx => { | ||
let ctx = __do_not_use_server_ctx; | ||
// Client hydrates from window | ||
if (typeof document !== 'undefined') { | ||
ctx = window.__DEHYDRATED__; | ||
invariant(ctx, 'Expected to find a __DEHYDRATED__ property on window... but we did not. THIS IS VERY BAD'); | ||
} | ||
this.options.hydrate?.(ctx); | ||
return await this.load(); | ||
}; | ||
update = opts => { | ||
Object.assign(this.options, opts); | ||
this.context = this.options.context; | ||
if (!this.history || this.options.history && this.options.history !== this.history) { | ||
@@ -1247,36 +1685,53 @@ if (this.#unsubHistory) { | ||
}; | ||
dehydrate = () => { | ||
return { | ||
state: { | ||
...pick(this.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']), | ||
currentMatches: this.state.currentMatches.map(match => ({ | ||
id: match.id, | ||
state: { | ||
status: match.state.status | ||
} | ||
})) | ||
} | ||
}; | ||
}; | ||
hydrate = dehydratedRouter => { | ||
this.__store.setState(s => { | ||
// Match the routes | ||
const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, { | ||
strictParseParams: true | ||
}); | ||
currentMatches.forEach((match, index) => { | ||
const dehydratedMatch = dehydratedRouter.state.currentMatches[index]; | ||
invariant(dehydratedMatch && dehydratedMatch.id === match.id, 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬'); | ||
match.__store.setState(s => ({ | ||
...s, | ||
...dehydratedMatch.state | ||
})); | ||
}); | ||
return { | ||
...s, | ||
...dehydratedRouter.state, | ||
currentMatches | ||
}; | ||
}); | ||
}; | ||
// dehydrate = (): DehydratedRouter => { | ||
// return { | ||
// state: { | ||
// ...pick(this.state, [ | ||
// 'latestLocation', | ||
// 'currentLocation', | ||
// 'status', | ||
// 'lastUpdated', | ||
// ]), | ||
// // currentMatches: this.state.currentMatches.map((match) => ({ | ||
// // id: match.id, | ||
// // state: { | ||
// // status: match.state.status, | ||
// // // status: 'idle', | ||
// // }, | ||
// // })), | ||
// }, | ||
// } | ||
// } | ||
// hydrate = (dehydratedRouter: DehydratedRouter) => { | ||
// this.__store.setState((s) => { | ||
// // Match the routes | ||
// // const currentMatches = this.matchRoutes( | ||
// // dehydratedRouter.state.latestLocation.pathname, | ||
// // { | ||
// // strictParseParams: true, | ||
// // }, | ||
// // ) | ||
// // currentMatches.forEach((match, index) => { | ||
// // const dehydratedMatch = dehydratedRouter.state.currentMatches[index] | ||
// // invariant( | ||
// // dehydratedMatch && dehydratedMatch.id === match.id, | ||
// // 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬', | ||
// // ) | ||
// // match.__store.setState((s) => ({ | ||
// // ...s, | ||
// // ...dehydratedMatch.state, | ||
// // })) | ||
// // }) | ||
// return { | ||
// ...s, | ||
// ...dehydratedRouter.state, | ||
// // currentMatches, | ||
// } | ||
// }) | ||
// } | ||
#buildRouteTree = routeTree => { | ||
@@ -1475,3 +1930,4 @@ const recurseRoutes = (routes, parentRoute) => { | ||
search: {}, | ||
status: 'idle' | ||
status: 'idle', | ||
loader: undefined | ||
}, { | ||
@@ -1486,5 +1942,3 @@ onUpdate: next => { | ||
const component = this.route.options[type]; | ||
if (typeof this[type] !== 'function') { | ||
this[type] = component; | ||
} | ||
this[type] = component; | ||
}); | ||
@@ -1499,3 +1953,3 @@ if (this.state.status === 'idle' && !this.#hasLoaders()) { | ||
#hasLoaders = () => { | ||
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload)); | ||
return !!(this.route.options.loader || componentTypes.some(d => this.route.options[d]?.preload)); | ||
}; | ||
@@ -1611,4 +2065,2 @@ __commit = () => { | ||
} | ||
// TODO: Should load promises be tracked based on location? | ||
this.__loadPromise = Promise.resolve().then(async () => { | ||
@@ -1637,10 +2089,10 @@ const loadId = '' + Date.now() + Math.random(); | ||
const component = this.route.options[type]; | ||
if (this[type]?.preload) { | ||
this[type] = await this.router.options.loadComponent(component); | ||
if (component?.preload) { | ||
await component.preload(); | ||
} | ||
})); | ||
})(); | ||
const dataPromise = Promise.resolve().then(() => { | ||
if (this.route.options.onLoad) { | ||
return this.route.options.onLoad({ | ||
const loaderPromise = Promise.resolve().then(() => { | ||
if (this.route.options.loader) { | ||
return this.route.options.loader({ | ||
params: this.params, | ||
@@ -1658,3 +2110,3 @@ routeSearch, | ||
try { | ||
await Promise.all([componentsPromise, dataPromise]); | ||
const [_, loader] = await Promise.all([componentsPromise, loaderPromise]); | ||
if (latestPromise = checkLatest()) return await latestPromise; | ||
@@ -1665,3 +2117,4 @@ this.__store.setState(s => ({ | ||
status: 'success', | ||
updatedAt: Date.now() | ||
updatedAt: Date.now(), | ||
loader | ||
})); | ||
@@ -1708,3 +2161,3 @@ } catch (err) { | ||
export { RootRoute, Route, RouteMatch, Router, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultFetchServerDataFn, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight }; | ||
export { Block, ErrorComponent, Link, MatchRoute, Navigate, Outlet, RootRoute, Route, RouteMatch, Router, RouterProvider, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultFetchServerDataFn, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, lazy, matchByPath, matchPathname, matchesContext, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, routerContext, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, useBlocker, useLinkProps, useLoader, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useRouter, useRouterContext, useSearch }; | ||
//# sourceMappingURL=index.js.map |
@@ -14,7 +14,7 @@ { | ||
"name": "tiny-invariant@1.3.1/node_modules/tiny-invariant/dist/esm/tiny-invariant.js", | ||
"uid": "3f93-32" | ||
"uid": "5b7b-49" | ||
}, | ||
{ | ||
"name": "tiny-warning@1.0.3/node_modules/tiny-warning/dist/tiny-warning.esm.js", | ||
"uid": "3f93-34" | ||
"uid": "5b7b-51" | ||
} | ||
@@ -30,35 +30,39 @@ ] | ||
{ | ||
"uid": "3f93-36", | ||
"uid": "5b7b-53", | ||
"name": "history.ts" | ||
}, | ||
{ | ||
"uid": "3f93-38", | ||
"uid": "5b7b-55", | ||
"name": "utils.ts" | ||
}, | ||
{ | ||
"uid": "3f93-40", | ||
"uid": "5b7b-57", | ||
"name": "path.ts" | ||
}, | ||
{ | ||
"uid": "3f93-42", | ||
"uid": "5b7b-59", | ||
"name": "qss.ts" | ||
}, | ||
{ | ||
"uid": "3f93-44", | ||
"uid": "5b7b-67", | ||
"name": "react.tsx" | ||
}, | ||
{ | ||
"uid": "5b7b-69", | ||
"name": "route.ts" | ||
}, | ||
{ | ||
"uid": "3f93-48", | ||
"uid": "5b7b-71", | ||
"name": "searchParams.ts" | ||
}, | ||
{ | ||
"uid": "3f93-50", | ||
"uid": "5b7b-73", | ||
"name": "router.ts" | ||
}, | ||
{ | ||
"uid": "3f93-52", | ||
"uid": "5b7b-75", | ||
"name": "routeMatch.ts" | ||
}, | ||
{ | ||
"uid": "3f93-54", | ||
"uid": "5b7b-77", | ||
"name": "index.ts" | ||
@@ -70,5 +74,13 @@ } | ||
"name": "store/build/esm/index.js", | ||
"uid": "3f93-46" | ||
"uid": "5b7b-63" | ||
}, | ||
{ | ||
"name": "react-store/build/esm/index.js", | ||
"uid": "5b7b-65" | ||
} | ||
] | ||
}, | ||
{ | ||
"uid": "5b7b-61", | ||
"name": "\u0000rollupPluginBabelHelpers.js" | ||
} | ||
@@ -81,80 +93,98 @@ ] | ||
"nodeParts": { | ||
"3f93-32": { | ||
"5b7b-49": { | ||
"renderedLength": 199, | ||
"gzipLength": 134, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-31" | ||
"mainUid": "5b7b-48" | ||
}, | ||
"3f93-34": { | ||
"5b7b-51": { | ||
"renderedLength": 48, | ||
"gzipLength": 65, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-33" | ||
"mainUid": "5b7b-50" | ||
}, | ||
"3f93-36": { | ||
"5b7b-53": { | ||
"renderedLength": 5639, | ||
"gzipLength": 1385, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-35" | ||
"mainUid": "5b7b-52" | ||
}, | ||
"3f93-38": { | ||
"5b7b-55": { | ||
"renderedLength": 2821, | ||
"gzipLength": 990, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-37" | ||
"mainUid": "5b7b-54" | ||
}, | ||
"3f93-40": { | ||
"5b7b-57": { | ||
"renderedLength": 5705, | ||
"gzipLength": 1352, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-39" | ||
"mainUid": "5b7b-56" | ||
}, | ||
"3f93-42": { | ||
"5b7b-59": { | ||
"renderedLength": 1395, | ||
"gzipLength": 558, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-41" | ||
"mainUid": "5b7b-58" | ||
}, | ||
"3f93-44": { | ||
"renderedLength": 3715, | ||
"gzipLength": 1056, | ||
"5b7b-61": { | ||
"renderedLength": 457, | ||
"gzipLength": 241, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-43" | ||
"mainUid": "5b7b-60" | ||
}, | ||
"3f93-46": { | ||
"5b7b-63": { | ||
"renderedLength": 1384, | ||
"gzipLength": 502, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-45" | ||
"mainUid": "5b7b-62" | ||
}, | ||
"3f93-48": { | ||
"5b7b-65": { | ||
"renderedLength": 1042, | ||
"gzipLength": 465, | ||
"brotliLength": 0, | ||
"mainUid": "5b7b-64" | ||
}, | ||
"5b7b-67": { | ||
"renderedLength": 13748, | ||
"gzipLength": 3309, | ||
"brotliLength": 0, | ||
"mainUid": "5b7b-66" | ||
}, | ||
"5b7b-69": { | ||
"renderedLength": 3424, | ||
"gzipLength": 897, | ||
"brotliLength": 0, | ||
"mainUid": "5b7b-68" | ||
}, | ||
"5b7b-71": { | ||
"renderedLength": 1387, | ||
"gzipLength": 483, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-47" | ||
"mainUid": "5b7b-70" | ||
}, | ||
"3f93-50": { | ||
"renderedLength": 25930, | ||
"gzipLength": 5901, | ||
"5b7b-73": { | ||
"renderedLength": 26712, | ||
"gzipLength": 6119, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-49" | ||
"mainUid": "5b7b-72" | ||
}, | ||
"3f93-52": { | ||
"renderedLength": 7647, | ||
"gzipLength": 1795, | ||
"5b7b-75": { | ||
"renderedLength": 7552, | ||
"gzipLength": 1757, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-51" | ||
"mainUid": "5b7b-74" | ||
}, | ||
"3f93-54": { | ||
"5b7b-77": { | ||
"renderedLength": 0, | ||
"gzipLength": 0, | ||
"brotliLength": 0, | ||
"mainUid": "3f93-53" | ||
"mainUid": "5b7b-76" | ||
} | ||
}, | ||
"nodeMetas": { | ||
"3f93-31": { | ||
"5b7b-48": { | ||
"id": "/node_modules/.pnpm/tiny-invariant@1.3.1/node_modules/tiny-invariant/dist/esm/tiny-invariant.js", | ||
"moduleParts": { | ||
"index.production.js": "3f93-32" | ||
"index.production.js": "5b7b-49" | ||
}, | ||
@@ -164,16 +194,19 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-43" | ||
"uid": "5b7b-68" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
}, | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
}, | ||
"3f93-33": { | ||
"5b7b-50": { | ||
"id": "/node_modules/.pnpm/tiny-warning@1.0.3/node_modules/tiny-warning/dist/tiny-warning.esm.js", | ||
"moduleParts": { | ||
"index.production.js": "3f93-34" | ||
"index.production.js": "5b7b-51" | ||
}, | ||
@@ -183,10 +216,13 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
}, | ||
"3f93-35": { | ||
"5b7b-52": { | ||
"id": "/packages/router/src/history.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-36" | ||
"index.production.js": "5b7b-53" | ||
}, | ||
@@ -196,13 +232,13 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
} | ||
] | ||
}, | ||
"3f93-37": { | ||
"5b7b-54": { | ||
"id": "/packages/router/src/utils.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-38" | ||
"index.production.js": "5b7b-55" | ||
}, | ||
@@ -212,23 +248,26 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-39" | ||
"uid": "5b7b-56" | ||
}, | ||
{ | ||
"uid": "3f93-51" | ||
"uid": "5b7b-74" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
}, | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
}, | ||
"3f93-39": { | ||
"5b7b-56": { | ||
"id": "/packages/router/src/path.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-40" | ||
"index.production.js": "5b7b-57" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-37" | ||
"uid": "5b7b-54" | ||
} | ||
@@ -238,16 +277,16 @@ ], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-43" | ||
"uid": "5b7b-68" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
} | ||
] | ||
}, | ||
"3f93-41": { | ||
"5b7b-58": { | ||
"id": "/packages/router/src/qss.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-42" | ||
"index.production.js": "5b7b-59" | ||
}, | ||
@@ -257,20 +296,44 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-47" | ||
"uid": "5b7b-70" | ||
} | ||
] | ||
}, | ||
"3f93-43": { | ||
"id": "/packages/router/src/route.ts", | ||
"5b7b-60": { | ||
"id": "\u0000rollupPluginBabelHelpers.js", | ||
"moduleParts": { | ||
"index.production.js": "3f93-44" | ||
"index.production.js": "5b7b-61" | ||
}, | ||
"imported": [], | ||
"importedBy": [ | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
}, | ||
"5b7b-62": { | ||
"id": "/packages/store/build/esm/index.js", | ||
"moduleParts": { | ||
"index.production.js": "5b7b-63" | ||
}, | ||
"imported": [], | ||
"importedBy": [ | ||
{ | ||
"uid": "5b7b-64" | ||
} | ||
] | ||
}, | ||
"5b7b-64": { | ||
"id": "/packages/react-store/build/esm/index.js", | ||
"moduleParts": { | ||
"index.production.js": "5b7b-65" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-31" | ||
"uid": "5b7b-81" | ||
}, | ||
{ | ||
"uid": "3f93-39" | ||
"uid": "5b7b-62" | ||
} | ||
@@ -280,29 +343,76 @@ ], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-74" | ||
}, | ||
{ | ||
"uid": "5b7b-72" | ||
}, | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
}, | ||
"3f93-45": { | ||
"id": "/packages/store/build/esm/index.js", | ||
"5b7b-66": { | ||
"id": "/packages/router/src/react.tsx", | ||
"moduleParts": { | ||
"index.production.js": "3f93-46" | ||
"index.production.js": "5b7b-67" | ||
}, | ||
"imported": [], | ||
"imported": [ | ||
{ | ||
"uid": "5b7b-60" | ||
}, | ||
{ | ||
"uid": "5b7b-80" | ||
}, | ||
{ | ||
"uid": "5b7b-64" | ||
}, | ||
{ | ||
"uid": "5b7b-48" | ||
}, | ||
{ | ||
"uid": "5b7b-50" | ||
}, | ||
{ | ||
"uid": "5b7b-54" | ||
} | ||
], | ||
"importedBy": [ | ||
{ | ||
"uid": "3f93-51" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-68" | ||
} | ||
] | ||
}, | ||
"3f93-47": { | ||
"5b7b-68": { | ||
"id": "/packages/router/src/route.ts", | ||
"moduleParts": { | ||
"index.production.js": "5b7b-69" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "5b7b-48" | ||
}, | ||
{ | ||
"uid": "5b7b-56" | ||
}, | ||
{ | ||
"uid": "5b7b-66" | ||
} | ||
], | ||
"importedBy": [ | ||
{ | ||
"uid": "5b7b-76" | ||
} | ||
] | ||
}, | ||
"5b7b-70": { | ||
"id": "/packages/router/src/searchParams.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-48" | ||
"index.production.js": "5b7b-71" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-41" | ||
"uid": "5b7b-58" | ||
} | ||
@@ -312,35 +422,35 @@ ], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
} | ||
] | ||
}, | ||
"3f93-49": { | ||
"5b7b-72": { | ||
"id": "/packages/router/src/router.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-50" | ||
"index.production.js": "5b7b-73" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-45" | ||
"uid": "5b7b-64" | ||
}, | ||
{ | ||
"uid": "3f93-31" | ||
"uid": "5b7b-48" | ||
}, | ||
{ | ||
"uid": "3f93-39" | ||
"uid": "5b7b-56" | ||
}, | ||
{ | ||
"uid": "3f93-51" | ||
"uid": "5b7b-74" | ||
}, | ||
{ | ||
"uid": "3f93-47" | ||
"uid": "5b7b-70" | ||
}, | ||
{ | ||
"uid": "3f93-37" | ||
"uid": "5b7b-54" | ||
}, | ||
{ | ||
"uid": "3f93-35" | ||
"uid": "5b7b-52" | ||
} | ||
@@ -350,23 +460,23 @@ ], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-51" | ||
"uid": "5b7b-74" | ||
} | ||
] | ||
}, | ||
"3f93-51": { | ||
"5b7b-74": { | ||
"id": "/packages/router/src/routeMatch.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-52" | ||
"index.production.js": "5b7b-75" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-45" | ||
"uid": "5b7b-64" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
}, | ||
{ | ||
"uid": "3f93-37" | ||
"uid": "5b7b-54" | ||
} | ||
@@ -376,53 +486,53 @@ ], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-72" | ||
} | ||
] | ||
}, | ||
"3f93-53": { | ||
"5b7b-76": { | ||
"id": "/packages/router/src/index.ts", | ||
"moduleParts": { | ||
"index.production.js": "3f93-54" | ||
"index.production.js": "5b7b-77" | ||
}, | ||
"imported": [ | ||
{ | ||
"uid": "3f93-31" | ||
"uid": "5b7b-48" | ||
}, | ||
{ | ||
"uid": "3f93-33" | ||
"uid": "5b7b-50" | ||
}, | ||
{ | ||
"uid": "3f93-35" | ||
"uid": "5b7b-52" | ||
}, | ||
{ | ||
"uid": "3f93-55" | ||
"uid": "5b7b-78" | ||
}, | ||
{ | ||
"uid": "3f93-56" | ||
"uid": "5b7b-56" | ||
}, | ||
{ | ||
"uid": "3f93-39" | ||
"uid": "5b7b-58" | ||
}, | ||
{ | ||
"uid": "3f93-41" | ||
"uid": "5b7b-68" | ||
}, | ||
{ | ||
"uid": "3f93-43" | ||
"uid": "5b7b-79" | ||
}, | ||
{ | ||
"uid": "3f93-57" | ||
"uid": "5b7b-74" | ||
}, | ||
{ | ||
"uid": "3f93-51" | ||
"uid": "5b7b-72" | ||
}, | ||
{ | ||
"uid": "3f93-49" | ||
"uid": "5b7b-70" | ||
}, | ||
{ | ||
"uid": "3f93-47" | ||
"uid": "5b7b-54" | ||
}, | ||
{ | ||
"uid": "3f93-37" | ||
"uid": "5b7b-66" | ||
} | ||
@@ -433,4 +543,4 @@ ], | ||
}, | ||
"3f93-55": { | ||
"id": "/packages/router/src/frameworks.ts", | ||
"5b7b-78": { | ||
"id": "/packages/router/src/link.ts", | ||
"moduleParts": {}, | ||
@@ -440,8 +550,8 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
} | ||
] | ||
}, | ||
"3f93-56": { | ||
"id": "/packages/router/src/link.ts", | ||
"5b7b-79": { | ||
"id": "/packages/router/src/routeInfo.ts", | ||
"moduleParts": {}, | ||
@@ -451,8 +561,8 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-76" | ||
} | ||
] | ||
}, | ||
"3f93-57": { | ||
"id": "/packages/router/src/routeInfo.ts", | ||
"5b7b-80": { | ||
"id": "react", | ||
"moduleParts": {}, | ||
@@ -462,5 +572,17 @@ "imported": [], | ||
{ | ||
"uid": "3f93-53" | ||
"uid": "5b7b-66" | ||
} | ||
] | ||
], | ||
"isExternal": true | ||
}, | ||
"5b7b-81": { | ||
"id": "use-sync-external-store/shim/with-selector", | ||
"moduleParts": {}, | ||
"imported": [], | ||
"importedBy": [ | ||
{ | ||
"uid": "5b7b-64" | ||
} | ||
], | ||
"isExternal": true | ||
} | ||
@@ -467,0 +589,0 @@ }, |
@@ -13,3 +13,5 @@ /** | ||
export { default as warning } from 'tiny-warning'; | ||
import { Store } from '@tanstack/store'; | ||
import { Store, NoInfer as NoInfer$1 } from '@tanstack/react-store'; | ||
export { useStore } from '@tanstack/react-store'; | ||
import * as React$1 from 'react'; | ||
@@ -47,6 +49,2 @@ interface RouterHistory { | ||
interface FrameworkGenerics { | ||
} | ||
type GetFrameworkGeneric<U> = U extends keyof FrameworkGenerics ? FrameworkGenerics[U] : any; | ||
type NoInfer<T> = [T][T extends any ? 0 : never]; | ||
@@ -105,5 +103,10 @@ type IsAny<T, Y, N> = 1 extends 0 & T ? Y : N; | ||
declare global { | ||
interface Window { | ||
__DEHYDRATED__?: Record<string, any>; | ||
} | ||
} | ||
interface Register { | ||
} | ||
type AnyRouter = Router<any, any>; | ||
type AnyRouter = Router<any, any, any>; | ||
type RegisteredRouter = Register extends { | ||
@@ -140,3 +143,3 @@ router: Router<infer TRoute, infer TRoutesInfo>; | ||
}; | ||
interface RouterOptions<TRouteTree extends AnyRoute> { | ||
interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<string, any>> { | ||
history?: RouterHistory; | ||
@@ -148,5 +151,10 @@ stringifySearch?: SearchSerializer; | ||
defaultPreloadDelay?: number; | ||
defaultComponent?: GetFrameworkGeneric<'Component'>; | ||
defaultErrorComponent?: GetFrameworkGeneric<'ErrorComponent'>; | ||
defaultPendingComponent?: GetFrameworkGeneric<'Component'>; | ||
defaultComponent?: RouteComponent; | ||
defaultErrorComponent?: RouteComponent<{ | ||
error: Error; | ||
info: { | ||
componentStack: string; | ||
}; | ||
}>; | ||
defaultPendingComponent?: RouteComponent; | ||
defaultLoaderMaxAge?: number; | ||
@@ -157,3 +165,2 @@ defaultLoaderGcMaxAge?: number; | ||
basepath?: string; | ||
Router?: (router: AnyRouter) => void; | ||
createRoute?: (opts: { | ||
@@ -163,6 +170,10 @@ route: AnyRoute; | ||
}) => void; | ||
loadComponent?: (component: GetFrameworkGeneric<'Component'>) => Promise<GetFrameworkGeneric<'Component'>>; | ||
onRouteChange?: () => void; | ||
fetchServerDataFn?: FetchServerDataFn; | ||
context?: TRouteTree['__types']['routerContext']; | ||
Provider?: React.ComponentType<{ | ||
children: any; | ||
}>; | ||
dehydrate?: () => TDehydrated; | ||
hydrate?: (dehydrated: TDehydrated) => void; | ||
} | ||
@@ -173,3 +184,3 @@ type FetchServerDataFn = (ctx: { | ||
}) => Promise<any>; | ||
interface RouterStore<TRoutesInfo extends AnyRoutesInfo = AnyRoutesInfo, TState extends LocationState = LocationState> { | ||
interface RouterState<TRoutesInfo extends AnyRoutesInfo = AnyRoutesInfo, TState extends LocationState = LocationState> { | ||
status: 'idle' | 'pending'; | ||
@@ -212,4 +223,3 @@ latestLocation: ParsedLocation<TRoutesInfo['fullSearchSchema'], TState>; | ||
} | ||
interface DehydratedRouterState extends Pick<RouterStore, 'status' | 'latestLocation' | 'currentLocation' | 'lastUpdated'> { | ||
currentMatches: DehydratedRouteMatch[]; | ||
interface DehydratedRouterState extends Pick<RouterState, 'status' | 'latestLocation' | 'currentLocation' | 'lastUpdated'> { | ||
} | ||
@@ -220,11 +230,5 @@ interface DehydratedRouter { | ||
type MatchCache = Record<string, MatchCacheEntry>; | ||
interface DehydratedRouteMatch { | ||
id: string; | ||
state: Pick<RouteMatchStore<any, any>, 'status'>; | ||
} | ||
interface RouterContext { | ||
} | ||
declare const defaultFetchServerDataFn: FetchServerDataFn; | ||
type RouterConstructorOptions<TRouteTree extends AnyRoute> = Omit<RouterOptions<TRouteTree>, 'context'> & RouterContextOptions<TRouteTree>; | ||
declare class Router<TRouteTree extends AnyRoute = RootRoute, TRoutesInfo extends AnyRoutesInfo = RoutesInfo<TRouteTree>> { | ||
type RouterConstructorOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<string, any>> = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> & RouterContextOptions<TRouteTree>; | ||
declare class Router<TRouteTree extends AnyRoute = AnyRoute, TRoutesInfo extends AnyRoutesInfo = RoutesInfo<TRouteTree>, TDehydrated extends Record<string, any> = Record<string, any>> { | ||
#private; | ||
@@ -235,3 +239,4 @@ types: { | ||
}; | ||
options: PickAsRequired<RouterOptions<TRouteTree>, 'stringifySearch' | 'parseSearch' | 'context'>; | ||
options: PickAsRequired<RouterOptions<TRouteTree, TDehydrated>, 'stringifySearch' | 'parseSearch' | 'context'>; | ||
context: NonNullable<TRouteTree['__types']['routerContext']>; | ||
history: RouterHistory; | ||
@@ -244,11 +249,12 @@ basepath: string; | ||
navigationPromise: undefined | Promise<void>; | ||
__store: Store<RouterStore<TRoutesInfo>>; | ||
state: RouterStore<TRoutesInfo>; | ||
__store: Store<RouterState<TRoutesInfo>>; | ||
state: RouterState<TRoutesInfo>; | ||
startedLoadingAt: number; | ||
resolveNavigation: () => void; | ||
constructor(options?: RouterConstructorOptions<TRouteTree>); | ||
constructor(options?: RouterConstructorOptions<TRouteTree, TDehydrated>); | ||
reset: () => void; | ||
mount: () => () => void; | ||
update: (opts?: RouterOptions<TRouteTree>) => this; | ||
buildNext: (opts: BuildNextOptions) => ParsedLocation<{}, LocationState>; | ||
hydrate: (__do_not_use_server_ctx?: any) => Promise<void>; | ||
update: (opts?: RouterOptions<any, any>) => this; | ||
buildNext: (opts: BuildNextOptions) => ParsedLocation; | ||
cancelMatches: () => void; | ||
@@ -275,4 +281,2 @@ safeLoad: (opts?: { | ||
buildLink: <TFrom extends ValidFromPath<TRoutesInfo> = "/", TTo extends string = "">({ from, to, search, params, hash, target, replace, activeOptions, preload, preloadDelay: userPreloadDelay, disabled, }: LinkOptions<TRoutesInfo, TFrom, TTo>) => LinkInfo; | ||
dehydrate: () => DehydratedRouter; | ||
hydrate: (dehydratedRouter: DehydratedRouter) => void; | ||
} | ||
@@ -286,3 +290,84 @@ type AnyRedirect = Redirect<any, any, any>; | ||
interface RouteMatchStore<TRoutesInfo extends AnyRoutesInfo = DefaultRoutesInfo, TRoute extends AnyRoute = Route> { | ||
type ReactNode = any; | ||
type SyncRouteComponent<TProps = {}> = (props: TProps) => ReactNode; | ||
type RouteComponent<TProps = {}> = SyncRouteComponent<TProps> & { | ||
preload?: () => Promise<void>; | ||
}; | ||
declare function lazy(importer: () => Promise<{ | ||
default: SyncRouteComponent; | ||
}>): RouteComponent; | ||
type LinkPropsOptions<TFrom extends RegisteredRoutesInfo['routePaths'] = '/', TTo extends string = ''> = LinkOptions<RegisteredRoutesInfo, TFrom, TTo> & { | ||
activeProps?: React$1.AnchorHTMLAttributes<HTMLAnchorElement> | (() => React$1.AnchorHTMLAttributes<HTMLAnchorElement>); | ||
inactiveProps?: React$1.AnchorHTMLAttributes<HTMLAnchorElement> | (() => React$1.AnchorHTMLAttributes<HTMLAnchorElement>); | ||
}; | ||
type MakeUseMatchRouteOptions<TFrom extends RegisteredRoutesInfo['routePaths'] = '/', TTo extends string = ''> = ToOptions<RegisteredRoutesInfo, TFrom, TTo> & MatchRouteOptions; | ||
type MakeMatchRouteOptions<TFrom extends RegisteredRoutesInfo['routePaths'] = '/', TTo extends string = ''> = ToOptions<RegisteredRoutesInfo, TFrom, TTo> & MatchRouteOptions & { | ||
children?: ReactNode | ((params: RouteByPath<RegisteredRoutesInfo, ResolveRelativePath<TFrom, NoInfer$1<TTo>>>['__types']['allParams']) => ReactNode); | ||
}; | ||
type MakeLinkPropsOptions<TFrom extends ValidFromPath<RegisteredRoutesInfo> = '/', TTo extends string = ''> = LinkPropsOptions<TFrom, TTo> & React$1.AnchorHTMLAttributes<HTMLAnchorElement>; | ||
type MakeLinkOptions<TFrom extends RegisteredRoutesInfo['routePaths'] = '/', TTo extends string = ''> = LinkPropsOptions<TFrom, TTo> & React$1.AnchorHTMLAttributes<HTMLAnchorElement> & Omit<React$1.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & { | ||
children?: ReactNode | ((state: { | ||
isActive: boolean; | ||
}) => ReactNode); | ||
}; | ||
type PromptProps = { | ||
message: string; | ||
condition?: boolean | any; | ||
children?: ReactNode; | ||
}; | ||
declare function useLinkProps<TFrom extends ValidFromPath<RegisteredRoutesInfo> = '/', TTo extends string = ''>(options: MakeLinkPropsOptions<TFrom, TTo>): React$1.AnchorHTMLAttributes<HTMLAnchorElement>; | ||
interface LinkFn<TDefaultFrom extends RegisteredRoutesInfo['routePaths'] = '/', TDefaultTo extends string = ''> { | ||
<TFrom extends RegisteredRoutesInfo['routePaths'] = TDefaultFrom, TTo extends string = TDefaultTo>(props: MakeLinkOptions<TFrom, TTo> & React$1.RefAttributes<HTMLAnchorElement>): ReactNode; | ||
} | ||
declare const Link: LinkFn; | ||
declare function Navigate<TFrom extends RegisteredRoutesInfo['routePaths'] = '/', TTo extends string = ''>(props: NavigateOptions<RegisteredRoutesInfo, TFrom, TTo>): null; | ||
type MatchesContextValue = AnyRouteMatch[]; | ||
declare const matchesContext: React$1.Context<MatchesContextValue>; | ||
declare const routerContext: React$1.Context<{ | ||
router: RegisteredRouter; | ||
}>; | ||
type MatchesProviderProps = { | ||
value: MatchesContextValue; | ||
children: ReactNode; | ||
}; | ||
type RouterProps<TRouteConfig extends AnyRoute = AnyRoute, TRoutesInfo extends AnyRoutesInfo = DefaultRoutesInfo, TDehydrated extends Record<string, any> = Record<string, any>> = RouterOptions<TRouteConfig, TDehydrated> & { | ||
router: Router<TRouteConfig, TRoutesInfo>; | ||
}; | ||
declare function RouterProvider<TRouteConfig extends AnyRoute = AnyRoute, TRoutesInfo extends AnyRoutesInfo = DefaultRoutesInfo, TDehydrated extends Record<string, any> = Record<string, any>>({ router, ...rest }: RouterProps<TRouteConfig, TRoutesInfo, TDehydrated>): JSX.Element; | ||
declare function useRouterContext(): RegisteredRouter; | ||
declare function useRouter<T = RouterState>(track?: (state: Router['__store']) => T): RegisteredRouter; | ||
declare function useMatches(): RouteMatch[]; | ||
declare function useMatch<TFrom extends keyof RegisteredRoutesInfo['routesById'], TStrict extends boolean = true, TRouteMatch = RouteMatch<RegisteredRoutesInfo, RegisteredRoutesInfo['routesById'][TFrom]>>(opts?: { | ||
from: TFrom; | ||
strict?: TStrict; | ||
track?: (match: TRouteMatch) => any; | ||
}): TStrict extends true ? TRouteMatch : TRouteMatch | undefined; | ||
type RouteFromIdOrRoute<T> = T extends RegisteredRoutesInfo['routeUnion'] ? T : T extends keyof RegisteredRoutesInfo['routesById'] ? RegisteredRoutesInfo['routesById'][T] : T extends string ? keyof RegisteredRoutesInfo['routesById'] : never; | ||
declare function useLoader<TFrom extends keyof RegisteredRoutesInfo['routesById'], TStrict extends boolean = true, TLoader = RegisteredRoutesInfo['routesById'][TFrom]['__types']['loader'], TSelected = TLoader>(opts?: { | ||
from: TFrom; | ||
strict?: TStrict; | ||
track?: (search: TLoader) => TSelected; | ||
}): TStrict extends true ? TSelected : TSelected | undefined; | ||
declare function useSearch<TFrom extends keyof RegisteredRoutesInfo['routesById'], TStrict extends boolean = true, TSearch = RegisteredRoutesInfo['routesById'][TFrom]['__types']['fullSearchSchema'], TSelected = TSearch>(opts?: { | ||
from: TFrom; | ||
strict?: TStrict; | ||
track?: (search: TSearch) => TSelected; | ||
}): TStrict extends true ? TSelected : TSelected | undefined; | ||
declare function useParams<TFrom extends keyof RegisteredRoutesInfo['routesById'] = '/', TDefaultSelected = RegisteredRoutesInfo['allParams'] & RegisteredRoutesInfo['routesById'][TFrom]['__types']['allParams'], TSelected = TDefaultSelected>(opts?: { | ||
from: TFrom; | ||
track?: (search: TDefaultSelected) => TSelected; | ||
}): TSelected; | ||
declare function useNavigate<TDefaultFrom extends keyof RegisteredRoutesInfo['routesById'] = '/'>(defaultOpts?: { | ||
from?: TDefaultFrom; | ||
}): <TFrom extends string = TDefaultFrom, TTo extends string = "">(opts?: MakeLinkOptions<TFrom, TTo> | undefined) => Promise<void>; | ||
declare function useMatchRoute(): <TFrom extends ValidFromPath<AnyRoutesInfo> = "/", TTo extends string = "">(opts: MakeUseMatchRouteOptions<TFrom, TTo>) => any; | ||
declare function MatchRoute<TFrom extends ValidFromPath<RegisteredRoutesInfo> = '/', TTo extends string = ''>(props: MakeMatchRouteOptions<TFrom, TTo>): any; | ||
declare function Outlet(): JSX.Element | null; | ||
declare function ErrorComponent({ error }: { | ||
error: any; | ||
}): JSX.Element; | ||
declare function useBlocker(message: string, condition?: boolean | any): void; | ||
declare function Block({ message, condition, children }: PromptProps): any; | ||
interface RouteMatchState<TRoutesInfo extends AnyRoutesInfo = DefaultRoutesInfo, TRoute extends AnyRoute = Route> { | ||
routeSearch: TRoute['__types']['searchSchema']; | ||
@@ -293,5 +378,6 @@ search: TRoutesInfo['fullSearchSchema'] & TRoute['__types']['fullSearchSchema']; | ||
updatedAt: number; | ||
loader: TRoute['__types']['loader']; | ||
} | ||
interface PendingRouteMatchInfo { | ||
state: RouteMatchStore<any, any>; | ||
state: RouteMatchState<any, any>; | ||
routeContext: {}; | ||
@@ -306,4 +392,4 @@ context: {}; | ||
router: Router<TRoutesInfo['routeTree'], TRoutesInfo>; | ||
__store: Store<RouteMatchStore<TRoutesInfo, TRoute>>; | ||
state: RouteMatchStore<TRoutesInfo, TRoute>; | ||
__store: Store<RouteMatchState<TRoutesInfo, TRoute>>; | ||
state: RouteMatchState<TRoutesInfo, TRoute>; | ||
id: string; | ||
@@ -313,6 +399,16 @@ pathname: string; | ||
routeContext?: TRoute['__types']['routeContext']; | ||
context?: TRoute['__types']['context']; | ||
component?: GetFrameworkGeneric<'Component'>; | ||
errorComponent?: GetFrameworkGeneric<'ErrorComponent'>; | ||
pendingComponent?: GetFrameworkGeneric<'Component'>; | ||
context: TRoute['__types']['context']; | ||
component?: RouteComponent<{ | ||
useLoader: TRoute['useLoader']; | ||
useMatch: TRoute['useMatch']; | ||
useContext: TRoute['useContext']; | ||
useSearch: TRoute['useSearch']; | ||
}>; | ||
errorComponent?: RouteComponent<{ | ||
error: Error; | ||
info: { | ||
componentStack: string; | ||
}; | ||
}>; | ||
pendingComponent?: RouteComponent; | ||
abortController: AbortController; | ||
@@ -355,4 +451,2 @@ parentMatch?: RouteMatch; | ||
type RouteOptionsBaseIntersection<TCustomId, TPath> = UnionToIntersection<RouteOptionsBase<TCustomId, TPath>>; | ||
interface FrameworkRouteOptions { | ||
} | ||
type MetaOptions = keyof PickRequired<RouteMeta> extends never ? { | ||
@@ -378,3 +472,15 @@ meta?: RouteMeta; | ||
}; | ||
type RouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TParentSearchSchema extends {} = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParentParams extends AnyPathParams = {}, TParams = Record<ParsePathParams<TPath>, string>, TAllParams = TParams, TParentContext extends AnyContext = AnyContext, TAllParentContext extends AnyContext = AnyContext, TRouteContext extends RouteContext = RouteContext, TContext extends AnyContext = TRouteContext> = RouteOptionsBase<TCustomId, TPath> & FrameworkRouteOptions & { | ||
type RouteProps<TParentRoute extends AnyRoute, TPath extends string, TFullPath extends ResolveFullPath<TParentRoute, TPath, RoutePrefix<TParentRoute['fullPath'], TPath>>, TCustomId extends string, TId extends ResolveId<TParentRoute, TCustomId, TPath>, TLoader, TSearchSchema extends AnySearchSchema, TFullSearchSchema extends AnySearchSchema, TAllParams, TParentContext, TAllParentContext extends IsAny<TParentRoute['__types']['allParams'], TParentContext, TParentRoute['__types']['allParams'] & TParentContext>, TRouteContext, TContext, TRouterContext extends AnyContext> = { | ||
useMatch: () => RouteMatch<AnyRoutesInfo, Route<TParentRoute, TPath, TFullPath, TCustomId, TId, TLoader, TSearchSchema, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext, TContext, TRouterContext, any, any>>; | ||
useLoader: () => TLoader; | ||
useSearch: <TStrict extends boolean = true, TSearch = TFullSearchSchema, TSelected = TSearch>(opts?: { | ||
strict?: TStrict; | ||
track?: (search: TSearch) => TSelected; | ||
}) => TStrict extends true ? TSelected : TSelected | undefined; | ||
useParams: <TDefaultSelected = TAllParams, TSelected = TDefaultSelected>(opts?: { | ||
track?: (search: TDefaultSelected) => TSelected; | ||
}) => TSelected; | ||
useContext: () => TContext; | ||
}; | ||
type RouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends {} = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParentParams extends AnyPathParams = {}, TParams = Record<ParsePathParams<TPath>, string>, TAllParams = TParams, TParentContext extends AnyContext = AnyContext, TAllParentContext extends IsAny<TParentRoute['__types']['allParams'], TParentContext, TParentRoute['__types']['allParams'] & TParentContext> = IsAny<TParentRoute['__types']['allParams'], TParentContext, TParentRoute['__types']['allParams'] & TParentContext>, TRouteContext extends RouteContext = RouteContext, TContext extends MergeFromParent<TAllParentContext, TRouteContext> = MergeFromParent<TAllParentContext, TRouteContext>> = RouteOptionsBase<TCustomId, TPath> & { | ||
getParentRoute: () => TParentRoute; | ||
@@ -384,5 +490,11 @@ caseSensitive?: boolean; | ||
postSearchFilters?: SearchFilter<TFullSearchSchema>[]; | ||
component?: GetFrameworkGeneric<'Component'>; | ||
errorComponent?: GetFrameworkGeneric<'ErrorComponent'>; | ||
pendingComponent?: GetFrameworkGeneric<'Component'>; | ||
component?: RouteComponent<RouteProps<TParentRoute, TPath, ResolveFullPath<TParentRoute, TPath>, TCustomId, ResolveId<TParentRoute, TCustomId, TPath>, TLoader, TSearchSchema, TFullSearchSchema, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext, NoInfer<TRouteContext>>>; | ||
errorComponent?: RouteComponent<{ | ||
error: Error; | ||
info: { | ||
componentStack: string; | ||
}; | ||
}>; | ||
pendingComponent?: RouteComponent<RouteProps<TParentRoute, TPath, ResolveFullPath<TParentRoute, TPath>, TCustomId, ResolveId<TParentRoute, TCustomId, TPath>, TLoader, TSearchSchema, TFullSearchSchema, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext, NoInfer<TRouteContext>>>; | ||
wrapInSuspense?: boolean; | ||
beforeLoad?: (opts: { | ||
@@ -395,3 +507,3 @@ router: AnyRouter; | ||
onValidateSearchError?: (err: any) => void; | ||
onLoad?: OnLoadFn<TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TContext>; | ||
loader?: OnLoadFn<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TContext>; | ||
onLoadError?: (err: any) => void; | ||
@@ -411,3 +523,3 @@ onError?: (err: any) => void; | ||
} & MetaOptions & ContextOptions<TParentRoute, TAllParams, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext> & ({ | ||
parseParams?: (rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>) => TParams extends Record<ParsePathParams<TPath>, any> ? TParams : 'parseParams must return an ojbect'; | ||
parseParams?: (rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>) => TParams extends Record<ParsePathParams<TPath>, any> ? TParams : 'parseParams must return an object'; | ||
stringifyParams?: (params: NoInfer<TParams>) => Record<ParsePathParams<TPath>, string>; | ||
@@ -432,3 +544,3 @@ } | { | ||
}; | ||
type OnLoadFn<TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = {}, TAllParams = {}, TContext extends AnyContext = AnyContext, TAllContext extends AnyContext = AnyContext> = (loaderContext: LoaderContext<TSearchSchema, TFullSearchSchema, TAllParams, TContext, TAllContext>) => Promise<any> | void; | ||
type OnLoadFn<TLoader = unknown, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = {}, TAllParams = {}, TContext extends AnyContext = AnyContext, TAllContext extends AnyContext = AnyContext> = (loaderContext: LoaderContext<TSearchSchema, TFullSearchSchema, TAllParams, TContext, TAllContext>) => Promise<TLoader> | TLoader; | ||
interface LoaderContext<TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = {}, TAllParams = {}, TContext extends AnyContext = AnyContext, TAllContext extends AnyContext = AnyContext> { | ||
@@ -459,6 +571,6 @@ params: TAllParams; | ||
type ResolveFullSearchSchema<TParentRoute, TSearchSchema> = InferFullSearchSchema<TParentRoute> & TSearchSchema; | ||
interface AnyRoute extends Route<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any> { | ||
interface AnyRoute extends Route<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any> { | ||
} | ||
type MergeFromParent<T, U> = IsAny<T, U, T & U>; | ||
declare class Route<TParentRoute extends AnyRoute = AnyRoute, TPath extends string = string, TFullPath extends ResolveFullPath<TParentRoute, TPath> = ResolveFullPath<TParentRoute, TPath>, TCustomId extends string = string, TId extends ResolveId<TParentRoute, TCustomId, TPath> = ResolveId<TParentRoute, TCustomId, TPath>, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = ResolveFullSearchSchema<TParentRoute, TSearchSchema>, TParams extends Record<ParsePathParams<TPath>, any> = Record<ParsePathParams<TPath>, string>, TAllParams extends MergeFromParent<TParentRoute['__types']['allParams'], TParams> = MergeFromParent<TParentRoute['__types']['allParams'], TParams>, TParentContext extends TParentRoute['__types']['routeContext'] = TParentRoute['__types']['routeContext'], TAllParentContext extends TParentRoute['__types']['context'] = TParentRoute['__types']['context'], TRouteContext extends RouteContext = RouteContext, TContext extends MergeFromParent<TParentRoute['__types']['context'], TRouteContext> = MergeFromParent<TParentRoute['__types']['context'], TRouteContext>, TRouterContext extends AnyContext = AnyContext, TChildren extends unknown = unknown, TRoutesInfo extends DefaultRoutesInfo = DefaultRoutesInfo> { | ||
declare class Route<TParentRoute extends AnyRoute = AnyRoute, TPath extends string = string, TFullPath extends ResolveFullPath<TParentRoute, TPath> = ResolveFullPath<TParentRoute, TPath>, TCustomId extends string = string, TId extends ResolveId<TParentRoute, TCustomId, TPath> = ResolveId<TParentRoute, TCustomId, TPath>, TLoader = unknown, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = ResolveFullSearchSchema<TParentRoute, TSearchSchema>, TParams extends Record<ParsePathParams<TPath>, any> = Record<ParsePathParams<TPath>, string>, TAllParams extends MergeFromParent<TParentRoute['__types']['allParams'], TParams> = MergeFromParent<TParentRoute['__types']['allParams'], TParams>, TParentContext extends TParentRoute['__types']['routeContext'] = TParentRoute['__types']['routeContext'], TAllParentContext extends TParentRoute['__types']['context'] = TParentRoute['__types']['context'], TRouteContext extends RouteContext = RouteContext, TContext extends MergeFromParent<TParentRoute['__types']['context'], TRouteContext> = MergeFromParent<TParentRoute['__types']['context'], TRouteContext>, TRouterContext extends AnyContext = AnyContext, TChildren extends unknown = unknown, TRoutesInfo extends DefaultRoutesInfo = DefaultRoutesInfo> { | ||
__types: { | ||
@@ -470,2 +582,3 @@ parentRoute: TParentRoute; | ||
id: TId; | ||
loader: TLoader; | ||
searchSchema: TSearchSchema; | ||
@@ -484,3 +597,3 @@ fullSearchSchema: TFullSearchSchema; | ||
isRoot: TParentRoute extends Route<any> ? true : false; | ||
options: RouteOptions<TParentRoute, TCustomId, TPath, InferFullSearchSchema<TParentRoute>, TSearchSchema, InferFullSearchSchema<TParentRoute> & TSearchSchema, TParentRoute['__types']['allParams'], TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext>; | ||
options: RouteOptions<TParentRoute, TCustomId, TPath, TLoader, InferFullSearchSchema<TParentRoute>, TSearchSchema, InferFullSearchSchema<TParentRoute> & TSearchSchema, TParentRoute['__types']['allParams'], TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext>; | ||
parentRoute: TParentRoute; | ||
@@ -493,3 +606,3 @@ id: TId; | ||
router?: Router<TRoutesInfo['routeTree'], TRoutesInfo>; | ||
constructor(options: RouteOptions<TParentRoute, TCustomId, TPath, InferFullSearchSchema<TParentRoute>, TSearchSchema, TFullSearchSchema, TParentRoute['__types']['allParams'], TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext>); | ||
constructor(options: RouteOptions<TParentRoute, TCustomId, TPath, TLoader, InferFullSearchSchema<TParentRoute>, TSearchSchema, TFullSearchSchema, TParentRoute['__types']['allParams'], TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext>); | ||
init: (opts: { | ||
@@ -499,8 +612,24 @@ originalIndex: number; | ||
}) => void; | ||
addChildren: <TNewChildren extends AnyRoute[]>(children: TNewChildren) => Route<TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext, TRouterContext, TNewChildren, TRoutesInfo>; | ||
addChildren: <TNewChildren extends AnyRoute[]>(children: TNewChildren) => Route<TParentRoute, TPath, TFullPath, TCustomId, TId, TLoader, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TContext, TRouterContext, TNewChildren, TRoutesInfo>; | ||
useMatch: <TStrict extends boolean = true, TSelected = TContext>(opts?: { | ||
strict?: TStrict | undefined; | ||
track?: ((search: TContext) => TSelected) | undefined; | ||
} | undefined) => TStrict extends true ? TSelected : TSelected | undefined; | ||
useLoader: <TStrict extends boolean = true, TSelected = TLoader>(opts?: { | ||
strict?: TStrict | undefined; | ||
track?: ((search: TLoader) => TSelected) | undefined; | ||
} | undefined) => TStrict extends true ? TSelected : TSelected | undefined; | ||
useContext: <TStrict extends boolean = true, TSelected = TContext>(opts?: { | ||
strict?: TStrict | undefined; | ||
track?: ((search: TContext) => TSelected) | undefined; | ||
} | undefined) => TStrict extends true ? TSelected : TSelected | undefined; | ||
useSearch: <TStrict extends boolean = true, TSelected = TFullSearchSchema>(opts?: { | ||
strict?: TStrict | undefined; | ||
track?: ((search: TFullSearchSchema) => TSelected) | undefined; | ||
} | undefined) => TStrict extends true ? TSelected : TSelected | undefined; | ||
} | ||
type AnyRootRoute = RootRoute<any, any, any>; | ||
declare class RootRoute<TSearchSchema extends AnySearchSchema = {}, TContext extends RouteContext = RouteContext, TRouterContext extends RouterContext = RouterContext> extends Route<any, '/', '/', string, RootRouteId, TSearchSchema, TSearchSchema, {}, {}, TRouterContext, TRouterContext, TContext, MergeFromParent<TRouterContext, TContext>, TRouterContext> { | ||
constructor(options?: Omit<RouteOptions<AnyRoute, RootRouteId, '', {}, TSearchSchema, NoInfer<TSearchSchema>, {}, TRouterContext, TRouterContext, TContext, NoInfer<TContext>>, 'path' | 'id' | 'getParentRoute' | 'caseSensitive' | 'parseParams' | 'stringifyParams'>); | ||
static withRouterContext: <TRouterContext_1 extends RouterContext>() => <TSearchSchema_1 extends AnySearchSchema = {}, TContext_1 extends RouterContext = RouterContext>(options?: Omit<RouteOptions<AnyRoute, "__root__", "", {}, TSearchSchema_1, NoInfer<TSearchSchema_1>, {}, TRouterContext_1, TRouterContext_1, TContext_1, TRouterContext_1 & TContext_1, RouteContext, RouteContext>, "caseSensitive" | "id" | "path" | "getParentRoute"> | undefined) => RootRoute<TSearchSchema_1, TContext_1, TRouterContext_1>; | ||
type AnyRootRoute = RootRoute<any, any, any, any>; | ||
declare class RootRoute<TLoader = unknown, TSearchSchema extends AnySearchSchema = {}, TContext extends RouteContext = RouteContext, TRouterContext extends {} = {}> extends Route<any, '/', '/', string, RootRouteId, TLoader, TSearchSchema, TSearchSchema, {}, {}, TRouterContext, TRouterContext, MergeFromParent<TRouterContext, TContext>, MergeFromParent<TRouterContext, TContext>, TRouterContext, any, any> { | ||
constructor(options?: Omit<RouteOptions<AnyRoute, RootRouteId, '', TLoader, {}, TSearchSchema, NoInfer<TSearchSchema>, {}, TRouterContext, TRouterContext, TContext, NoInfer<TContext>>, 'path' | 'id' | 'getParentRoute' | 'caseSensitive' | 'parseParams' | 'stringifyParams'>); | ||
static withRouterContext: <TRouterContext_1 extends {}>() => <TLoader_1 = unknown, TSearchSchema_1 extends AnySearchSchema = {}, TContext_1 extends {} = {}>(options?: Omit<RouteOptions<AnyRoute, "__root__", "", TLoader_1, {}, TSearchSchema_1, NoInfer<TSearchSchema_1>, {}, TRouterContext_1, TRouterContext_1, TContext_1, TRouterContext_1 & TContext_1, RouteContext, IsAny<TRouterContext_1 & TContext_1, RouteContext, TRouterContext_1 & TContext_1 & RouteContext>>, "caseSensitive" | "id" | "path" | "getParentRoute"> | undefined) => RootRoute<TLoader_1, TSearchSchema_1, TContext_1, TRouterContext_1>; | ||
} | ||
@@ -514,3 +643,3 @@ type ResolveFullPath<TParentRoute extends AnyRoute, TPath extends string, TPrefixed extends RoutePrefix<TParentRoute['fullPath'], TPath> = RoutePrefix<TParentRoute['fullPath'], TPath>> = TPrefixed extends RootRouteId ? '/' : TrimPathRight<`${TPrefixed}`>; | ||
interface AnyRoutesInfo { | ||
routeTree: AnyRootRoute; | ||
routeTree: AnyRoute; | ||
routeUnion: AnyRoute; | ||
@@ -526,3 +655,3 @@ routesById: Record<string, AnyRoute>; | ||
interface DefaultRoutesInfo { | ||
routeTree: RootRoute; | ||
routeTree: AnyRoute; | ||
routeUnion: AnyRoute; | ||
@@ -559,2 +688,3 @@ routesById: Record<string, Route>; | ||
TRouteUnion['__types']['id'], // TId, | ||
TRouteUnion['__types']['loader'], // TId, | ||
// TId, | ||
@@ -580,3 +710,3 @@ MergeUnion<TRouteUnion['__types']['searchSchema']> & {}, // TSearchSchema, | ||
type ParseRoute<TRouteTree> = TRouteTree extends AnyRoute ? TRouteTree | ParseRouteChildren<TRouteTree> : never; | ||
type ParseRouteChildren<TRouteTree> = TRouteTree extends Route<any, any, any, any, any, any, any, any, any, any, any, any, any, any, infer TChildren, any> ? unknown extends TChildren ? never : TChildren extends AnyRoute[] ? Values<{ | ||
type ParseRouteChildren<TRouteTree> = TRouteTree extends Route<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, infer TChildren, any> ? unknown extends TChildren ? never : TChildren extends AnyRoute[] ? Values<{ | ||
[TId in TChildren[number]['id']]: ParseRouteChild<TChildren[number], TId>; | ||
@@ -699,2 +829,2 @@ }> : never : never; | ||
export { ActiveOptions, AnyContext, AnyPathParams, AnyRedirect, AnyRootRoute, AnyRoute, AnyRouteMatch, AnyRouter, AnyRoutesInfo, AnySearchSchema, BuildNextOptions, CheckId, CheckIdError, CheckPath, CheckPathError, CheckRelativePath, ContextOptions, DeepAwaited, DefaultRoutesInfo, DefinedPathParamWarning, DehydratedRouter, DehydratedRouterState, Expand, FilterRoutesFn, FrameworkGenerics, FrameworkRouteOptions, FromLocation, GetFrameworkGeneric, InferFullSearchSchema, IsAny, IsAnyBoolean, IsKnown, LinkInfo, LinkOptions, ListenerFn, LoaderContext, LocationState, MatchCache, MatchCacheEntry, MatchLocation, MatchRouteOptions, MergeUnion, MetaOptions, NavigateOptions, NoInfer, OnLoadFn, ParentParams, ParsePathParams, ParseRoute, ParseRouteChild, ParseRouteChildren, ParsedLocation, ParsedPath, PathParamMask, PathParamOptions, PendingRouteMatchInfo, PickAsPartial, PickAsRequired, PickExclude, PickExtra, PickExtract, PickRequired, PickUnsafe, Redirect, Register, RegisteredRouter, RegisteredRoutesInfo, RelativeToPathAutoComplete, ResolveFullSearchSchema, ResolveRelativePath, RootRoute, RootRouteId, Route, RouteById, RouteByPath, RouteContext, RouteMatch, RouteMatchStore, RouteMeta, RouteOptions, RouteOptionsBase, RouteOptionsBaseIntersection, Router, RouterConstructorOptions, RouterContext, RouterHistory, RouterLocation, RouterOptions, RouterStore, RoutesById, RoutesInfo, RoutesInfoInner, SearchFilter, SearchParamOptions, SearchParser, SearchSchemaValidator, SearchSchemaValidatorFn, SearchSchemaValidatorObj, SearchSerializer, Segment, Split, Timeout, ToIdOption, ToOptions, ToPathOption, UnionToIntersection, UnloaderFn, Updater, ValidFromPath, ValueKeys, Values, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultFetchServerDataFn, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight }; | ||
export { ActiveOptions, AnyContext, AnyPathParams, AnyRedirect, AnyRootRoute, AnyRoute, AnyRouteMatch, AnyRouter, AnyRoutesInfo, AnySearchSchema, Block, BuildNextOptions, CheckId, CheckIdError, CheckPath, CheckPathError, CheckRelativePath, ContextOptions, DeepAwaited, DefaultRoutesInfo, DefinedPathParamWarning, DehydratedRouter, DehydratedRouterState, ErrorComponent, Expand, FilterRoutesFn, FromLocation, InferFullSearchSchema, IsAny, IsAnyBoolean, IsKnown, Link, LinkFn, LinkInfo, LinkOptions, LinkPropsOptions, ListenerFn, LoaderContext, LocationState, MakeLinkOptions, MakeLinkPropsOptions, MakeMatchRouteOptions, MakeUseMatchRouteOptions, MatchCache, MatchCacheEntry, MatchLocation, MatchRoute, MatchRouteOptions, MatchesProviderProps, MergeUnion, MetaOptions, Navigate, NavigateOptions, NoInfer, OnLoadFn, Outlet, ParentParams, ParsePathParams, ParseRoute, ParseRouteChild, ParseRouteChildren, ParsedLocation, ParsedPath, PathParamMask, PathParamOptions, PendingRouteMatchInfo, PickAsPartial, PickAsRequired, PickExclude, PickExtra, PickExtract, PickRequired, PickUnsafe, PromptProps, Redirect, Register, RegisteredRouter, RegisteredRoutesInfo, RelativeToPathAutoComplete, ResolveFullSearchSchema, ResolveRelativePath, RootRoute, RootRouteId, Route, RouteById, RouteByPath, RouteComponent, RouteContext, RouteFromIdOrRoute, RouteMatch, RouteMatchState, RouteMeta, RouteOptions, RouteOptionsBase, RouteOptionsBaseIntersection, RouteProps, Router, RouterConstructorOptions, RouterHistory, RouterLocation, RouterOptions, RouterProps, RouterProvider, RouterState, RoutesById, RoutesInfo, RoutesInfoInner, SearchFilter, SearchParamOptions, SearchParser, SearchSchemaValidator, SearchSchemaValidatorFn, SearchSchemaValidatorObj, SearchSerializer, Segment, Split, SyncRouteComponent, Timeout, ToIdOption, ToOptions, ToPathOption, UnionToIntersection, UnloaderFn, Updater, ValidFromPath, ValueKeys, Values, cleanPath, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultFetchServerDataFn, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, lazy, matchByPath, matchPathname, matchesContext, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, routerContext, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, useBlocker, useLinkProps, useLoader, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useRouter, useRouterContext, useSearch }; |
@@ -11,3 +11,3 @@ /** | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).RouterCore={})}(this,(function(t){"use strict";function e(t,e){if(!t)throw new Error("Invariant failed")}const a="popstate",s="beforeunload",r=t=>(t.preventDefault(),t.returnValue=""),o=()=>{removeEventListener(s,r,{capture:!0})};function n(t){let e=t.getLocation(),a=()=>{},n=new Set,i=[],h=[];const c=()=>{if(i.length)i[0]?.(c,(()=>{i=[],o()}));else{for(;h.length;)h.shift()?.();l()}},u=t=>{h.push(t),c()},l=()=>{e=t.getLocation(),n.forEach((t=>t()))};return{get location(){return e},listen:e=>(0===n.size&&(a=t.listener(l)),n.add(e),()=>{n.delete(e),0===n.size&&a()}),push:(e,a)=>{u((()=>{t.pushState(e,a)}))},replace:(e,a)=>{u((()=>{t.replaceState(e,a)}))},go:e=>{u((()=>{t.go(e)}))},back:()=>{u((()=>{t.back()}))},forward:()=>{u((()=>{t.forward()}))},createHref:e=>t.createHref(e),block:t=>(i.push(t),1===i.length&&addEventListener(s,r,{capture:!0}),()=>{i=i.filter((e=>e!==t)),i.length||o()})}}function i(t){const e=t?.getHref??(()=>`${window.location.pathname}${window.location.hash}${window.location.search}`),s=t?.createHref??(t=>t);return n({getLocation:()=>c(e(),history.state),listener:t=>(window.addEventListener(a,t),()=>{window.removeEventListener(a,t)}),pushState:(t,e)=>{window.history.pushState({...e,key:u()},"",s(t))},replaceState:(t,e)=>{window.history.replaceState({...e,key:u()},"",s(t))},back:()=>window.history.back(),forward:()=>window.history.forward(),go:t=>window.history.go(t),createHref:t=>s(t)})}function h(t={initialEntries:["/"]}){const e=t.initialEntries;let a=t.initialIndex??e.length-1,s={};return n({getLocation:()=>c(e[a],s),listener:()=>()=>{},pushState:(t,r)=>{s={...r,key:u()},e.push(t),a++},replaceState:(t,r)=>{s={...r,key:u()},e[a]=t},back:()=>{a--},forward:()=>{a=Math.min(a+1,e.length-1)},go:t=>window.history.go(t),createHref:t=>t})}function c(t,e){let a=t.indexOf("#"),s=t.indexOf("?");return{href:t,pathname:t.substring(0,a>0?s>0?Math.min(a,s):a:s>0?s:t.length),hash:a>-1?t.substring(a,s):"",search:s>-1?t.substring(s):"",state:e}}function u(){return(Math.random()+1).toString(36).substring(7)}function l(t){return t[t.length-1]}function p(t,e){return"function"==typeof t?t(e):t}function d(t,e){return e.reduce(((e,a)=>(e[a]=t[a],e)),{})}function f(t,e){if(t===e)return t;const a=e,s=Array.isArray(t)&&Array.isArray(a);if(s||m(t)&&m(a)){const e=s?t.length:Object.keys(t).length,r=s?a:Object.keys(a),o=r.length,n=s?[]:{};let i=0;for(let e=0;e<o;e++){const o=s?e:r[e];n[o]=f(t[o],a[o]),n[o]===t[o]&&i++}return e===o&&i===e?t:n}return a}function m(t){if(!g(t))return!1;const e=t.constructor;if(void 0===e)return!0;const a=e.prototype;return!!g(a)&&!!a.hasOwnProperty("isPrototypeOf")}function g(t){return"[object Object]"===Object.prototype.toString.call(t)}function y(t,e){return t===e||typeof t==typeof e&&(m(t)&&m(e)?!Object.keys(e).some((a=>!y(t[a],e[a]))):!(!Array.isArray(t)||!Array.isArray(e))&&(t.length===e.length&&t.every(((t,a)=>y(t,e[a])))))}function v(t){return w(t.filter(Boolean).join("/"))}function w(t){return t.replace(/\/{2,}/g,"/")}function _(t){return"/"===t?t:t.replace(/^\/{1,}/,"")}function S(t){return"/"===t?t:t.replace(/\/{1,}$/,"")}function b(t){return S(_(t))}function L(t,e,a){e=e.replace(new RegExp(`^${t}`),"/"),a=a.replace(new RegExp(`^${t}`),"/");let s=P(e);const r=P(a);r.forEach(((t,e)=>{if("/"===t.value)e?e===r.length-1&&s.push(t):s=[t];else if(".."===t.value)s.length>1&&"/"===l(s)?.value&&s.pop(),s.pop();else{if("."===t.value)return;s.push(t)}}));return w(v([t,...s.map((t=>t.value))]))}function P(t){if(!t)return[];const e=[];if("/"===(t=w(t)).slice(0,1)&&(t=t.substring(1),e.push({type:"pathname",value:"/"})),!t)return e;const a=t.split("/").filter(Boolean);return e.push(...a.map((t=>"$"===t||"*"===t?{type:"wildcard",value:t}:"$"===t.charAt(0)?{type:"param",value:t}:{type:"pathname",value:t}))),"/"===t.slice(-1)&&(t=t.substring(1),e.push({type:"pathname",value:"/"})),e}function R(t,e,a){return v(P(t).map((t=>["$","*"].includes(t.value)&&!a?"":"param"===t.type?e[t.value.substring(1)]??"":t.value)))}function x(t,e,a){const s=E(t,e,a);if(!a.to||s)return s??{}}function E(t,e,a){if(!e.startsWith(t))return;const s=P(e="/"!=t?e.substring(t.length):e),r=P(`${a.to??"$"}`);"/"===l(s)?.value&&s.pop();const o={};return(()=>{for(let t=0;t<Math.max(s.length,r.length);t++){const e=s[t],n=r[t],i=t===r.length-1,h=t===s.length-1;if(n){if("wildcard"===n.type)return!!e?.value&&(o["*"]=v(s.slice(t).map((t=>t.value))),!0);if("pathname"===n.type){if("/"===n.value&&!e?.value)return!0;if(e)if(a.caseSensitive){if(n.value!==e.value)return!1}else if(n.value.toLowerCase()!==e.value.toLowerCase())return!1}if(!e)return!1;if("param"===n.type){if("/"===e?.value)return!1;"$"!==e.value.charAt(0)&&(o[n.value.substring(1)]=e.value)}}if(i&&!h)return!!a.fuzzy}return!0})()?o:void 0}function M(t,e){var a,s,r,o="";for(a in t)if(void 0!==(r=t[a]))if(Array.isArray(r))for(s=0;s<r.length;s++)o&&(o+="&"),o+=encodeURIComponent(a)+"="+encodeURIComponent(r[s]);else o&&(o+="&"),o+=encodeURIComponent(a)+"="+encodeURIComponent(r);return(e||"")+o}function C(t){if(!t)return"";var e=decodeURIComponent(t);return"false"!==e&&("true"===e||("0"===e.charAt(0)?e:0*+e==0?+e:e))}function $(t){for(var e,a,s={},r=t.split("&");e=r.shift();)void 0!==s[a=(e=e.split("=")).shift()]?s[a]=[].concat(s[a],C(e.shift())):s[a]=C(e.shift());return s}const A="__root__";class I{constructor(t){this.options=t||{},this.isRoot=!t?.getParentRoute}init=t=>{this.originalIndex=t.originalIndex,this.router=t.router;const a=this.options,s=!a?.path&&!a?.id;this.parentRoute=this.options?.getParentRoute?.(),s?this.path=A:e(this.parentRoute);let r=s?A:a.path;r&&"/"!==r&&(r=b(r));const o=a?.id||r;let n=s?A:v([this.parentRoute.id===A?"":this.parentRoute.id,o]);r===A&&(r="/"),n!==A&&(n=v(["/",n]));const i=n===A?"/":S(v([this.parentRoute.fullPath,r]));this.path=r,this.id=n,this.fullPath=i};addChildren=t=>(this.children=t,this)}class k extends I{constructor(t){super(t)}static withRouterContext=()=>t=>new k(t)} | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("use-sync-external-store/shim/with-selector")):"function"==typeof define&&define.amd?define(["exports","react","use-sync-external-store/shim/with-selector"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).RouterCore={},t.React,t.withSelector)}(this,(function(t,e,r){"use strict";function o(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(r){if("default"!==r){var o=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,o.get?o:{enumerable:!0,get:function(){return t[r]}})}})),e.default=t,Object.freeze(e)}var a=o(e);function s(t,e){if(!t)throw new Error("Invariant failed")}function n(t,e){}const i="popstate",c="beforeunload",h=t=>(t.preventDefault(),t.returnValue=""),u=()=>{removeEventListener(c,h,{capture:!0})};function l(t){let e=t.getLocation(),r=()=>{},o=new Set,a=[],s=[];const n=()=>{if(a.length)a[0]?.(n,(()=>{a=[],u()}));else{for(;s.length;)s.shift()?.();l()}},i=t=>{s.push(t),n()},l=()=>{e=t.getLocation(),o.forEach((t=>t()))};return{get location(){return e},listen:e=>(0===o.size&&(r=t.listener(l)),o.add(e),()=>{o.delete(e),0===o.size&&r()}),push:(e,r)=>{i((()=>{t.pushState(e,r)}))},replace:(e,r)=>{i((()=>{t.replaceState(e,r)}))},go:e=>{i((()=>{t.go(e)}))},back:()=>{i((()=>{t.back()}))},forward:()=>{i((()=>{t.forward()}))},createHref:e=>t.createHref(e),block:t=>(a.push(t),1===a.length&&addEventListener(c,h,{capture:!0}),()=>{a=a.filter((e=>e!==t)),a.length||u()})}}function d(t){const e=t?.getHref??(()=>`${window.location.pathname}${window.location.hash}${window.location.search}`),r=t?.createHref??(t=>t);return l({getLocation:()=>f(e(),history.state),listener:t=>(window.addEventListener(i,t),()=>{window.removeEventListener(i,t)}),pushState:(t,e)=>{window.history.pushState({...e,key:m()},"",r(t))},replaceState:(t,e)=>{window.history.replaceState({...e,key:m()},"",r(t))},back:()=>window.history.back(),forward:()=>window.history.forward(),go:t=>window.history.go(t),createHref:t=>r(t)})}function p(t={initialEntries:["/"]}){const e=t.initialEntries;let r=t.initialIndex??e.length-1,o={};return l({getLocation:()=>f(e[r],o),listener:()=>()=>{},pushState:(t,a)=>{o={...a,key:m()},e.push(t),r++},replaceState:(t,a)=>{o={...a,key:m()},e[r]=t},back:()=>{r--},forward:()=>{r=Math.min(r+1,e.length-1)},go:t=>window.history.go(t),createHref:t=>t})}function f(t,e){let r=t.indexOf("#"),o=t.indexOf("?");return{href:t,pathname:t.substring(0,r>0?o>0?Math.min(r,o):r:o>0?o:t.length),hash:r>-1?t.substring(r,o):"",search:o>-1?t.substring(o):"",state:e}}function m(){return(Math.random()+1).toString(36).substring(7)}function y(t){return t[t.length-1]}function g(t,e){return"function"==typeof t?t(e):t}function v(t,e){if(t===e)return t;const r=e,o=Array.isArray(t)&&Array.isArray(r);if(o||w(t)&&w(r)){const e=o?t.length:Object.keys(t).length,a=o?r:Object.keys(r),s=a.length,n=o?[]:{};let i=0;for(let e=0;e<s;e++){const s=o?e:a[e];n[s]=v(t[s],r[s]),n[s]===t[s]&&i++}return e===s&&i===e?t:n}return r}function w(t){if(!_(t))return!1;const e=t.constructor;if(void 0===e)return!0;const r=e.prototype;return!!_(r)&&!!r.hasOwnProperty("isPrototypeOf")}function _(t){return"[object Object]"===Object.prototype.toString.call(t)}function b(t,e){return t===e||typeof t==typeof e&&(w(t)&&w(e)?!Object.keys(e).some((r=>!b(t[r],e[r]))):!(!Array.isArray(t)||!Array.isArray(e))&&(t.length===e.length&&t.every(((t,r)=>b(t,e[r])))))}function S(t){return L(t.filter(Boolean).join("/"))}function L(t){return t.replace(/\/{2,}/g,"/")}function E(t){return"/"===t?t:t.replace(/^\/{1,}/,"")}function x(t){return"/"===t?t:t.replace(/\/{1,}$/,"")}function P(t){return x(E(t))}function C(t,e,r){e=e.replace(new RegExp(`^${t}`),"/"),r=r.replace(new RegExp(`^${t}`),"/");let o=R(e);const a=R(r);a.forEach(((t,e)=>{if("/"===t.value)e?e===a.length-1&&o.push(t):o=[t];else if(".."===t.value)o.length>1&&"/"===y(o)?.value&&o.pop(),o.pop();else{if("."===t.value)return;o.push(t)}}));return L(S([t,...o.map((t=>t.value))]))}function R(t){if(!t)return[];const e=[];if("/"===(t=L(t)).slice(0,1)&&(t=t.substring(1),e.push({type:"pathname",value:"/"})),!t)return e;const r=t.split("/").filter(Boolean);return e.push(...r.map((t=>"$"===t||"*"===t?{type:"wildcard",value:t}:"$"===t.charAt(0)?{type:"param",value:t}:{type:"pathname",value:t}))),"/"===t.slice(-1)&&(t=t.substring(1),e.push({type:"pathname",value:"/"})),e}function M(t,e,r){return S(R(t).map((t=>["$","*"].includes(t.value)&&!r?"":"param"===t.type?e[t.value.substring(1)]??"":t.value)))}function k(t,e,r){const o=O(t,e,r);if(!r.to||o)return o??{}}function O(t,e,r){if(!e.startsWith(t))return;const o=R(e="/"!=t?e.substring(t.length):e),a=R(`${r.to??"$"}`);"/"===y(o)?.value&&o.pop();const s={};return(()=>{for(let t=0;t<Math.max(o.length,a.length);t++){const e=o[t],n=a[t],i=t===a.length-1,c=t===o.length-1;if(n){if("wildcard"===n.type)return!!e?.value&&(s["*"]=S(o.slice(t).map((t=>t.value))),!0);if("pathname"===n.type){if("/"===n.value&&!e?.value)return!0;if(e)if(r.caseSensitive){if(n.value!==e.value)return!1}else if(n.value.toLowerCase()!==e.value.toLowerCase())return!1}if(!e)return!1;if("param"===n.type){if("/"===e?.value)return!1;"$"!==e.value.charAt(0)&&(s[n.value.substring(1)]=e.value)}}if(i&&!c)return!!r.fuzzy}return!0})()?s:void 0}function j(t,e){var r,o,a,s="";for(r in t)if(void 0!==(a=t[r]))if(Array.isArray(a))for(o=0;o<a.length;o++)s&&(s+="&"),s+=encodeURIComponent(r)+"="+encodeURIComponent(a[o]);else s&&(s+="&"),s+=encodeURIComponent(r)+"="+encodeURIComponent(a);return(e||"")+s}function A(t){if(!t)return"";var e=decodeURIComponent(t);return"false"!==e&&("true"===e||("0"===e.charAt(0)?e:0*+e==0?+e:e))}function I(t){for(var e,r,o={},a=t.split("&");e=a.shift();)void 0!==o[r=(e=e.split("=")).shift()]?o[r]=[].concat(o[r],A(e.shift())):o[r]=A(e.shift());return o}function $(){return $=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=r[o])}return t},$.apply(this,arguments)} | ||
/** | ||
@@ -22,3 +22,13 @@ * store | ||
* @license MIT | ||
*/class D{listeners=new Set;batching=!1;queue=[];constructor(t,e){this.state=t,this.options=e}subscribe=t=>{this.listeners.add(t);const e=this.options?.onSubscribe?.(t,this);return()=>{this.listeners.delete(t),e?.()}};setState=t=>{const e=this.state;this.state=this.options?.updateFn?this.options.updateFn(e)(t):t(e),this.state!==e&&(this.options?.onUpdate?.(this.state,e),this.queue.push((()=>{this.listeners.forEach((t=>t(this.state,e)))})),this.#t())};#t=()=>{this.batching||(this.queue.forEach((t=>t())),this.queue=[])};batch=t=>{this.batching=!0,t(),this.batching=!1,this.#t()}}const T=j(JSON.parse),H=O(JSON.stringify);function j(t){return e=>{"?"===e.substring(0,1)&&(e=e.substring(1));let a=$(e);for(let e in a){const s=a[e];if("string"==typeof s)try{a[e]=t(s)}catch(t){}}return a}}function O(t){return e=>{(e={...e})&&Object.keys(e).forEach((a=>{const s=e[a];if(void 0===s||void 0===s)delete e[a];else if(s&&"object"==typeof s&&null!==s)try{e[a]=t(s)}catch(t){}}));const a=M(e).toString();return a?`?${a}`:""}}const N=async({router:t,routeMatch:e})=>{const a=t.buildNext({to:".",search:t=>({...t??{},__data:{matchId:e.id}})}),s=await fetch(a.href,{method:"GET",signal:e.abortController.signal});if(s.ok)return s.json();throw new Error("Failed to fetch match data")};const U="undefined"==typeof window||!window.document.createElement;function B(){return{status:"idle",latestLocation:null,currentLocation:null,currentMatches:[],lastUpdated:Date.now()}}function F(t){return!!t?.isRedirect}const q=["component","errorComponent","pendingComponent"];class z{abortController=new AbortController;constructor(t,e,a){Object.assign(this,{route:e,router:t,id:a.id,pathname:a.pathname,params:a.params,__store:new D({updatedAt:0,routeSearch:{},search:{},status:"idle"},{onUpdate:t=>{this.state=t}})}),this.state=this.__store.state,q.map((async t=>{const e=this.route.options[t];"function"!=typeof this[t]&&(this[t]=e)})),"idle"!==this.state.status||this.#e()||this.__store.setState((t=>({...t,status:"success"})))}#e=()=>!(!this.route.options.onLoad&&!q.some((t=>this.route.options[t]?.preload)));__commit=()=>{const{routeSearch:t,search:e,context:a,routeContext:s}=this.#a({location:this.router.state.currentLocation});this.context=a,this.routeContext=s,this.__store.setState((a=>({...a,routeSearch:f(a.routeSearch,t),search:f(a.search,e)})))};cancel=()=>{this.abortController?.abort()};#s=t=>{const e=this.parentMatch?this.parentMatch.#s(t):{search:t.location.search,routeSearch:t.location.search};try{const t=("object"==typeof this.route.options.validateSearch?this.route.options.validateSearch.parse:this.route.options.validateSearch)?.(e.search)??{};return{routeSearch:t,search:{...e.search,...t}}}catch(t){if(F(t))throw t;(this.route.options.onValidateSearchError??this.route.options.onError)?.(t);const e=new Error("Invalid search params found",{cause:t});throw e.code="INVALID_SEARCH_PARAMS",e}};#a=t=>{const{search:e,routeSearch:a}=this.#s(t);try{const t=this.route.options.getContext?.({parentContext:this.parentMatch?.routeContext??{},context:this.parentMatch?.context??this.router?.options.context??{},params:this.params,search:e})||{};return{routeSearch:a,search:e,context:{...this.parentMatch?.context??this.router?.options.context,...t},routeContext:t}}catch(t){throw this.route.options.onError?.(t),t}};__load=async t=>{let e;this.parentMatch=t.parentMatch;try{e=this.#a(t)}catch(e){return F(e)?void(t?.preload||this.router.navigate(e)):void this.__store.setState((t=>({...t,status:"error",error:e})))}const{routeSearch:a,search:s,context:r,routeContext:o}=e;if("pending"!==this.state.status)return this.__loadPromise=Promise.resolve().then((async()=>{const e=""+Date.now()+Math.random();this.#r=e;const n=()=>e!==this.#r?this.__loadPromise:void 0;let i;"idle"===this.state.status&&this.__store.setState((t=>({...t,status:"pending"})));const h=(async()=>{await Promise.all(q.map((async t=>{const e=this.route.options[t];this[t]?.preload&&(this[t]=await this.router.options.loadComponent(e))})))})(),c=Promise.resolve().then((()=>{if(this.route.options.onLoad)return this.route.options.onLoad({params:this.params,routeSearch:a,search:s,signal:this.abortController.signal,preload:!!t?.preload,routeContext:o,context:r})}));try{if(await Promise.all([h,c]),i=n())return await i;this.__store.setState((t=>({...t,error:void 0,status:"success",updatedAt:Date.now()})))}catch(e){if(F(e))return void(t?.preload||this.router.navigate(e));const a=this.route.options.onLoadError??this.route.options.onError;try{a?.(e)}catch(e){return F(e)?void(t?.preload||this.router.navigate(e)):void this.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}this.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}finally{delete this.__loadPromise}})),this.__loadPromise};#r=""}t.RootRoute=k,t.Route=I,t.RouteMatch=z,t.Router=class{#o;startedLoadingAt=Date.now();resolveNavigation=()=>{};constructor(t){this.options={defaultPreloadDelay:50,context:void 0,...t,stringifySearch:t?.stringifySearch??H,parseSearch:t?.parseSearch??T,fetchServerDataFn:t?.fetchServerDataFn??N},this.__store=new D(B(),{onUpdate:t=>{this.state=t}}),this.state=this.__store.state,this.basepath="",this.update(t),this.options.Router?.(this);const e=this.buildNext({hash:!0,fromCurrent:!0,search:!0,state:!0});this.state.latestLocation.href!==e.href&&this.#n({...e,replace:!0})}reset=()=>{this.__store.setState((t=>Object.assign(t,B())))};mount=()=>(U||this.state.currentMatches.length||this.safeLoad(),()=>{});update=t=>{if(Object.assign(this.options,t),!this.history||this.options.history&&this.options.history!==this.history){this.#o&&this.#o(),this.history=this.options.history??(U?h():i());const t=this.#i();this.__store.setState((e=>({...e,latestLocation:t,currentLocation:t}))),this.#o=this.history.listen((()=>{this.safeLoad({next:this.#i(this.state.latestLocation)})}))}const{basepath:e,routeTree:a}=this.options;return this.basepath=`/${b(e??"")??""}`,a&&(this.routesById={},this.routeTree=this.#h(a)),this};buildNext=t=>{const e=this.#c(t),a=this.matchRoutes(e.pathname);return this.#c({...t,__matches:a})};cancelMatches=()=>{[...this.state.currentMatches,...this.state.pendingMatches||[]].forEach((t=>{t.cancel()}))};safeLoad=t=>{this.load(t).catch((t=>{console.warn(t),e(!1)}))};load=async t=>{let e=Date.now();const a=e;let s;if(this.startedLoadingAt=a,this.cancelMatches(),this.__store.batch((()=>{t?.next&&this.__store.setState((e=>({...e,latestLocation:t.next}))),s=this.matchRoutes(this.state.latestLocation.pathname,{strictParseParams:!0}),this.__store.setState((t=>({...t,status:"pending",pendingMatches:s,pendingLocation:this.state.latestLocation})))})),await this.loadMatches(s,this.state.pendingLocation),this.startedLoadingAt!==a)return this.navigationPromise;const r=this.state.currentMatches,o=[],n=[];r.forEach((t=>{s.find((e=>e.id===t.id))?n.push(t):o.push(t)}));const i=s.filter((t=>!r.find((e=>e.id===t.id))));e=Date.now(),o.forEach((t=>{t.__onExit?.({params:t.params,search:t.state.routeSearch}),"error"===t.state.status&&this.__store.setState((t=>({...t,status:"idle",error:void 0})))})),n.forEach((t=>{t.route.options.onTransition?.({params:t.params,search:t.state.routeSearch})})),i.forEach((t=>{t.__onExit=t.route.options.onLoaded?.({params:t.params,search:t.state.search})}));const h=this.state.currentLocation;this.__store.setState((t=>({...t,status:"idle",currentLocation:this.state.latestLocation,currentMatches:s,pendingLocation:void 0,pendingMatches:void 0}))),s.forEach((t=>{t.__commit()})),h.href!==this.state.currentLocation.href&&this.options.onRouteChange?.(),this.resolveNavigation()};getRoute=t=>{const a=this.routesById[t];return e(a),a};loadRoute=async(t=this.state.latestLocation)=>{const e=this.buildNext(t),a=this.matchRoutes(e.pathname,{strictParseParams:!0});return await this.loadMatches(a,e),a};preloadRoute=async(t=this.state.latestLocation)=>{const e=this.buildNext(t),a=this.matchRoutes(e.pathname,{strictParseParams:!0});return await this.loadMatches(a,e,{preload:!0}),a};matchRoutes=(t,e)=>{const a=[];if(!this.routeTree)return a;const s=[...this.state.currentMatches,...this.state.pendingMatches??[]],r=async o=>{let n=l(a)?.params??{};const i=this.options.filterRoutes?.(o)??o;let h=[];const c=(a,s)=>(s.some((s=>{const r=s.children;if(!s.path&&r?.length)return c([...h,s],r);const o=!("/"===s.path&&!r?.length),i=x(this.basepath,t,{to:s.fullPath,fuzzy:o,caseSensitive:s.options.caseSensitive??this.options.caseSensitive});if(i){let t;try{t=s.options.parseParams?.(i)??i}catch(t){if(e?.strictParseParams)throw t}n={...n,...t}}return i&&(h=[...a,s]),!!h.length})),!!h.length);if(c([],i),!h.length)return;h.forEach((t=>{const e=R(t.path,n),r=R(t.id,n,!0),o=s.find((t=>t.id===r))||new z(this,t,{id:r,params:n,pathname:v([this.basepath,e])});a.push(o)}));const u=l(h).children;u?.length&&r(u)};return r([this.routeTree]),a};loadMatches=async(t,e,a)=>{let s;try{await Promise.all(t.map((async(t,e)=>{try{await(t.route.options.beforeLoad?.({router:this,match:t}))}catch(a){if(F(a))throw a;s=s??e;const r=t.route.options.onBeforeLoadError??t.route.options.onError;try{r?.(a)}catch(e){if(F(e))throw e;return void t.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}t.__store.setState((t=>({...t,error:a,status:"error",updatedAt:Date.now()})))}})))}catch(t){if(F(t))return void(a?.preload||this.navigate(t));throw t}const r=t.slice(0,s),o=r.map((async(t,s)=>{const o=r[s-1];t.__load({preload:a?.preload,location:e,parentMatch:o}),await t.__loadPromise,o&&await o.__loadPromise}));await Promise.all(o)};reload=()=>{this.navigate({fromCurrent:!0,replace:!0,search:!0})};resolvePath=(t,e)=>L(this.basepath,t,w(e));navigate=async({from:t,to:a="",search:s,hash:r,replace:o,params:n})=>{const i=String(a),h=void 0===t?t:String(t);let c;try{new URL(`${i}`),c=!0}catch(t){}return e(!c),this.#n({from:h,to:i,search:s,hash:r,replace:o,params:n})};matchRoute=(t,e)=>{t={...t,to:t.to?this.resolvePath(t.from??"",t.to):void 0};const a=this.buildNext(t),s=e?.pending?this.state.pendingLocation:this.state.currentLocation;if(!s)return!1;const r=x(this.basepath,s.pathname,{...e,to:a.pathname});return!!r&&(e?.includeSearch??1?!!y(s.search,a.search)&&r:r)};buildLink=({from:t,to:e=".",search:a,params:s,hash:r,target:o,replace:n,activeOptions:i,preload:h,preloadDelay:c,disabled:u})=>{try{return new URL(`${e}`),{type:"external",href:e}}catch(t){}const l={from:t,to:e,search:a,params:s,hash:r,replace:n},p=this.buildNext(l);h=h??this.options.defaultPreload;const d=c??this.options.defaultPreloadDelay??0,f=this.state.currentLocation.pathname.split("/"),m=p.pathname.split("/").every(((t,e)=>t===f[e])),g=i?.exact?this.state.currentLocation.pathname===p.pathname:m,v=!i?.includeHash||this.state.currentLocation.hash===p.hash,w=!(i?.includeSearch??1)||y(this.state.currentLocation.search,p.search);return{type:"internal",next:p,handleFocus:t=>{h&&this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))},handleClick:t=>{u||function(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}(t)||t.defaultPrevented||o&&"_self"!==o||0!==t.button||(t.preventDefault(),this.#n(l))},handleEnter:t=>{const e=t.target||{};if(h){if(e.preloadTimeout)return;e.preloadTimeout=setTimeout((()=>{e.preloadTimeout=null,this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))}),d)}},handleLeave:t=>{const e=t.target||{};e.preloadTimeout&&(clearTimeout(e.preloadTimeout),e.preloadTimeout=null)},handleTouchStart:t=>{this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))},isActive:g&&v&&w,disabled:u}};dehydrate=()=>({state:{...d(this.state,["latestLocation","currentLocation","status","lastUpdated"]),currentMatches:this.state.currentMatches.map((t=>({id:t.id,state:{status:t.state.status}})))}});hydrate=t=>{this.__store.setState((a=>{const s=this.matchRoutes(t.state.latestLocation.pathname,{strictParseParams:!0});return s.forEach(((a,s)=>{const r=t.state.currentMatches[s];e(r&&r.id===a.id),a.__store.setState((t=>({...t,...r.state})))})),{...a,...t.state,currentMatches:s}}))};#h=t=>{const a=(t,s)=>{t.forEach(((t,s)=>{t.init({originalIndex:s,router:this});e(!this.routesById[t.id],String(t.id)),this.routesById[t.id]=t;const r=t.children;r?.length&&(a(r),t.children=r.map(((t,e)=>{const a=P(_(w(t.path??"/")));for(;a.length>1&&"/"===a[0]?.value;)a.shift();let s=0;return a.forEach(((t,e)=>{let a=1;for(;e--;)a*=.001;"pathname"===t.type&&"/"!==t.value?s+=1*a:"param"===t.type?s+=2*a:"wildcard"===t.type&&(s+=3*a)})),{child:t,parsed:a,index:e,score:s}})).sort(((t,e)=>t.score!==e.score?t.score-e.score:t.index-e.index)).map((t=>t.child)))}))};a([t]);const s=(t,a)=>{t.forEach((t=>{t.isRoot?e(!a):e(!a||t.parentRoute===a,(t.path,t.parentRoute?.id,a?.id)),t.children&&s(t.children,t)}))};return s([t],void 0),t};#i=t=>{let{pathname:e,search:a,hash:s,state:r}=this.history.location;const o=this.options.parseSearch(a);return{pathname:e,searchStr:a,search:f(t?.search,o),hash:s.split("#").reverse()[0]??"",href:`${e}${a}${s}`,state:r,key:r?.key||"__init__"}};#c=(t={})=>{t.fromCurrent=t.fromCurrent??""===t.to;const e=t.fromCurrent?this.state.latestLocation.pathname:t.from??this.state.latestLocation.pathname;let a=L(this.basepath??"/",e,`${t.to??""}`);const s={...l(this.matchRoutes(this.state.latestLocation.pathname,{strictParseParams:!0}))?.params};let r=!0===(t.params??!0)?s:p(t.params,s);r&&t.__matches?.map((t=>t.route.options.stringifyParams)).filter(Boolean).forEach((t=>{r={...r,...t(r)}})),a=R(a,r??{});const o=t.__matches?.map((t=>t.route.options.preSearchFilters??[])).flat().filter(Boolean)??[],n=t.__matches?.map((t=>t.route.options.postSearchFilters??[])).flat().filter(Boolean)??[],i=o?.length?o?.reduce(((t,e)=>e(t)),this.state.latestLocation.search):this.state.latestLocation.search,h=!0===t.search?i:t.search?p(t.search,i)??{}:o?.length?i:{},c=n?.length?n.reduce(((t,e)=>e(t)),h):h,u=f(this.state.latestLocation.search,c),d=this.options.stringifySearch(u);let m=!0===t.hash?this.state.latestLocation.hash:p(t.hash,this.state.latestLocation.hash);m=m?`#${m}`:"";return{pathname:a,search:u,searchStr:d,state:!0===t.state?this.state.latestLocation.state:p(t.state,this.state.latestLocation.state),hash:m,href:this.history.createHref(`${a}${d}${m}`),key:t.key}};#n=async t=>{const e=this.buildNext(t),a=""+Date.now()+Math.random();this.navigateTimeout&&clearTimeout(this.navigateTimeout);let s="replace";t.replace||(s="push");this.state.latestLocation.href===e.href&&!e.key&&(s="replace");const r=`${e.pathname}${e.searchStr}${e.hash?`${e.hash}`:""}`;return this.history["push"===s?"push":"replace"](r,{id:a,...e.state}),this.navigationPromise=new Promise((t=>{const e=this.resolveNavigation;this.resolveNavigation=()=>{e(),t()}}))}},t.cleanPath=w,t.createBrowserHistory=i,t.createHashHistory=function(){return i({getHref:()=>window.location.hash.substring(1),createHref:t=>`#${t}`})},t.createMemoryHistory=h,t.decode=$,t.defaultFetchServerDataFn=N,t.defaultParseSearch=T,t.defaultStringifySearch=H,t.encode=M,t.functionalUpdate=p,t.interpolatePath=R,t.invariant=e,t.isPlainObject=m,t.isRedirect=F,t.joinPaths=v,t.last=l,t.matchByPath=E,t.matchPathname=x,t.parsePathname=P,t.parseSearchWith=j,t.partialDeepEqual=y,t.pick=d,t.redirect=function(t){return t.isRedirect=!0,t},t.replaceEqualDeep=f,t.resolvePath=L,t.rootRouteId=A,t.stringifySearchWith=O,t.trimPath=b,t.trimPathLeft=_,t.trimPathRight=S,t.warning=function(t,e){},Object.defineProperty(t,"__esModule",{value:!0})})); | ||
*/class D{listeners=new Set;batching=!1;queue=[];constructor(t,e){this.state=t,this.options=e}subscribe=t=>{this.listeners.add(t);const e=this.options?.onSubscribe?.(t,this);return()=>{this.listeners.delete(t),e?.()}};setState=t=>{const e=this.state;this.state=this.options?.updateFn?this.options.updateFn(e)(t):t(e),this.state!==e&&(this.options?.onUpdate?.(this.state,e),this.queue.push((()=>{this.listeners.forEach((t=>t(this.state,e)))})),this.#t())};#t=()=>{this.batching||(this.queue.forEach((t=>t())),this.queue=[])};batch=t=>{this.batching=!0,t(),this.batching=!1,this.#t()}} | ||
/** | ||
* react-store | ||
* | ||
* Copyright (c) TanStack | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE.md file in the root directory of this source tree. | ||
* | ||
* @license MIT | ||
*/function T(t,e=(t=>t)){return r.useSyncExternalStoreWithSelector(t.subscribe,(()=>t.state),(()=>t.state),e,N)}function N(t,e){if(Object.is(t,e))return!0;if("object"!=typeof t||null===t||"object"!=typeof e||null===e)return!1;const r=Object.keys(t);if(r.length!==Object.keys(e).length)return!1;for(let o=0;o<r.length;o++)if(!Object.prototype.hasOwnProperty.call(e,r[o])||!Object.is(t[r[o]],e[r[o]]))return!1;return!0}function H(t){const e=z(),{type:r,children:o,target:s,activeProps:n=(()=>({className:"active"})),inactiveProps:i=(()=>({})),activeOptions:c,disabled:h,hash:u,search:l,params:d,to:p=".",preload:f,preloadDelay:m,replace:y,style:v,className:w,onClick:_,onFocus:b,onMouseEnter:S,onMouseLeave:L,onTouchStart:E,...x}=t,P=e.buildLink(t);if("external"===P.type){const{href:t}=P;return{href:t}}const{handleClick:C,handleFocus:R,handleEnter:M,handleLeave:k,handleTouchStart:O,isActive:j,next:A}=P,I=t=>e=>{e.persist&&e.persist(),t.filter(Boolean).forEach((t=>{e.defaultPrevented||t(e)}))},$=j?g(n,{})??{}:{},D=j?{}:g(i,{})??{};return{...$,...D,...x,href:h?void 0:A.href,onClick:I([_,t=>{a.startTransition?a.startTransition((()=>{C(t)})):C(t)}]),onFocus:I([b,R]),onMouseEnter:I([S,M]),onMouseLeave:I([L,k]),onTouchStart:I([E,O]),target:s,style:{...v,...$.style,...D.style},className:[w,$.className,D.className].filter(Boolean).join(" ")||void 0,...h?{role:"link","aria-disabled":!0}:void 0,"data-status":j?"active":void 0}}const B=a.forwardRef(((t,e)=>{const r=H(t);return a.createElement("a",$({ref:e},r,{children:"function"==typeof t.children?t.children({isActive:"active"===r["data-status"]}):t.children}))}));const F=a.createContext(null),U=a.createContext(null);function z(){const t=a.useContext(U);return T(t.router.__store),t.router}function q(t){const e=z();return T(e.__store,t),e}function W(){return a.useContext(F)}function K(t){const e=z(),r=W()[0],o=t?.from?e.state.currentMatches.find((e=>e.route.id===t?.from)):r;return s(o,t?.from&&t.from),(t?.strict??1)&&s(r.route.id==o?.route.id,(o?.route.id,r.route.id,o?.route.id,o?.route.id)),T(o.__store,(e=>t?.track?.(o)??o)),o}function V(t){const{track:e,...r}=t,o=K(r);return T(o.__store,(e=>t?.track?.(e.loader)??e.loader)),o.state.loader}function J(t){const{track:e,...r}=t,o=K(r);return T(o.__store,(e=>t?.track?.(e.search)??e.search)),o.state.search}function G(){const t=z();return a.useCallback((e=>{const{pending:r,caseSensitive:o,...a}=e;return t.matchRoute(a,{pending:r,caseSensitive:o})}),[])}function Y(){const t=W().slice(1),e=t[0];return e?a.createElement(Q,{matches:t,match:e}):null}function Q({matches:t,match:e}){const r=z();T(e.__store,(t=>[t.status,t.error]));const o=a.useCallback((()=>null),[]),s=e.pendingComponent??r.options.defaultPendingComponent??o,n=e.errorComponent??r.options.defaultErrorComponent,i=e.route.options.wrapInSuspense??1?a.Suspense:Z,c=n?tt:Z;return a.createElement(F.Provider,{value:t},a.createElement(i,{fallback:a.createElement(s,null)},a.createElement(c,{key:e.route.id,errorComponent:n,onCatch:()=>{e.id}},a.createElement(X,{match:e}))))}function X(t){const e=z();if("error"===t.match.state.status)throw t.match.state.error;if("pending"===t.match.state.status)throw t.match.__loadPromise;if("success"===t.match.state.status)return a.createElement(t.match.component??e.options.defaultComponent??Y,{useLoader:t.match.route.useLoader,useMatch:t.match.route.useMatch,useContext:t.match.route.useContext,useSearch:t.match.route.useSearch});s(!1)}function Z(t){return a.createElement(a.Fragment,null,t.children)}class tt extends a.Component{state={error:!1,info:void 0};componentDidCatch(t,e){this.props.onCatch(t,e),console.error(t),this.setState({error:t,info:e})}render(){return a.createElement(et,$({},this.props,{errorState:this.state,reset:()=>this.setState({})}))}}function et(t){const[e,r]=a.useState(t.errorState),o=z(),s=t.errorComponent??rt,n=a.useRef("");return a.useEffect((()=>{e&&o.state.currentLocation.key!==n.current&&r({}),n.current=o.state.currentLocation.key}),[e,o.state.currentLocation.key]),a.useEffect((()=>{t.errorState.error&&r(t.errorState)}),[t.errorState.error]),t.errorState.error&&e.error?a.createElement(s,e):t.children}function rt({error:t}){return a.createElement("div",{style:{padding:".5rem",maxWidth:"100%"}},a.createElement("strong",{style:{fontSize:"1.2rem"}},"Something went wrong!"),a.createElement("div",{style:{height:".5rem"}}),a.createElement("div",null,a.createElement("pre",{style:{fontSize:".7em",border:"1px solid red",borderRadius:".25rem",padding:".5rem",color:"red",overflow:"auto"}},t.message?a.createElement("code",null,t.message):null)))}function ot(t,e=!0){const r=q();a.useEffect((()=>{if(!e)return;let o=r.history.block(((e,r)=>{window.confirm(t)?(o(),e()):r()}));return o}))}const at="__root__";class st{constructor(t){this.options=t||{},this.isRoot=!t?.getParentRoute}init=t=>{this.originalIndex=t.originalIndex,this.router=t.router;const e=this.options,r=!e?.path&&!e?.id;this.parentRoute=this.options?.getParentRoute?.(),r?this.path=at:s(this.parentRoute);let o=r?at:e.path;o&&"/"!==o&&(o=P(o));const a=e?.id||o;let n=r?at:S([this.parentRoute.id===at?"":this.parentRoute.id,a]);o===at&&(o="/"),n!==at&&(n=S(["/",n]));const i=n===at?"/":x(S([this.parentRoute.fullPath,o]));this.path=o,this.id=n,this.fullPath=i};addChildren=t=>(this.children=t,this);useMatch=t=>K({...t,from:this.id});useLoader=t=>V({...t,from:this.id});useContext=t=>K({...t,from:this.id}).context;useSearch=t=>J({...t,from:this.id})}class nt extends st{constructor(t){super(t)}static withRouterContext=()=>t=>new nt(t)}const it=ht(JSON.parse),ct=ut(JSON.stringify);function ht(t){return e=>{"?"===e.substring(0,1)&&(e=e.substring(1));let r=I(e);for(let e in r){const o=r[e];if("string"==typeof o)try{r[e]=t(o)}catch(t){}}return r}}function ut(t){return e=>{(e={...e})&&Object.keys(e).forEach((r=>{const o=e[r];if(void 0===o||void 0===o)delete e[r];else if(o&&"object"==typeof o&&null!==o)try{e[r]=t(o)}catch(t){}}));const r=j(e).toString();return r?`?${r}`:""}}const lt=async({router:t,routeMatch:e})=>{const r=t.buildNext({to:".",search:t=>({...t??{},__data:{matchId:e.id}})}),o=await fetch(r.href,{method:"GET",signal:e.abortController.signal});if(o.ok)return o.json();throw new Error("Failed to fetch match data")};const dt="undefined"==typeof window||!window.document.createElement;function pt(){return{status:"idle",latestLocation:null,currentLocation:null,currentMatches:[],lastUpdated:Date.now()}}function ft(t){return!!t?.isRedirect}const mt=["component","errorComponent","pendingComponent"];class yt{abortController=new AbortController;constructor(t,e,r){Object.assign(this,{route:e,router:t,id:r.id,pathname:r.pathname,params:r.params,__store:new D({updatedAt:0,routeSearch:{},search:{},status:"idle",loader:void 0},{onUpdate:t=>{this.state=t}})}),this.state=this.__store.state,mt.map((async t=>{const e=this.route.options[t];this[t]=e})),"idle"!==this.state.status||this.#e()||this.__store.setState((t=>({...t,status:"success"})))}#e=()=>!(!this.route.options.loader&&!mt.some((t=>this.route.options[t]?.preload)));__commit=()=>{const{routeSearch:t,search:e,context:r,routeContext:o}=this.#r({location:this.router.state.currentLocation});this.context=r,this.routeContext=o,this.__store.setState((r=>({...r,routeSearch:v(r.routeSearch,t),search:v(r.search,e)})))};cancel=()=>{this.abortController?.abort()};#o=t=>{const e=this.parentMatch?this.parentMatch.#o(t):{search:t.location.search,routeSearch:t.location.search};try{const t=("object"==typeof this.route.options.validateSearch?this.route.options.validateSearch.parse:this.route.options.validateSearch)?.(e.search)??{};return{routeSearch:t,search:{...e.search,...t}}}catch(t){if(ft(t))throw t;(this.route.options.onValidateSearchError??this.route.options.onError)?.(t);const e=new Error("Invalid search params found",{cause:t});throw e.code="INVALID_SEARCH_PARAMS",e}};#r=t=>{const{search:e,routeSearch:r}=this.#o(t);try{const t=this.route.options.getContext?.({parentContext:this.parentMatch?.routeContext??{},context:this.parentMatch?.context??this.router?.options.context??{},params:this.params,search:e})||{};return{routeSearch:r,search:e,context:{...this.parentMatch?.context??this.router?.options.context,...t},routeContext:t}}catch(t){throw this.route.options.onError?.(t),t}};__load=async t=>{let e;this.parentMatch=t.parentMatch;try{e=this.#r(t)}catch(e){return ft(e)?void(t?.preload||this.router.navigate(e)):void this.__store.setState((t=>({...t,status:"error",error:e})))}const{routeSearch:r,search:o,context:a,routeContext:s}=e;if("pending"!==this.state.status)return this.__loadPromise=Promise.resolve().then((async()=>{const e=""+Date.now()+Math.random();this.#a=e;const n=()=>e!==this.#a?this.__loadPromise:void 0;let i;"idle"===this.state.status&&this.__store.setState((t=>({...t,status:"pending"})));const c=(async()=>{await Promise.all(mt.map((async t=>{const e=this.route.options[t];e?.preload&&await e.preload()})))})(),h=Promise.resolve().then((()=>{if(this.route.options.loader)return this.route.options.loader({params:this.params,routeSearch:r,search:o,signal:this.abortController.signal,preload:!!t?.preload,routeContext:s,context:a})}));try{const[t,e]=await Promise.all([c,h]);if(i=n())return await i;this.__store.setState((t=>({...t,error:void 0,status:"success",updatedAt:Date.now(),loader:e})))}catch(e){if(ft(e))return void(t?.preload||this.router.navigate(e));const r=this.route.options.onLoadError??this.route.options.onError;try{r?.(e)}catch(e){return ft(e)?void(t?.preload||this.router.navigate(e)):void this.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}this.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}finally{delete this.__loadPromise}})),this.__loadPromise};#a=""}t.Block=function({message:t,condition:e,children:r}){return ot(t,e),r??null},t.ErrorComponent=rt,t.Link=B,t.MatchRoute=function(t){const e=G()(t);return e?"function"==typeof t.children?t.children(e):e?t.children:null:null},t.Navigate=function(t){const e=z();return a.useLayoutEffect((()=>{e.navigate(t)}),[]),null},t.Outlet=Y,t.RootRoute=nt,t.Route=st,t.RouteMatch=yt,t.Router=class{#s;startedLoadingAt=Date.now();resolveNavigation=()=>{};constructor(t){this.options={defaultPreloadDelay:50,context:void 0,...t,stringifySearch:t?.stringifySearch??ct,parseSearch:t?.parseSearch??it,fetchServerDataFn:t?.fetchServerDataFn??lt},this.__store=new D(pt(),{onUpdate:t=>{this.state=t}}),this.state=this.__store.state,this.update(t);const e=this.buildNext({hash:!0,fromCurrent:!0,search:!0,state:!0});this.state.latestLocation.href!==e.href&&this.#n({...e,replace:!0})}reset=()=>{this.__store.setState((t=>Object.assign(t,pt())))};mount=()=>(dt||this.state.currentMatches.length||this.safeLoad(),()=>{});hydrate=async t=>{let e=t;return"undefined"!=typeof document&&(e=window.__DEHYDRATED__,s(e)),this.options.hydrate?.(e),await this.load()};update=t=>{if(Object.assign(this.options,t),this.context=this.options.context,!this.history||this.options.history&&this.options.history!==this.history){this.#s&&this.#s(),this.history=this.options.history??(dt?p():d());const t=this.#i();this.__store.setState((e=>({...e,latestLocation:t,currentLocation:t}))),this.#s=this.history.listen((()=>{this.safeLoad({next:this.#i(this.state.latestLocation)})}))}const{basepath:e,routeTree:r}=this.options;return this.basepath=`/${P(e??"")??""}`,r&&(this.routesById={},this.routeTree=this.#c(r)),this};buildNext=t=>{const e=this.#h(t),r=this.matchRoutes(e.pathname);return this.#h({...t,__matches:r})};cancelMatches=()=>{[...this.state.currentMatches,...this.state.pendingMatches||[]].forEach((t=>{t.cancel()}))};safeLoad=t=>{this.load(t).catch((t=>{console.warn(t),s(!1)}))};load=async t=>{let e=Date.now();const r=e;let o;if(this.startedLoadingAt=r,this.cancelMatches(),this.__store.batch((()=>{t?.next&&this.__store.setState((e=>({...e,latestLocation:t.next}))),o=this.matchRoutes(this.state.latestLocation.pathname,{strictParseParams:!0}),this.__store.setState((t=>({...t,status:"pending",pendingMatches:o,pendingLocation:this.state.latestLocation})))})),await this.loadMatches(o,this.state.pendingLocation),this.startedLoadingAt!==r)return this.navigationPromise;const a=this.state.currentMatches,s=[],n=[];a.forEach((t=>{o.find((e=>e.id===t.id))?n.push(t):s.push(t)}));const i=o.filter((t=>!a.find((e=>e.id===t.id))));e=Date.now(),s.forEach((t=>{t.__onExit?.({params:t.params,search:t.state.routeSearch}),"error"===t.state.status&&this.__store.setState((t=>({...t,status:"idle",error:void 0})))})),n.forEach((t=>{t.route.options.onTransition?.({params:t.params,search:t.state.routeSearch})})),i.forEach((t=>{t.__onExit=t.route.options.onLoaded?.({params:t.params,search:t.state.search})}));const c=this.state.currentLocation;this.__store.setState((t=>({...t,status:"idle",currentLocation:this.state.latestLocation,currentMatches:o,pendingLocation:void 0,pendingMatches:void 0}))),o.forEach((t=>{t.__commit()})),c.href!==this.state.currentLocation.href&&this.options.onRouteChange?.(),this.resolveNavigation()};getRoute=t=>{const e=this.routesById[t];return s(e),e};loadRoute=async(t=this.state.latestLocation)=>{const e=this.buildNext(t),r=this.matchRoutes(e.pathname,{strictParseParams:!0});return await this.loadMatches(r,e),r};preloadRoute=async(t=this.state.latestLocation)=>{const e=this.buildNext(t),r=this.matchRoutes(e.pathname,{strictParseParams:!0});return await this.loadMatches(r,e,{preload:!0}),r};matchRoutes=(t,e)=>{const r=[];if(!this.routeTree)return r;const o=[...this.state.currentMatches,...this.state.pendingMatches??[]],a=async s=>{let n=y(r)?.params??{};const i=this.options.filterRoutes?.(s)??s;let c=[];const h=(r,o)=>(o.some((o=>{const a=o.children;if(!o.path&&a?.length)return h([...c,o],a);const s=!("/"===o.path&&!a?.length),i=k(this.basepath,t,{to:o.fullPath,fuzzy:s,caseSensitive:o.options.caseSensitive??this.options.caseSensitive});if(i){let t;try{t=o.options.parseParams?.(i)??i}catch(t){if(e?.strictParseParams)throw t}n={...n,...t}}return i&&(c=[...r,o]),!!c.length})),!!c.length);if(h([],i),!c.length)return;c.forEach((t=>{const e=M(t.path,n),a=M(t.id,n,!0),s=o.find((t=>t.id===a))||new yt(this,t,{id:a,params:n,pathname:S([this.basepath,e])});r.push(s)}));const u=y(c).children;u?.length&&a(u)};return a([this.routeTree]),r};loadMatches=async(t,e,r)=>{let o;try{await Promise.all(t.map((async(t,e)=>{try{await(t.route.options.beforeLoad?.({router:this,match:t}))}catch(r){if(ft(r))throw r;o=o??e;const a=t.route.options.onBeforeLoadError??t.route.options.onError;try{a?.(r)}catch(e){if(ft(e))throw e;return void t.__store.setState((t=>({...t,error:e,status:"error",updatedAt:Date.now()})))}t.__store.setState((t=>({...t,error:r,status:"error",updatedAt:Date.now()})))}})))}catch(t){if(ft(t))return void(r?.preload||this.navigate(t));throw t}const a=t.slice(0,o),s=a.map((async(t,o)=>{const s=a[o-1];t.__load({preload:r?.preload,location:e,parentMatch:s}),await t.__loadPromise,s&&await s.__loadPromise}));await Promise.all(s)};reload=()=>{this.navigate({fromCurrent:!0,replace:!0,search:!0})};resolvePath=(t,e)=>C(this.basepath,t,L(e));navigate=async({from:t,to:e="",search:r,hash:o,replace:a,params:n})=>{const i=String(e),c=void 0===t?t:String(t);let h;try{new URL(`${i}`),h=!0}catch(t){}return s(!h),this.#n({from:c,to:i,search:r,hash:o,replace:a,params:n})};matchRoute=(t,e)=>{t={...t,to:t.to?this.resolvePath(t.from??"",t.to):void 0};const r=this.buildNext(t),o=e?.pending?this.state.pendingLocation:this.state.currentLocation;if(!o)return!1;const a=k(this.basepath,o.pathname,{...e,to:r.pathname});return!!a&&(e?.includeSearch??1?!!b(o.search,r.search)&&a:a)};buildLink=({from:t,to:e=".",search:r,params:o,hash:a,target:s,replace:n,activeOptions:i,preload:c,preloadDelay:h,disabled:u})=>{try{return new URL(`${e}`),{type:"external",href:e}}catch(t){}const l={from:t,to:e,search:r,params:o,hash:a,replace:n},d=this.buildNext(l);c=c??this.options.defaultPreload;const p=h??this.options.defaultPreloadDelay??0,f=this.state.currentLocation.pathname.split("/"),m=d.pathname.split("/").every(((t,e)=>t===f[e])),y=i?.exact?this.state.currentLocation.pathname===d.pathname:m,g=!i?.includeHash||this.state.currentLocation.hash===d.hash,v=!(i?.includeSearch??1)||b(this.state.currentLocation.search,d.search);return{type:"internal",next:d,handleFocus:t=>{c&&this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))},handleClick:t=>{u||function(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}(t)||t.defaultPrevented||s&&"_self"!==s||0!==t.button||(t.preventDefault(),this.#n(l))},handleEnter:t=>{const e=t.target||{};if(c){if(e.preloadTimeout)return;e.preloadTimeout=setTimeout((()=>{e.preloadTimeout=null,this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))}),p)}},handleLeave:t=>{const e=t.target||{};e.preloadTimeout&&(clearTimeout(e.preloadTimeout),e.preloadTimeout=null)},handleTouchStart:t=>{this.preloadRoute(l).catch((t=>{console.warn(t),console.warn("Error preloading route! ☝️")}))},isActive:y&&g&&v,disabled:u}};#c=t=>{const e=(t,r)=>{t.forEach(((t,r)=>{t.init({originalIndex:r,router:this});s(!this.routesById[t.id],String(t.id)),this.routesById[t.id]=t;const o=t.children;o?.length&&(e(o),t.children=o.map(((t,e)=>{const r=R(E(L(t.path??"/")));for(;r.length>1&&"/"===r[0]?.value;)r.shift();let o=0;return r.forEach(((t,e)=>{let r=1;for(;e--;)r*=.001;"pathname"===t.type&&"/"!==t.value?o+=1*r:"param"===t.type?o+=2*r:"wildcard"===t.type&&(o+=3*r)})),{child:t,parsed:r,index:e,score:o}})).sort(((t,e)=>t.score!==e.score?t.score-e.score:t.index-e.index)).map((t=>t.child)))}))};e([t]);const r=(t,e)=>{t.forEach((t=>{t.isRoot?s(!e):s(!e||t.parentRoute===e,(t.path,t.parentRoute?.id,e?.id)),t.children&&r(t.children,t)}))};return r([t],void 0),t};#i=t=>{let{pathname:e,search:r,hash:o,state:a}=this.history.location;const s=this.options.parseSearch(r);return{pathname:e,searchStr:r,search:v(t?.search,s),hash:o.split("#").reverse()[0]??"",href:`${e}${r}${o}`,state:a,key:a?.key||"__init__"}};#h=(t={})=>{t.fromCurrent=t.fromCurrent??""===t.to;const e=t.fromCurrent?this.state.latestLocation.pathname:t.from??this.state.latestLocation.pathname;let r=C(this.basepath??"/",e,`${t.to??""}`);const o={...y(this.matchRoutes(this.state.latestLocation.pathname,{strictParseParams:!0}))?.params};let a=!0===(t.params??!0)?o:g(t.params,o);a&&t.__matches?.map((t=>t.route.options.stringifyParams)).filter(Boolean).forEach((t=>{a={...a,...t(a)}})),r=M(r,a??{});const s=t.__matches?.map((t=>t.route.options.preSearchFilters??[])).flat().filter(Boolean)??[],n=t.__matches?.map((t=>t.route.options.postSearchFilters??[])).flat().filter(Boolean)??[],i=s?.length?s?.reduce(((t,e)=>e(t)),this.state.latestLocation.search):this.state.latestLocation.search,c=!0===t.search?i:t.search?g(t.search,i)??{}:s?.length?i:{},h=n?.length?n.reduce(((t,e)=>e(t)),c):c,u=v(this.state.latestLocation.search,h),l=this.options.stringifySearch(u);let d=!0===t.hash?this.state.latestLocation.hash:g(t.hash,this.state.latestLocation.hash);d=d?`#${d}`:"";return{pathname:r,search:u,searchStr:l,state:!0===t.state?this.state.latestLocation.state:g(t.state,this.state.latestLocation.state),hash:d,href:this.history.createHref(`${r}${l}${d}`),key:t.key}};#n=async t=>{const e=this.buildNext(t),r=""+Date.now()+Math.random();this.navigateTimeout&&clearTimeout(this.navigateTimeout);let o="replace";t.replace||(o="push");this.state.latestLocation.href===e.href&&!e.key&&(o="replace");const a=`${e.pathname}${e.searchStr}${e.hash?`${e.hash}`:""}`;return this.history["push"===o?"push":"replace"](a,{id:r,...e.state}),this.navigationPromise=new Promise((t=>{const e=this.resolveNavigation;this.resolveNavigation=()=>{e(),t()}}))}},t.RouterProvider=function({router:t,...e}){t.update(e);const r=T(t.__store,(t=>t.currentMatches));return a.useEffect(t.mount,[t]),a.createElement(U.Provider,{value:{router:t}},a.createElement(F.Provider,{value:[void 0,...r]},a.createElement(tt,{errorComponent:rt,onCatch:()=>{}},a.createElement(Y,null))))},t.cleanPath=L,t.createBrowserHistory=d,t.createHashHistory=function(){return d({getHref:()=>window.location.hash.substring(1),createHref:t=>`#${t}`})},t.createMemoryHistory=p,t.decode=I,t.defaultFetchServerDataFn=lt,t.defaultParseSearch=it,t.defaultStringifySearch=ct,t.encode=j,t.functionalUpdate=g,t.interpolatePath=M,t.invariant=s,t.isPlainObject=w,t.isRedirect=ft,t.joinPaths=S,t.last=y,t.lazy=function(t){const e=a.lazy(t);return e.preload=async()=>{await t()},e},t.matchByPath=O,t.matchPathname=k,t.matchesContext=F,t.parsePathname=R,t.parseSearchWith=ht,t.partialDeepEqual=b,t.pick=function(t,e){return e.reduce(((e,r)=>(e[r]=t[r],e)),{})},t.redirect=function(t){return t.isRedirect=!0,t},t.replaceEqualDeep=v,t.resolvePath=C,t.rootRouteId=at,t.routerContext=U,t.stringifySearchWith=ut,t.trimPath=P,t.trimPathLeft=E,t.trimPathRight=x,t.useBlocker=ot,t.useLinkProps=H,t.useLoader=V,t.useMatch=K,t.useMatchRoute=G,t.useMatches=W,t.useNavigate=function(t){const e=z();return a.useCallback((r=>e.navigate({...t,...r})),[])},t.useParams=function(t){const e=z();return T(e.__store,(e=>{const r=y(e.currentMatches)?.params;return t?.track?.(r)??r})),y(e.state.currentMatches)?.params},t.useRouter=q,t.useRouterContext=z,t.useSearch=J,t.useStore=T,t.warning=n,Object.defineProperty(t,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=index.production.js.map |
{ | ||
"name": "@tanstack/router", | ||
"author": "Tanner Linsley", | ||
"version": "0.0.1-beta.83", | ||
"version": "0.0.1-beta.84", | ||
"license": "MIT", | ||
@@ -37,2 +37,6 @@ "repository": "tanstack/router", | ||
"sideEffects": false, | ||
"peerDependencies": { | ||
"react": ">=16", | ||
"react-dom": ">=16" | ||
}, | ||
"dependencies": { | ||
@@ -42,4 +46,4 @@ "@babel/runtime": "^7.16.7", | ||
"tiny-warning": "^1.0.3", | ||
"@tanstack/store": "0.0.1-beta.81" | ||
"@tanstack/react-store": "0.0.1-beta.84" | ||
} | ||
} |
export { default as invariant } from 'tiny-invariant' | ||
export { default as warning } from 'tiny-warning' | ||
export * from './history' | ||
export * from './frameworks' | ||
export * from './link' | ||
@@ -14,2 +13,2 @@ export * from './path' | ||
export * from './utils' | ||
// export * from './routeError' | ||
export * from './react' |
@@ -1,2 +0,1 @@ | ||
import invariant from 'tiny-invariant' | ||
import { AnyPathParams } from './route' | ||
@@ -3,0 +2,0 @@ import { MatchLocation } from './router' |
336
src/route.ts
@@ -1,5 +0,4 @@ | ||
import { GetFrameworkGeneric } from './frameworks' | ||
import { ParsePathParams } from './link' | ||
import { RouteMatch } from './routeMatch' | ||
import { AnyRouter, Router, RouterContext } from './router' | ||
import { AnyRouter, RegisteredRoutesInfo, Router } from './router' | ||
import { | ||
@@ -14,7 +13,13 @@ IsAny, | ||
import { joinPaths, trimPath, trimPathRight } from './path' | ||
import { DefaultRoutesInfo } from './routeInfo' | ||
import { AnyRoutesInfo, DefaultRoutesInfo } from './routeInfo' | ||
import { | ||
MakeLinkOptions, | ||
RouteComponent, | ||
useLoader, | ||
useMatch, | ||
useSearch, | ||
} from './react' | ||
export const rootRouteId = '__root__' as const | ||
export type RootRouteId = typeof rootRouteId | ||
export type AnyPathParams = {} | ||
@@ -37,4 +42,2 @@ export type AnySearchSchema = {} | ||
export interface FrameworkRouteOptions {} | ||
export type MetaOptions = keyof PickRequired<RouteMeta> extends never | ||
@@ -99,2 +102,67 @@ ? { | ||
export type RouteProps< | ||
TParentRoute extends AnyRoute, | ||
TPath extends string, | ||
TFullPath extends ResolveFullPath< | ||
TParentRoute, | ||
TPath, | ||
RoutePrefix<TParentRoute['fullPath'], TPath> | ||
>, | ||
TCustomId extends string, | ||
TId extends ResolveId<TParentRoute, TCustomId, TPath>, | ||
TLoader, | ||
TSearchSchema extends AnySearchSchema, | ||
TFullSearchSchema extends AnySearchSchema, | ||
TAllParams, | ||
TParentContext, | ||
TAllParentContext extends IsAny< | ||
TParentRoute['__types']['allParams'], | ||
TParentContext, | ||
TParentRoute['__types']['allParams'] & TParentContext | ||
>, | ||
TRouteContext, | ||
TContext, | ||
TRouterContext extends AnyContext, | ||
> = { | ||
useMatch: () => RouteMatch< | ||
AnyRoutesInfo, | ||
Route< | ||
TParentRoute, | ||
TPath, | ||
TFullPath, | ||
TCustomId, | ||
TId, | ||
TLoader, | ||
TSearchSchema, | ||
TFullSearchSchema, | ||
TParentContext, | ||
TAllParentContext, | ||
TRouteContext, | ||
TContext, | ||
TRouterContext, | ||
any, | ||
any | ||
> | ||
> | ||
useLoader: () => TLoader | ||
useSearch: < | ||
TStrict extends boolean = true, | ||
TSearch = TFullSearchSchema, | ||
TSelected = TSearch, | ||
>(opts?: { | ||
strict?: TStrict | ||
track?: (search: TSearch) => TSelected | ||
}) => TStrict extends true ? TSelected : TSelected | undefined | ||
useParams: < | ||
TDefaultSelected = TAllParams, | ||
TSelected = TDefaultSelected, | ||
>(opts?: { | ||
track?: (search: TDefaultSelected) => TSelected | ||
}) => TSelected | ||
useContext: () => TContext | ||
// navigate: <T extends TFullPath, TTo extends string = ''>( | ||
// opts?: MakeLinkOptions<T, TTo>, | ||
// ) => Promise<void> | ||
} | ||
export type RouteOptions< | ||
@@ -104,2 +172,3 @@ TParentRoute extends AnyRoute = AnyRoute, | ||
TPath extends string = string, | ||
TLoader = unknown, | ||
TParentSearchSchema extends {} = {}, | ||
@@ -112,64 +181,114 @@ TSearchSchema extends AnySearchSchema = {}, | ||
TParentContext extends AnyContext = AnyContext, | ||
TAllParentContext extends AnyContext = AnyContext, | ||
TAllParentContext extends IsAny< | ||
TParentRoute['__types']['allParams'], | ||
TParentContext, | ||
TParentRoute['__types']['allParams'] & TParentContext | ||
> = IsAny< | ||
TParentRoute['__types']['allParams'], | ||
TParentContext, | ||
TParentRoute['__types']['allParams'] & TParentContext | ||
>, | ||
TRouteContext extends RouteContext = RouteContext, | ||
TContext extends AnyContext = TRouteContext, | ||
> = RouteOptionsBase<TCustomId, TPath> & | ||
FrameworkRouteOptions & { | ||
getParentRoute: () => TParentRoute | ||
// If true, this route will be matched as case-sensitive | ||
caseSensitive?: boolean | ||
// Filter functions that can manipulate search params *before* they are passed to links and navigate | ||
// calls that match this route. | ||
preSearchFilters?: SearchFilter<TFullSearchSchema>[] | ||
// Filter functions that can manipulate search params *after* they are passed to links and navigate | ||
// calls that match this route. | ||
postSearchFilters?: SearchFilter<TFullSearchSchema>[] | ||
// The content to be rendered when the route is matched. If no component is provided, defaults to `<Outlet />` | ||
component?: GetFrameworkGeneric<'Component'> // , NoInfer<TParentAllLoaderData>> | ||
// The content to be rendered when the route encounters an error | ||
errorComponent?: GetFrameworkGeneric<'ErrorComponent'> // , NoInfer<TParentAllLoaderData>> | ||
// If supported by your framework, the content to be rendered as the fallback content until the route is ready to render | ||
pendingComponent?: GetFrameworkGeneric<'Component'> //, NoInfer<TParentAllLoaderData>> | ||
// This async function is called before a route is loaded. | ||
// If an error is thrown here, the route's loader will not be called. | ||
// If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onLoadError` function. | ||
// If thrown during a preload event, the error will be logged to the console. | ||
beforeLoad?: (opts: { | ||
router: AnyRouter | ||
match: RouteMatch | ||
}) => Promise<void> | void | ||
// This function will be called if the route's loader throws an error **during an attempted navigation**. | ||
// If you want to redirect due to an error, call `router.navigate()` from within this function. | ||
onBeforeLoadError?: (err: any) => void | ||
validateSearch?: SearchSchemaValidator<TSearchSchema, TParentSearchSchema> | ||
// This function will be called if the route's validateSearch option throws an error **during an attempted validation**. | ||
// If you want to redirect due to an error, call `router.navigate()` from within this function. | ||
// If you want to display the errorComponent, rethrow the error | ||
onValidateSearchError?: (err: any) => void | ||
// An asynchronous function responsible for preparing or fetching data for the route before it is rendered | ||
onLoad?: OnLoadFn< | ||
TContext extends MergeFromParent< | ||
TAllParentContext, | ||
TRouteContext | ||
> = MergeFromParent<TAllParentContext, TRouteContext>, | ||
> = RouteOptionsBase<TCustomId, TPath> & { | ||
getParentRoute: () => TParentRoute | ||
// If true, this route will be matched as case-sensitive | ||
caseSensitive?: boolean | ||
// Filter functions that can manipulate search params *before* they are passed to links and navigate | ||
// calls that match this route. | ||
preSearchFilters?: SearchFilter<TFullSearchSchema>[] | ||
// Filter functions that can manipulate search params *after* they are passed to links and navigate | ||
// calls that match this route. | ||
postSearchFilters?: SearchFilter<TFullSearchSchema>[] | ||
// The content to be rendered when the route is matched. If no component is provided, defaults to `<Outlet />` | ||
component?: RouteComponent< | ||
RouteProps< | ||
TParentRoute, | ||
TPath, | ||
ResolveFullPath<TParentRoute, TPath>, | ||
TCustomId, | ||
ResolveId<TParentRoute, TCustomId, TPath>, | ||
TLoader, | ||
TSearchSchema, | ||
TFullSearchSchema, | ||
TAllParams, | ||
NoInfer<TRouteContext>, | ||
TContext | ||
TParentContext, | ||
TAllParentContext, | ||
TRouteContext, | ||
TContext, | ||
NoInfer<TRouteContext> | ||
> | ||
onLoadError?: (err: any) => void | ||
onError?: (err: any) => void | ||
// This function is called | ||
// when moving from an inactive state to an active one. Likewise, when moving from | ||
// an active to an inactive state, the return function (if provided) is called. | ||
onLoaded?: (matchContext: { | ||
params: TAllParams | ||
search: TFullSearchSchema | ||
}) => | ||
| void | ||
| undefined | ||
| ((match: { params: TAllParams; search: TFullSearchSchema }) => void) | ||
// This function is called when the route remains active from one transition to the next. | ||
onTransition?: (match: { | ||
params: TAllParams | ||
search: TFullSearchSchema | ||
}) => void | ||
} & MetaOptions & | ||
> // | ||
// The content to be rendered when the route encounters an error | ||
errorComponent?: RouteComponent<{ | ||
error: Error | ||
info: { componentStack: string } | ||
}> // | ||
// If supported by your framework, the content to be rendered as the fallback content until the route is ready to render | ||
pendingComponent?: RouteComponent< | ||
RouteProps< | ||
TParentRoute, | ||
TPath, | ||
ResolveFullPath<TParentRoute, TPath>, | ||
TCustomId, | ||
ResolveId<TParentRoute, TCustomId, TPath>, | ||
TLoader, | ||
TSearchSchema, | ||
TFullSearchSchema, | ||
TAllParams, | ||
TParentContext, | ||
TAllParentContext, | ||
TRouteContext, | ||
TContext, | ||
NoInfer<TRouteContext> | ||
> | ||
> // | ||
wrapInSuspense?: boolean | ||
// This async function is called before a route is loaded. | ||
// If an error is thrown here, the route's loader will not be called. | ||
// If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onLoadError` function. | ||
// If thrown during a preload event, the error will be logged to the console. | ||
beforeLoad?: (opts: { | ||
router: AnyRouter | ||
match: RouteMatch | ||
}) => Promise<void> | void | ||
// This function will be called if the route's loader throws an error **during an attempted navigation**. | ||
// If you want to redirect due to an error, call `router.navigate()` from within this function. | ||
onBeforeLoadError?: (err: any) => void | ||
validateSearch?: SearchSchemaValidator<TSearchSchema, TParentSearchSchema> | ||
// This function will be called if the route's validateSearch option throws an error **during an attempted validation**. | ||
// If you want to redirect due to an error, call `router.navigate()` from within this function. | ||
// If you want to display the errorComponent, rethrow the error | ||
onValidateSearchError?: (err: any) => void | ||
// An asynchronous function responsible for preparing or fetching data for the route before it is rendered | ||
loader?: OnLoadFn< | ||
TLoader, | ||
TSearchSchema, | ||
TFullSearchSchema, | ||
TAllParams, | ||
NoInfer<TRouteContext>, | ||
TContext | ||
> | ||
onLoadError?: (err: any) => void | ||
onError?: (err: any) => void | ||
// This function is called | ||
// when moving from an inactive state to an active one. Likewise, when moving from | ||
// an active to an inactive state, the return function (if provided) is called. | ||
onLoaded?: (matchContext: { | ||
params: TAllParams | ||
search: TFullSearchSchema | ||
}) => | ||
| void | ||
| undefined | ||
| ((match: { params: TAllParams; search: TFullSearchSchema }) => void) | ||
// This function is called when the route remains active from one transition to the next. | ||
onTransition?: (match: { | ||
params: TAllParams | ||
search: TFullSearchSchema | ||
}) => void | ||
} & MetaOptions & | ||
ContextOptions< | ||
@@ -190,3 +309,3 @@ TParentRoute, | ||
? TParams | ||
: 'parseParams must return an ojbect' | ||
: 'parseParams must return an object' | ||
stringifyParams?: ( | ||
@@ -235,2 +354,3 @@ params: NoInfer<TParams>, | ||
export type OnLoadFn< | ||
TLoader = unknown, | ||
TSearchSchema extends AnySearchSchema = {}, | ||
@@ -249,3 +369,3 @@ TFullSearchSchema extends AnySearchSchema = {}, | ||
>, | ||
) => Promise<any> | void | ||
) => Promise<TLoader> | TLoader | ||
@@ -317,2 +437,3 @@ export interface LoaderContext< | ||
any, | ||
any, | ||
any | ||
@@ -336,2 +457,3 @@ > {} | ||
>, | ||
TLoader = unknown, | ||
TSearchSchema extends AnySearchSchema = {}, | ||
@@ -367,2 +489,3 @@ TFullSearchSchema extends AnySearchSchema = ResolveFullSearchSchema< | ||
id: TId | ||
loader: TLoader | ||
searchSchema: TSearchSchema | ||
@@ -385,2 +508,3 @@ fullSearchSchema: TFullSearchSchema | ||
TPath, | ||
TLoader, | ||
InferFullSearchSchema<TParentRoute>, | ||
@@ -415,2 +539,3 @@ TSearchSchema, | ||
TPath, | ||
TLoader, | ||
InferFullSearchSchema<TParentRoute>, | ||
@@ -440,2 +565,3 @@ TSearchSchema, | ||
TPath, | ||
TLoader, | ||
InferFullSearchSchema<TParentRoute>, | ||
@@ -513,2 +639,3 @@ TSearchSchema, | ||
TId, | ||
TLoader, | ||
TSearchSchema, | ||
@@ -530,35 +657,41 @@ TFullSearchSchema, | ||
// generate = ( | ||
// options: Omit< | ||
// RouteOptions< | ||
// TParentRoute, | ||
// TCustomId, | ||
// TPath, | ||
// InferFullSearchSchema<TParentRoute>, | ||
// TSearchSchema, | ||
// TFullSearchSchema, | ||
// TParentRoute['__types']['allParams'], | ||
// TParams, | ||
// TAllParams, | ||
// TParentContext, | ||
// TAllParentContext, | ||
// TRouteContext, | ||
// TContext | ||
// >, | ||
// 'path' | ||
// >, | ||
// ) => { | ||
// invariant( | ||
// false, | ||
// `route.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `, | ||
// ) | ||
// } | ||
useMatch = <TStrict extends boolean = true, TSelected = TContext>(opts?: { | ||
strict?: TStrict | ||
track?: (search: TContext) => TSelected | ||
}): TStrict extends true ? TSelected : TSelected | undefined => { | ||
return useMatch({ ...opts, from: this.id }) as any | ||
} | ||
useLoader = <TStrict extends boolean = true, TSelected = TLoader>(opts?: { | ||
strict?: TStrict | ||
track?: (search: TLoader) => TSelected | ||
}): TStrict extends true ? TSelected : TSelected | undefined => { | ||
return useLoader({ ...opts, from: this.id }) as any | ||
} | ||
useContext = <TStrict extends boolean = true, TSelected = TContext>(opts?: { | ||
strict?: TStrict | ||
track?: (search: TContext) => TSelected | ||
}): TStrict extends true ? TSelected : TSelected | undefined => { | ||
return useMatch({ ...opts, from: this.id }).context | ||
} | ||
useSearch = < | ||
TStrict extends boolean = true, | ||
TSelected = TFullSearchSchema, | ||
>(opts?: { | ||
strict?: TStrict | ||
track?: (search: TFullSearchSchema) => TSelected | ||
}): TStrict extends true ? TSelected : TSelected | undefined => { | ||
return useSearch({ ...opts, from: this.id }) | ||
} | ||
} | ||
export type AnyRootRoute = RootRoute<any, any, any> | ||
export type AnyRootRoute = RootRoute<any, any, any, any> | ||
export class RootRoute< | ||
TLoader = unknown, | ||
TSearchSchema extends AnySearchSchema = {}, | ||
TContext extends RouteContext = RouteContext, | ||
TRouterContext extends RouterContext = RouterContext, | ||
TRouterContext extends {} = {}, | ||
> extends Route< | ||
@@ -570,2 +703,3 @@ any, | ||
RootRouteId, | ||
TLoader, | ||
TSearchSchema, | ||
@@ -577,5 +711,7 @@ TSearchSchema, | ||
TRouterContext, | ||
TContext, | ||
MergeFromParent<TRouterContext, TContext>, | ||
TRouterContext | ||
MergeFromParent<TRouterContext, TContext>, | ||
TRouterContext, | ||
any, | ||
any | ||
> { | ||
@@ -588,2 +724,3 @@ constructor( | ||
'', | ||
TLoader, | ||
{}, | ||
@@ -609,6 +746,7 @@ TSearchSchema, | ||
static withRouterContext = <TRouterContext extends RouterContext>() => { | ||
static withRouterContext = <TRouterContext extends {}>() => { | ||
return < | ||
TLoader = unknown, | ||
TSearchSchema extends AnySearchSchema = {}, | ||
TContext extends RouterContext = RouterContext, | ||
TContext extends {} = {}, | ||
>( | ||
@@ -620,2 +758,3 @@ options?: Omit< | ||
'', | ||
TLoader, | ||
{}, | ||
@@ -632,3 +771,6 @@ TSearchSchema, | ||
>, | ||
) => new RootRoute<TSearchSchema, TContext, TRouterContext>(options as any) | ||
) => | ||
new RootRoute<TLoader, TSearchSchema, TContext, TRouterContext>( | ||
options as any, | ||
) | ||
} | ||
@@ -635,0 +777,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { AnyRootRoute, AnyRoute, RootRoute, Route } from './route' | ||
import { AnyRoute, Route } from './route' | ||
import { AnyPathParams, AnySearchSchema, RootRouteId } from './route' | ||
@@ -6,3 +6,3 @@ import { IsAny, MergeUnion, Values } from './utils' | ||
export interface AnyRoutesInfo { | ||
routeTree: AnyRootRoute | ||
routeTree: AnyRoute | ||
routeUnion: AnyRoute | ||
@@ -19,3 +19,3 @@ routesById: Record<string, AnyRoute> | ||
export interface DefaultRoutesInfo { | ||
routeTree: RootRoute | ||
routeTree: AnyRoute | ||
routeUnion: AnyRoute | ||
@@ -60,2 +60,3 @@ routesById: Record<string, Route> | ||
TRouteUnion['__types']['id'], // TId, | ||
TRouteUnion['__types']['loader'], // TId, | ||
MergeUnion<TRouteUnion['__types']['searchSchema']> & {}, // TSearchSchema, | ||
@@ -98,2 +99,3 @@ MergeUnion<TRouteUnion['__types']['fullSearchSchema']> & {}, // TFullSearchSchema, | ||
any, | ||
any, | ||
infer TChildren, | ||
@@ -100,0 +102,0 @@ any |
@@ -1,10 +0,10 @@ | ||
import { Store } from '@tanstack/store' | ||
import { Store } from '@tanstack/react-store' | ||
// | ||
import { GetFrameworkGeneric } from './frameworks' | ||
import { AnyRoute, AnySearchSchema, Route } from './route' | ||
import { RouteComponent } from './react' | ||
import { AnyRoute, Route } from './route' | ||
import { AnyRoutesInfo, DefaultRoutesInfo } from './routeInfo' | ||
import { AnyRouter, isRedirect, ParsedLocation, Router } from './router' | ||
import { Expand, pick, replaceEqualDeep } from './utils' | ||
import { replaceEqualDeep } from './utils' | ||
export interface RouteMatchStore< | ||
export interface RouteMatchState< | ||
TRoutesInfo extends AnyRoutesInfo = DefaultRoutesInfo, | ||
@@ -19,2 +19,3 @@ TRoute extends AnyRoute = Route, | ||
updatedAt: number | ||
loader: TRoute['__types']['loader'] | ||
} | ||
@@ -29,3 +30,3 @@ | ||
export interface PendingRouteMatchInfo { | ||
state: RouteMatchStore<any, any> | ||
state: RouteMatchState<any, any> | ||
routeContext: {} | ||
@@ -43,4 +44,4 @@ context: {} | ||
router!: Router<TRoutesInfo['routeTree'], TRoutesInfo> | ||
__store!: Store<RouteMatchStore<TRoutesInfo, TRoute>> | ||
state!: RouteMatchStore<TRoutesInfo, TRoute> | ||
__store!: Store<RouteMatchState<TRoutesInfo, TRoute>> | ||
state!: RouteMatchState<TRoutesInfo, TRoute> | ||
id!: string | ||
@@ -51,7 +52,15 @@ pathname!: string | ||
routeContext?: TRoute['__types']['routeContext'] | ||
context?: TRoute['__types']['context'] | ||
context!: TRoute['__types']['context'] | ||
component?: GetFrameworkGeneric<'Component'> | ||
errorComponent?: GetFrameworkGeneric<'ErrorComponent'> | ||
pendingComponent?: GetFrameworkGeneric<'Component'> | ||
component?: RouteComponent<{ | ||
useLoader: TRoute['useLoader'] | ||
useMatch: TRoute['useMatch'] | ||
useContext: TRoute['useContext'] | ||
useSearch: TRoute['useSearch'] | ||
}> | ||
errorComponent?: RouteComponent<{ | ||
error: Error | ||
info: { componentStack: string } | ||
}> | ||
pendingComponent?: RouteComponent | ||
abortController = new AbortController() | ||
@@ -84,3 +93,3 @@ parentMatch?: RouteMatch | ||
params: opts.params, | ||
__store: new Store<RouteMatchStore<TRoutesInfo, TRoute>>( | ||
__store: new Store<RouteMatchState<TRoutesInfo, TRoute>>( | ||
{ | ||
@@ -91,2 +100,3 @@ updatedAt: 0, | ||
status: 'idle', | ||
loader: undefined, | ||
}, | ||
@@ -106,5 +116,3 @@ { | ||
if (typeof this[type] !== 'function') { | ||
this[type] = component | ||
} | ||
this[type] = component as any | ||
}) | ||
@@ -122,3 +130,3 @@ | ||
return !!( | ||
this.route.options.onLoad || | ||
this.route.options.loader || | ||
componentTypes.some((d) => this.route.options[d]?.preload) | ||
@@ -175,3 +183,4 @@ ) | ||
const errorHandler = this.route.options.onValidateSearchError ?? this.route.options.onError | ||
const errorHandler = | ||
this.route.options.onValidateSearchError ?? this.route.options.onError | ||
errorHandler?.(err) | ||
@@ -200,13 +209,13 @@ const error = new (Error as any)('Invalid search params found', { | ||
const context = { | ||
...(this.parentMatch?.context ?? this.router?.options.context), | ||
...routeContext, | ||
} as any | ||
return { | ||
routeSearch, | ||
search, | ||
context, | ||
routeContext, | ||
} | ||
const context = { | ||
...(this.parentMatch?.context ?? this.router?.options.context), | ||
...routeContext, | ||
} as any | ||
return { | ||
routeSearch, | ||
search, | ||
context, | ||
routeContext, | ||
} | ||
} catch (err) { | ||
@@ -254,3 +263,2 @@ this.route.options.onError?.(err) | ||
// TODO: Should load promises be tracked based on location? | ||
this.__loadPromise = Promise.resolve().then(async () => { | ||
@@ -284,4 +292,4 @@ const loadId = '' + Date.now() + Math.random() | ||
if (this[type]?.preload) { | ||
this[type] = await this.router.options.loadComponent!(component) | ||
if (component?.preload) { | ||
await component.preload() | ||
} | ||
@@ -292,5 +300,5 @@ }), | ||
const dataPromise = Promise.resolve().then(() => { | ||
if (this.route.options.onLoad) { | ||
return this.route.options.onLoad({ | ||
const loaderPromise = Promise.resolve().then(() => { | ||
if (this.route.options.loader) { | ||
return this.route.options.loader({ | ||
params: this.params, | ||
@@ -309,3 +317,6 @@ routeSearch, | ||
try { | ||
await Promise.all([componentsPromise, dataPromise]) | ||
const [_, loader] = await Promise.all([ | ||
componentsPromise, | ||
loaderPromise, | ||
]) | ||
if ((latestPromise = checkLatest())) return await latestPromise | ||
@@ -317,2 +328,3 @@ this.__store.setState((s) => ({ | ||
updatedAt: Date.now(), | ||
loader, | ||
})) | ||
@@ -327,3 +339,4 @@ } catch (err) { | ||
const errorHandler = this.route.options.onLoadError ?? this.route.options.onError | ||
const errorHandler = | ||
this.route.options.onLoadError ?? this.route.options.onError | ||
try { | ||
@@ -330,0 +343,0 @@ errorHandler?.(err) |
@@ -1,2 +0,2 @@ | ||
import { Store } from '@tanstack/store' | ||
import { Store } from '@tanstack/react-store' | ||
import invariant from 'tiny-invariant' | ||
@@ -6,4 +6,2 @@ | ||
import { GetFrameworkGeneric } from './frameworks' | ||
import { | ||
@@ -33,5 +31,6 @@ LinkInfo, | ||
AnyContext, | ||
AnyRootRoute, | ||
} from './route' | ||
import { RoutesInfo, AnyRoutesInfo, RoutesById } from './routeInfo' | ||
import { AnyRouteMatch, RouteMatch, RouteMatchStore } from './routeMatch' | ||
import { AnyRouteMatch, RouteMatch, RouteMatchState } from './routeMatch' | ||
import { defaultParseSearch, defaultStringifySearch } from './searchParams' | ||
@@ -54,3 +53,12 @@ import { | ||
} from './history' | ||
import { RouteComponent } from './react' | ||
// | ||
declare global { | ||
interface Window { | ||
__DEHYDRATED__?: Record<string, any> | ||
} | ||
} | ||
export interface Register { | ||
@@ -60,3 +68,3 @@ // router: Router | ||
export type AnyRouter = Router<any, any> | ||
export type AnyRouter = Router<any, any, any> | ||
@@ -112,3 +120,6 @@ export type RegisteredRouter = Register extends { | ||
export interface RouterOptions<TRouteTree extends AnyRoute> { | ||
export interface RouterOptions< | ||
TRouteTree extends AnyRoute, | ||
TDehydrated extends Record<string, any>, | ||
> { | ||
history?: RouterHistory | ||
@@ -120,5 +131,8 @@ stringifySearch?: SearchSerializer | ||
defaultPreloadDelay?: number | ||
defaultComponent?: GetFrameworkGeneric<'Component'> | ||
defaultErrorComponent?: GetFrameworkGeneric<'ErrorComponent'> | ||
defaultPendingComponent?: GetFrameworkGeneric<'Component'> | ||
defaultComponent?: RouteComponent | ||
defaultErrorComponent?: RouteComponent<{ | ||
error: Error | ||
info: { componentStack: string } | ||
}> | ||
defaultPendingComponent?: RouteComponent | ||
defaultLoaderMaxAge?: number | ||
@@ -129,10 +143,9 @@ defaultLoaderGcMaxAge?: number | ||
basepath?: string | ||
Router?: (router: AnyRouter) => void | ||
createRoute?: (opts: { route: AnyRoute; router: AnyRouter }) => void | ||
loadComponent?: ( | ||
component: GetFrameworkGeneric<'Component'>, | ||
) => Promise<GetFrameworkGeneric<'Component'>> | ||
onRouteChange?: () => void | ||
fetchServerDataFn?: FetchServerDataFn | ||
context?: TRouteTree['__types']['routerContext'] | ||
Provider?: React.ComponentType<{ children: any }> | ||
dehydrate?: () => TDehydrated | ||
hydrate?: (dehydrated: TDehydrated) => void | ||
} | ||
@@ -145,3 +158,3 @@ | ||
export interface RouterStore< | ||
export interface RouterState< | ||
TRoutesInfo extends AnyRoutesInfo = AnyRoutesInfo, | ||
@@ -199,6 +212,6 @@ TState extends LocationState = LocationState, | ||
extends Pick< | ||
RouterStore, | ||
RouterState, | ||
'status' | 'latestLocation' | 'currentLocation' | 'lastUpdated' | ||
> { | ||
currentMatches: DehydratedRouteMatch[] | ||
// currentMatches: DehydratedRouteMatch[] | ||
} | ||
@@ -214,7 +227,5 @@ | ||
id: string | ||
state: Pick<RouteMatchStore<any, any>, 'status'> | ||
state: Pick<RouteMatchState<any, any>, 'status'> | ||
} | ||
export interface RouterContext {} | ||
export const defaultFetchServerDataFn: FetchServerDataFn = async ({ | ||
@@ -246,11 +257,12 @@ router, | ||
export type RouterConstructorOptions<TRouteTree extends AnyRoute> = Omit< | ||
RouterOptions<TRouteTree>, | ||
'context' | ||
> & | ||
export type RouterConstructorOptions< | ||
TRouteTree extends AnyRoute, | ||
TDehydrated extends Record<string, any>, | ||
> = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> & | ||
RouterContextOptions<TRouteTree> | ||
export class Router< | ||
TRouteTree extends AnyRoute = RootRoute, | ||
TRouteTree extends AnyRoute = AnyRoute, | ||
TRoutesInfo extends AnyRoutesInfo = RoutesInfo<TRouteTree>, | ||
TDehydrated extends Record<string, any> = Record<string, any>, | ||
> { | ||
@@ -264,8 +276,9 @@ types!: { | ||
options: PickAsRequired< | ||
RouterOptions<TRouteTree>, | ||
RouterOptions<TRouteTree, TDehydrated>, | ||
'stringifySearch' | 'parseSearch' | 'context' | ||
> | ||
context!: NonNullable<TRouteTree['__types']['routerContext']> | ||
history!: RouterHistory | ||
#unsubHistory?: () => void | ||
basepath: string | ||
basepath!: string | ||
// __location: Location<TRoutesInfo['fullSearchSchema']> | ||
@@ -278,8 +291,8 @@ routeTree!: RootRoute | ||
__store: Store<RouterStore<TRoutesInfo>> | ||
state: RouterStore<TRoutesInfo> | ||
__store: Store<RouterState<TRoutesInfo>> | ||
state: RouterState<TRoutesInfo> | ||
startedLoadingAt = Date.now() | ||
resolveNavigation: () => void = () => {} | ||
constructor(options?: RouterConstructorOptions<TRouteTree>) { | ||
constructor(options?: RouterConstructorOptions<TRouteTree, TDehydrated>) { | ||
this.options = { | ||
@@ -294,3 +307,3 @@ defaultPreloadDelay: 50, | ||
this.__store = new Store<RouterStore<TRoutesInfo>>( | ||
this.__store = new Store<RouterState<TRoutesInfo>>( | ||
getInitialRouterState(), | ||
@@ -304,9 +317,5 @@ { | ||
this.state = this.__store.state | ||
this.basepath = '' | ||
this.update(options) | ||
// Allow frameworks to hook into the router creation | ||
this.options.Router?.(this) | ||
const next = this.buildNext({ | ||
@@ -340,5 +349,24 @@ hash: true, | ||
update = (opts?: RouterOptions<TRouteTree>): this => { | ||
hydrate = async (__do_not_use_server_ctx?: any) => { | ||
let ctx = __do_not_use_server_ctx | ||
// Client hydrates from window | ||
if (typeof document !== 'undefined') { | ||
ctx = window.__DEHYDRATED__ | ||
invariant( | ||
ctx, | ||
'Expected to find a __DEHYDRATED__ property on window... but we did not. THIS IS VERY BAD', | ||
) | ||
} | ||
this.options.hydrate?.(ctx) | ||
return await this.load() | ||
} | ||
update = (opts?: RouterOptions<any, any>): this => { | ||
Object.assign(this.options, opts) | ||
this.context = this.options.context | ||
if ( | ||
@@ -377,3 +405,3 @@ !this.history || | ||
this.routesById = {} as any | ||
this.routeTree = this.#buildRouteTree(routeTree) | ||
this.routeTree = this.#buildRouteTree(routeTree) as RootRoute | ||
} | ||
@@ -384,3 +412,3 @@ | ||
buildNext = (opts: BuildNextOptions) => { | ||
buildNext = (opts: BuildNextOptions): ParsedLocation => { | ||
const next = this.#buildLocation(opts) | ||
@@ -692,3 +720,5 @@ | ||
const errorHandler = match.route.options.onBeforeLoadError ?? match.route.options.onError | ||
const errorHandler = | ||
match.route.options.onBeforeLoadError ?? | ||
match.route.options.onError | ||
try { | ||
@@ -977,50 +1007,51 @@ errorHandler?.(err) | ||
dehydrate = (): DehydratedRouter => { | ||
return { | ||
state: { | ||
...pick(this.state, [ | ||
'latestLocation', | ||
'currentLocation', | ||
'status', | ||
'lastUpdated', | ||
]), | ||
currentMatches: this.state.currentMatches.map((match) => ({ | ||
id: match.id, | ||
state: { | ||
status: match.state.status, | ||
}, | ||
})), | ||
}, | ||
} | ||
} | ||
// dehydrate = (): DehydratedRouter => { | ||
// return { | ||
// state: { | ||
// ...pick(this.state, [ | ||
// 'latestLocation', | ||
// 'currentLocation', | ||
// 'status', | ||
// 'lastUpdated', | ||
// ]), | ||
// // currentMatches: this.state.currentMatches.map((match) => ({ | ||
// // id: match.id, | ||
// // state: { | ||
// // status: match.state.status, | ||
// // // status: 'idle', | ||
// // }, | ||
// // })), | ||
// }, | ||
// } | ||
// } | ||
hydrate = (dehydratedRouter: DehydratedRouter) => { | ||
this.__store.setState((s) => { | ||
// Match the routes | ||
const currentMatches = this.matchRoutes( | ||
dehydratedRouter.state.latestLocation.pathname, | ||
{ | ||
strictParseParams: true, | ||
}, | ||
) | ||
// hydrate = (dehydratedRouter: DehydratedRouter) => { | ||
// this.__store.setState((s) => { | ||
// // Match the routes | ||
// // const currentMatches = this.matchRoutes( | ||
// // dehydratedRouter.state.latestLocation.pathname, | ||
// // { | ||
// // strictParseParams: true, | ||
// // }, | ||
// // ) | ||
currentMatches.forEach((match, index) => { | ||
const dehydratedMatch = dehydratedRouter.state.currentMatches[index] | ||
invariant( | ||
dehydratedMatch && dehydratedMatch.id === match.id, | ||
'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬', | ||
) | ||
match.__store.setState((s) => ({ | ||
...s, | ||
...dehydratedMatch.state, | ||
})) | ||
}) | ||
// // currentMatches.forEach((match, index) => { | ||
// // const dehydratedMatch = dehydratedRouter.state.currentMatches[index] | ||
// // invariant( | ||
// // dehydratedMatch && dehydratedMatch.id === match.id, | ||
// // 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬', | ||
// // ) | ||
// // match.__store.setState((s) => ({ | ||
// // ...s, | ||
// // ...dehydratedMatch.state, | ||
// // })) | ||
// // }) | ||
return { | ||
...s, | ||
...dehydratedRouter.state, | ||
currentMatches, | ||
} | ||
}) | ||
} | ||
// return { | ||
// ...s, | ||
// ...dehydratedRouter.state, | ||
// // currentMatches, | ||
// } | ||
// }) | ||
// } | ||
@@ -1272,3 +1303,3 @@ #buildRouteTree = (routeTree: AnyRoute) => { | ||
function getInitialRouterState(): RouterStore<any, any> { | ||
function getInitialRouterState(): RouterState<any, any> { | ||
return { | ||
@@ -1275,0 +1306,0 @@ status: 'idle', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1286435
45
12230
6
2
+ Added@tanstack/react-store@0.0.1-beta.84(transitive)
+ Added@tanstack/store@0.0.1-beta.84(transitive)
+ Addedjs-tokens@4.0.0(transitive)
+ Addedloose-envify@1.4.0(transitive)
+ Addedreact@18.3.1(transitive)
+ Addedreact-dom@18.3.1(transitive)
+ Addedscheduler@0.23.2(transitive)
+ Addeduse-sync-external-store@1.2.2(transitive)
- Removed@tanstack/store@0.0.1-beta.81
- Removed@tanstack/store@0.0.1-beta.81(transitive)