@solidjs/router
Advanced tools
Comparing version 0.13.2 to 0.13.3
@@ -107,19 +107,14 @@ import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js"; | ||
let data; | ||
let custom; | ||
let keys; | ||
let invalidateKeys; | ||
let flightKeys; | ||
if (response instanceof Response) { | ||
if (response.headers.has("X-Revalidate")) | ||
keys = invalidateKeys = response.headers.get("X-Revalidate").split(","); | ||
keys = response.headers.get("X-Revalidate").split(","); | ||
if (response.customBody) { | ||
data = await response.customBody(); | ||
data = custom = await response.customBody(); | ||
if (response.headers.has("X-Single-Flight")) { | ||
keys || (keys = []); | ||
invalidateKeys || (invalidateKeys = []); | ||
Object.keys(data).forEach(key => { | ||
if (key === "_$value") | ||
return; | ||
keys.push(key); | ||
cache.set(key, data[key]); | ||
}); | ||
data = data._$value; | ||
delete custom._$value; | ||
flightKeys = Object.keys(custom); | ||
} | ||
@@ -142,3 +137,5 @@ } | ||
// invalidate | ||
cacheKeyOp(invalidateKeys, entry => (entry[0] = 0)); | ||
cacheKeyOp(keys, entry => (entry[0] = 0)); | ||
// set cache | ||
flightKeys && flightKeys.forEach(k => cache.set(k, custom[k])); | ||
// trigger revalidation | ||
@@ -145,0 +142,0 @@ await revalidate(keys, false); |
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js"; | ||
import { getRequestEvent, isServer } from "solid-js/web"; | ||
import { useNavigate, getIntent } from "../routing.js"; | ||
import { useNavigate, getIntent, getInLoadFn } from "../routing.js"; | ||
const LocationHeader = "Location"; | ||
@@ -50,2 +50,3 @@ const PRELOAD_TIMEOUT = 5000; | ||
const intent = getIntent(); | ||
const inLoadFn = getInLoadFn(); | ||
const owner = getOwner(); | ||
@@ -90,3 +91,3 @@ const navigate = owner ? useNavigate() : undefined; | ||
let res = cached[1]; | ||
if (intent !== "preload") { | ||
if (!inLoadFn) { | ||
res = | ||
@@ -98,2 +99,4 @@ "then" in cached[1] | ||
} | ||
else | ||
"then" in res && res.catch(() => { }); | ||
return res; | ||
@@ -123,3 +126,3 @@ } | ||
} | ||
if (intent !== "preload") { | ||
if (!inLoadFn) { | ||
res = | ||
@@ -130,2 +133,4 @@ "then" in res | ||
} | ||
else | ||
"then" in res && res.catch(() => { }); | ||
// serialize on server | ||
@@ -132,0 +137,0 @@ if (isServer && |
import type { RouterContext } from "../types.js"; | ||
export declare function setupNativeEvents(preload?: boolean, explicitLinks?: boolean, actionBase?: string): (router: RouterContext) => void; | ||
export declare function setupNativeEvents(preload?: boolean, explicitLinks?: boolean, actionBase?: string, transformUrl?: (url: string) => string): (router: RouterContext) => void; |
@@ -5,3 +5,3 @@ import { delegateEvents } from "solid-js/web"; | ||
import { mockBase } from "../utils.js"; | ||
export function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") { | ||
export function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server", transformUrl) { | ||
return (router) => { | ||
@@ -61,2 +61,5 @@ const basePath = router.base.path(); | ||
const [a, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (!preloadTimeout[url.pathname]) | ||
@@ -70,2 +73,5 @@ router.preloadRoute(url, a.getAttribute("preload") !== "false"); | ||
const [a, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (preloadTimeout[url.pathname]) | ||
@@ -83,2 +89,5 @@ return; | ||
const [, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (preloadTimeout[url.pathname]) { | ||
@@ -85,0 +94,0 @@ clearTimeout(preloadTimeout[url.pathname]); |
export * from "./routers/index.js"; | ||
export * from "./components.jsx"; | ||
export * from "./lifecycle.js"; | ||
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js"; | ||
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js"; | ||
export { mergeSearchString as _mergeSearchString } from "./utils.js"; | ||
export * from "./data/index.js"; | ||
export type { Location, LocationChange, NavigateOptions, Navigator, OutputMatch, Params, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types.js"; |
@@ -259,2 +259,3 @@ import { isServer, getRequestEvent, createComponent as createComponent$1, memo, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web'; | ||
}; | ||
const useCurrentMatches = () => useRouter().matches(); | ||
const useParams = () => useRouter().params; | ||
@@ -410,2 +411,9 @@ const useSearchParams = () => { | ||
} | ||
let inLoadFn = false; | ||
function getInLoadFn() { | ||
return inLoadFn; | ||
} | ||
function setInLoadFn(value) { | ||
inLoadFn = value; | ||
} | ||
function createRouterContext(integration, branches, getContext, options = {}) { | ||
@@ -443,3 +451,8 @@ const { | ||
const submissions = createSignal(isServer ? initFromFlash() : []); | ||
const matches = createMemo(() => getRouteMatches(branches(), location.pathname)); | ||
const matches = createMemo(() => { | ||
if (typeof options.transformUrl === "function") { | ||
return getRouteMatches(branches(), options.transformUrl(location.pathname)); | ||
} | ||
return getRouteMatches(branches(), location.pathname); | ||
}); | ||
const params = createMemoObject(() => { | ||
@@ -468,13 +481,11 @@ const m = matches(); | ||
untrack(() => { | ||
if (value !== reference()) { | ||
start(() => { | ||
intent = "native"; | ||
setReference(value); | ||
setState(state); | ||
resetErrorBoundaries(); | ||
submissions[1]([]); | ||
}).then(() => { | ||
intent = undefined; | ||
}); | ||
} | ||
start(() => { | ||
intent = "native"; | ||
if (value !== reference()) setReference(value); | ||
setState(state); | ||
resetErrorBoundaries(); | ||
submissions[1]([]); | ||
}).then(() => { | ||
intent = undefined; | ||
}); | ||
}); | ||
@@ -597,2 +608,3 @@ }); | ||
} = route; | ||
inLoadFn = true; | ||
preloadData && load && runWithOwner(getContext(), () => load({ | ||
@@ -610,2 +622,3 @@ params, | ||
})); | ||
inLoadFn = false; | ||
} | ||
@@ -632,2 +645,3 @@ intent = prevIntent; | ||
component && component.preload && component.preload(); | ||
inLoadFn = true; | ||
const data = load ? load({ | ||
@@ -638,2 +652,3 @@ params, | ||
}) : undefined; | ||
inLoadFn = false; | ||
const route = { | ||
@@ -667,3 +682,4 @@ parent, | ||
base, | ||
singleFlight: props.singleFlight | ||
singleFlight: props.singleFlight, | ||
transformUrl: props.transformUrl | ||
}); | ||
@@ -697,7 +713,11 @@ router.create && router.create(routerState); | ||
const params = props.routerState.params; | ||
const data = createMemo(() => props.load && untrack(() => props.load({ | ||
params, | ||
location, | ||
intent: "preload" | ||
}))); | ||
const data = createMemo(() => props.load && untrack(() => { | ||
setInLoadFn(true); | ||
props.load({ | ||
params, | ||
location, | ||
intent: getIntent() || "initial" | ||
}); | ||
setInLoadFn(false); | ||
})); | ||
return createComponent$1(Show, { | ||
@@ -834,3 +854,3 @@ get when() { | ||
const signal = intercept(createSignal(wrap(config.get()), { | ||
equals: (a, b) => a.value === b.value | ||
equals: (a, b) => a.value === b.value && a.state === b.state | ||
}), undefined, next => { | ||
@@ -870,4 +890,5 @@ !ignore && config.set(next); | ||
let e; | ||
const url = props.url || (e = getRequestEvent()) && getPath(e.request.url) || ""; | ||
const obj = { | ||
value: props.url || (e = getRequestEvent()) && getPath(e.request.url) || "" | ||
value: props.transformUrl ? props.transformUrl(url) : url | ||
}; | ||
@@ -922,2 +943,3 @@ return createRouterComponent({ | ||
const intent = getIntent(); | ||
const inLoadFn = getInLoadFn(); | ||
const owner = getOwner(); | ||
@@ -956,6 +978,6 @@ const navigate = owner ? useNavigate() : undefined; | ||
let res = cached[1]; | ||
if (intent !== "preload") { | ||
if (!inLoadFn) { | ||
res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]); | ||
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version | ||
} | ||
} else "then" in res && res.catch(() => {}); | ||
return res; | ||
@@ -982,5 +1004,5 @@ } | ||
} | ||
if (intent !== "preload") { | ||
if (!inLoadFn) { | ||
res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res); | ||
} | ||
} else "then" in res && res.catch(() => {}); | ||
// serialize on server | ||
@@ -1150,17 +1172,13 @@ if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) { | ||
let data; | ||
let custom; | ||
let keys; | ||
let invalidateKeys; | ||
let flightKeys; | ||
if (response instanceof Response) { | ||
if (response.headers.has("X-Revalidate")) keys = invalidateKeys = response.headers.get("X-Revalidate").split(","); | ||
if (response.headers.has("X-Revalidate")) keys = response.headers.get("X-Revalidate").split(","); | ||
if (response.customBody) { | ||
data = await response.customBody(); | ||
data = custom = await response.customBody(); | ||
if (response.headers.has("X-Single-Flight")) { | ||
keys || (keys = []); | ||
invalidateKeys || (invalidateKeys = []); | ||
Object.keys(data).forEach(key => { | ||
if (key === "_$value") return; | ||
keys.push(key); | ||
cache.set(key, data[key]); | ||
}); | ||
data = data._$value; | ||
delete custom._$value; | ||
flightKeys = Object.keys(custom); | ||
} | ||
@@ -1180,3 +1198,5 @@ } | ||
// invalidate | ||
cacheKeyOp(invalidateKeys, entry => entry[0] = 0); | ||
cacheKeyOp(keys, entry => entry[0] = 0); | ||
// set cache | ||
flightKeys && flightKeys.forEach(k => cache.set(k, custom[k])); | ||
// trigger revalidation | ||
@@ -1189,3 +1209,3 @@ await revalidate(keys, false); | ||
function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") { | ||
function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server", transformUrl) { | ||
return router => { | ||
@@ -1230,2 +1250,5 @@ const basePath = router.base.path(); | ||
const [a, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (!preloadTimeout[url.pathname]) router.preloadRoute(url, a.getAttribute("preload") !== "false"); | ||
@@ -1237,2 +1260,5 @@ } | ||
const [a, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (preloadTimeout[url.pathname]) return; | ||
@@ -1248,2 +1274,5 @@ preloadTimeout[url.pathname] = setTimeout(() => { | ||
const [, url] = res; | ||
if (typeof transformUrl === "function") { | ||
url.pathname = transformUrl(url.pathname); | ||
} | ||
if (preloadTimeout[url.pathname]) { | ||
@@ -1302,6 +1331,9 @@ clearTimeout(preloadTimeout[url.pathname]); | ||
if (isServer) return StaticRouter(props); | ||
const getSource = () => ({ | ||
value: window.location.pathname + window.location.search + window.location.hash, | ||
state: window.history.state | ||
}); | ||
const getSource = () => { | ||
const url = window.location.pathname + window.location.search; | ||
return { | ||
value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash, | ||
state: window.history.state | ||
}; | ||
}; | ||
const beforeLeave = createBeforeLeave(); | ||
@@ -1334,3 +1366,3 @@ return createRouter({ | ||
})), | ||
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase), | ||
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase, props.transformUrl), | ||
utils: { | ||
@@ -1633,2 +1665,2 @@ go: delta => window.history.go(delta), | ||
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions }; | ||
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions }; |
export * from "./routers/index.js"; | ||
export * from "./components.jsx"; | ||
export * from "./lifecycle.js"; | ||
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js"; | ||
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js"; | ||
export { mergeSearchString as _mergeSearchString } from "./utils.js"; | ||
export * from "./data/index.js"; |
@@ -12,2 +12,3 @@ import type { Component, JSX } from "solid-js"; | ||
children?: JSX.Element | RouteDefinition | RouteDefinition[]; | ||
transformUrl?: (url: string) => string; | ||
}; | ||
@@ -14,0 +15,0 @@ export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element; |
/*@refresh skip*/ | ||
import { getRequestEvent, isServer } from "solid-js/web"; | ||
import { children, createMemo, createRoot, getOwner, mergeProps, on, Show, untrack } from "solid-js"; | ||
import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj } from "../routing.js"; | ||
import { createBranches, createRouteContext, createRouterContext, getIntent, getRouteMatches, RouteContextObj, RouterContextObj, setInLoadFn } from "../routing.js"; | ||
export const createRouterComponent = (router) => (props) => { | ||
@@ -12,3 +12,4 @@ const { base } = props; | ||
base, | ||
singleFlight: props.singleFlight | ||
singleFlight: props.singleFlight, | ||
transformUrl: props.transformUrl, | ||
}); | ||
@@ -26,3 +27,8 @@ router.create && router.create(routerState); | ||
const params = props.routerState.params; | ||
const data = createMemo(() => props.load && untrack(() => props.load({ params, location, intent: "preload" }))); | ||
const data = createMemo(() => props.load && | ||
untrack(() => { | ||
setInLoadFn(true); | ||
props.load({ params, location, intent: getIntent() || "initial" }); | ||
setInLoadFn(false); | ||
})); | ||
return (<Show when={props.root} keyed fallback={props.children}> | ||
@@ -29,0 +35,0 @@ {Root => (<Root params={params} location={location} data={data()}> |
@@ -21,3 +21,5 @@ import { createSignal, onCleanup } from "solid-js"; | ||
const wrap = (value) => (typeof value === "string" ? { value } : value); | ||
const signal = intercept(createSignal(wrap(config.get()), { equals: (a, b) => a.value === b.value }), undefined, next => { | ||
const signal = intercept(createSignal(wrap(config.get()), { | ||
equals: (a, b) => a.value === b.value && a.state === b.state | ||
}), undefined, next => { | ||
!ignore && config.set(next); | ||
@@ -24,0 +26,0 @@ return next; |
@@ -9,6 +9,9 @@ import { isServer } from "solid-js/web"; | ||
return StaticRouter(props); | ||
const getSource = () => ({ | ||
value: window.location.pathname + window.location.search + window.location.hash, | ||
state: window.history.state | ||
}); | ||
const getSource = () => { | ||
const url = window.location.pathname + window.location.search; | ||
return { | ||
value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash, | ||
state: window.history.state | ||
}; | ||
}; | ||
const beforeLeave = createBeforeLeave(); | ||
@@ -36,3 +39,3 @@ return createRouter({ | ||
})), | ||
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase), | ||
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase, props.transformUrl), | ||
utils: { | ||
@@ -39,0 +42,0 @@ go: delta => window.history.go(delta), |
@@ -9,4 +9,5 @@ import { getRequestEvent } from "solid-js/web"; | ||
let e; | ||
const url = props.url || ((e = getRequestEvent()) && getPath(e.request.url)) || ""; | ||
const obj = { | ||
value: props.url || ((e = getRequestEvent()) && getPath(e.request.url)) || "" | ||
value: props.transformUrl ? props.transformUrl(url) : url, | ||
}; | ||
@@ -13,0 +14,0 @@ return createRouterComponent({ |
@@ -13,2 +13,3 @@ import { JSX, Accessor } from "solid-js"; | ||
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S> | undefined) => Accessor<import("./types.js").PathMatch | undefined>; | ||
export declare const useCurrentMatches: () => RouteMatch[]; | ||
export declare const useParams: <T extends Params>() => T; | ||
@@ -23,6 +24,9 @@ export declare const useSearchParams: <T extends Params>() => [Partial<T>, (params: SetParams, options?: Partial<NavigateOptions>) => void]; | ||
export declare function getIntent(): Intent | undefined; | ||
export declare function getInLoadFn(): boolean; | ||
export declare function setInLoadFn(value: boolean): void; | ||
export declare function createRouterContext(integration: RouterIntegration, branches: () => Branch[], getContext?: () => any, options?: { | ||
base?: string; | ||
singleFlight?: boolean; | ||
transformUrl?: (url: string) => string; | ||
}): RouterContext; | ||
export declare function createRouteContext(router: RouterContext, parent: RouteContext, outlet: () => JSX.Element, match: () => RouteMatch): RouteContext; |
@@ -37,2 +37,3 @@ import { runWithOwner } from "solid-js"; | ||
}; | ||
export const useCurrentMatches = () => useRouter().matches(); | ||
export const useParams = () => useRouter().params; | ||
@@ -188,2 +189,9 @@ export const useSearchParams = () => { | ||
} | ||
let inLoadFn = false; | ||
export function getInLoadFn() { | ||
return inLoadFn; | ||
} | ||
export function setInLoadFn(value) { | ||
inLoadFn = value; | ||
} | ||
export function createRouterContext(integration, branches, getContext, options = {}) { | ||
@@ -216,3 +224,8 @@ const { signal: [source, setSource], utils = {} } = integration; | ||
const submissions = createSignal(isServer ? initFromFlash() : []); | ||
const matches = createMemo(() => getRouteMatches(branches(), location.pathname)); | ||
const matches = createMemo(() => { | ||
if (typeof options.transformUrl === "function") { | ||
return getRouteMatches(branches(), options.transformUrl(location.pathname)); | ||
} | ||
return getRouteMatches(branches(), location.pathname); | ||
}); | ||
const params = createMemoObject(() => { | ||
@@ -238,13 +251,12 @@ const m = matches(); | ||
untrack(() => { | ||
if (value !== reference()) { | ||
start(() => { | ||
intent = "native"; | ||
start(() => { | ||
intent = "native"; | ||
if (value !== reference()) | ||
setReference(value); | ||
setState(state); | ||
resetErrorBoundaries(); | ||
submissions[1]([]); | ||
}).then(() => { | ||
intent = undefined; | ||
}); | ||
} | ||
setState(state); | ||
resetErrorBoundaries(); | ||
submissions[1]([]); | ||
}).then(() => { | ||
intent = undefined; | ||
}); | ||
}); | ||
@@ -350,2 +362,3 @@ }); | ||
const { load } = route; | ||
inLoadFn = true; | ||
preloadData && | ||
@@ -365,2 +378,3 @@ load && | ||
})); | ||
inLoadFn = false; | ||
} | ||
@@ -383,3 +397,5 @@ intent = prevIntent; | ||
component.preload(); | ||
inLoadFn = true; | ||
const data = load ? load({ params, location, intent: intent || "initial" }) : undefined; | ||
inLoadFn = false; | ||
const route = { | ||
@@ -386,0 +402,0 @@ parent, |
@@ -9,3 +9,3 @@ { | ||
"license": "MIT", | ||
"version": "0.13.2", | ||
"version": "0.13.3", | ||
"homepage": "https://github.com/solidjs/solid-router#readme", | ||
@@ -12,0 +12,0 @@ "repository": { |
@@ -33,2 +33,3 @@ <p> | ||
- [useMatch](#usematch) | ||
- [useCurrentMatches](#useCurrentMatches) | ||
- [useBeforeLeave](#usebeforeleave) | ||
@@ -433,3 +434,3 @@ - [SPAs in Deployed Environments](#spas-in-deployed-environments) | ||
```jsx | ||
const getUser = cache((id) => { | ||
const getUser = cache(async (id) => { | ||
return (await fetch(`/api/users${id}`)).json() | ||
@@ -865,2 +866,12 @@ }, "users") // used as cache key + serialized arguments | ||
### useCurrentMatches | ||
`useCurrentMatches` returns all the matches for the current matched route. Useful for getting all the route information. | ||
For example if you stored breadcrumbs on your route definition you could retrieve them like so: | ||
```js | ||
const matches = useCurrentMatches(); | ||
const breadcrumbs = createMemo(() => matches.map(m => m.route.info.breadcrumb)) | ||
``` | ||
### useBeforeLeave | ||
@@ -867,0 +878,0 @@ |
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
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
167175
3772
979