lit-navigation-router 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n *\n * Modifications Copyright 2026 VanLandingham Labs, same license. See NOTICE.md.\n */\n\n/// <reference types=\"urlpattern-polyfill\" />\n\nimport type {ReactiveController, ReactiveControllerHost} from 'lit';\n\nexport interface BaseRouteConfig {\n name?: string | undefined;\n render?: (params: {[key: string]: string | undefined}) => unknown;\n enter?: (params: {\n [key: string]: string | undefined;\n }) => Promise<boolean> | boolean;\n}\n\n/**\n * A RouteConfig that matches against a `path` string. `path` must be a\n * [`URLPattern` compatible pathname pattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/pathname).\n */\nexport interface PathRouteConfig extends BaseRouteConfig {\n path: string;\n}\n\n/**\n * A RouteConfig that matches against a given [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern)\n *\n * While `URLPattern` can match against protocols, hostnames, and ports,\n * routes will only be checked for matches if they're part of the current\n * origin. This means the pattern is limited to checking `pathname`, `search`\n * and `hash`.\n */\nexport interface URLPatternRouteConfig extends BaseRouteConfig {\n pattern: URLPatternLike;\n}\n\n/**\n * The part of `URLPattern` this router uses.\n *\n * Declared structurally rather than referencing the global so the emitted\n * `.d.ts` is self-contained: the `/// <reference types=\"urlpattern-polyfill\" />`\n * above is not carried into declaration output, and `URLPattern` is not in\n * TypeScript's bundled `lib.dom`, so a published package typed against the\n * global fails a consumer build with `TS2304: Cannot find name 'URLPattern'`.\n * A real `URLPattern` satisfies this, so passing one still type-checks.\n */\nexport interface URLPatternLike {\n /**\n * The pathname pattern string, as `URLPattern.prototype.pathname` returns\n * it. Read to tell a trailing wildcard from any other positional group —\n * the groups object alone cannot (see `tailOf`).\n */\n readonly pathname: string;\n /**\n * The hash pattern string. `'*'` means the route places no constraint on the\n * fragment, which is what `URLPattern` fills in for any component the caller\n * omits. `Router` reads this to decide whether a fragment-only navigation is\n * its business or the browser's.\n */\n readonly hash: string;\n test(input: RouteLocation): boolean;\n exec(input: RouteLocation): {\n pathname: {groups: {[key: string]: string | undefined}};\n search: {groups: {[key: string]: string | undefined}};\n hash: {groups: {[key: string]: string | undefined}};\n } | null;\n}\n\n/**\n * The parts of a location this router matches against, split out of a path\n * string by `parseLocation`.\n *\n * `search` and `hash` carry no leading `?` or `#`. `URLPattern` canonicalises\n * either form away on an init input, but only for a real `URLPattern` — the\n * structural `URLPatternLike` above admits other implementations, so the\n * delimiters are stripped here rather than left to the pattern.\n */\nexport interface RouteLocation {\n pathname: string;\n search: string;\n hash: string;\n}\n\n/**\n * Splits `path` into the components a pattern is matched against.\n *\n * Deliberately not `new URL(path, origin)`: a nested controller's path is a\n * *tail* — a bare relative segment like `abc` — which `URL` would resolve\n * against the current directory and mangle.\n */\nconst parseLocation = (path: string): RouteLocation => {\n const hashIndex = path.indexOf('#');\n const hash = hashIndex === -1 ? '' : path.slice(hashIndex + 1);\n const beforeHash = hashIndex === -1 ? path : path.slice(0, hashIndex);\n const searchIndex = beforeHash.indexOf('?');\n return {\n pathname: searchIndex === -1 ? beforeHash : beforeHash.slice(0, searchIndex),\n search: searchIndex === -1 ? '' : beforeHash.slice(searchIndex + 1),\n hash,\n };\n};\n\n/** Re-attaches `search` and `hash` to a pathname. Inverse of `parseLocation`. */\nconst formatLocation = (\n pathname: string,\n {search, hash}: {search: string; hash: string}\n): string =>\n pathname + (search === '' ? '' : `?${search}`) + (hash === '' ? '' : `#${hash}`);\n\n/**\n * A description of a route, which path or pattern to match against, and a\n * render() callback used to render a match to the outlet.\n */\nexport type RouteConfig = PathRouteConfig | URLPatternRouteConfig;\n\n// A cache of URLPatterns created for PathRouteConfig.\n// Rather than converting all given RoutConfigs to URLPatternRouteConfig, this\n// lets us make `routes` mutable so users can add new PathRouteConfigs\n// dynamically.\nconst patternCache = new WeakMap<PathRouteConfig, URLPatternLike>();\n\nconst isPatternConfig = (route: RouteConfig): route is URLPatternRouteConfig =>\n (route as URLPatternRouteConfig).pattern !== undefined;\n\nconst getPattern = (route: RouteConfig): URLPatternLike => {\n if (isPatternConfig(route)) {\n return route.pattern;\n }\n let pattern = patternCache.get(route);\n if (pattern === undefined) {\n patternCache.set(route, (pattern = new URLPattern({pathname: route.path})));\n }\n return pattern;\n};\n\n/**\n * Matches a pathname pattern that ends in a wildcard, in the forms\n * `URLPattern.prototype.pathname` regenerates one: a bare `*` — which a\n * trailing `(.*)` also normalises to — or `{*}`, which the generator emits for\n * a wildcard after a modified group, e.g. `/docs{/}?*`. Either may be\n * optional (`*?`). Not a wildcard: an escaped `\\*`, or a `*` that is the\n * modifier on a group (`(\\d+)*`, `{/}*`) or on a named param (`:rest*`).\n * Those exclusions matter when an earlier positional group exists —\n * `/x/(\\d+)/:rest*` — since that group would otherwise be taken for the tail.\n */\nconst TRAILING_WILDCARD = /(?:(?<![\\\\)}]|:[\\w$]+)\\*|\\{\\*\\})\\??$/;\n\n/**\n * The tail of a match — what a trailing wildcard (`/foo/*`) captured — or\n * undefined when the pattern has none.\n *\n * Decided from the pattern, not from the groups object: an unnamed regex group\n * (`/post/(\\d+)`) and a wildcard that is not last (`/foo/*` followed by\n * `/bar`) are keyed by index exactly as a tail is, and reading either as one\n * truncated `link()` and handed a child the wrong segment. When a trailing\n * wildcard is present it is the last group in the pattern, so its key is the\n * highest positional index.\n */\nconst tailOf = (\n route: RouteConfig,\n params: {[key: string]: string | undefined}\n): string | undefined => {\n if (!TRAILING_WILDCARD.test(getPattern(route).pathname)) {\n return undefined;\n }\n let tailIndex = -1;\n for (const key of Object.keys(params)) {\n // Numeric, not lexicographic: '9' sorts above '10' as a string, so a\n // pattern with eleven or more wildcards picked group 9 as its tail.\n if (/^\\d+$/.test(key) && Number(key) > tailIndex) {\n tailIndex = Number(key);\n }\n }\n return tailIndex < 0 ? undefined : params[String(tailIndex)];\n};\n\n/**\n * A reactive controller that performs location-based routing using a\n * configuration of URL patterns and associated render callbacks.\n */\nexport class Routes implements ReactiveController {\n private readonly _host: ReactiveControllerHost & HTMLElement;\n\n /*\n * The currently installed set of routes in precedence order.\n *\n * This array is mutable. To dynamically add a new route you can write:\n *\n * ```ts\n * this._routes.routes.push({\n * path: '/foo',\n * render: () => html`<p>Foo</p>`,\n * });\n * ```\n *\n * Mutating this property does not trigger any route transitions. If the\n * changes may result is a different route matching for the current path, you\n * must instigate a route update with `goto()`.\n */\n routes: Array<RouteConfig> = [];\n\n /**\n * A default fallback route which will always be matched if none of the\n * {@link routes} match. Behaves like a `/*` route: `params[0]` is the whole\n * pathname minus its leading slash, and is handed to child controllers as\n * their tail. A nested controller's own pathname is a tail, with no leading\n * slash; the fallback accepts that too.\n */\n fallback?: BaseRouteConfig;\n\n /*\n * The current set of child Routes controllers. These are connected via\n * the routes-connected event.\n */\n private readonly _childRoutes: Array<Routes> = [];\n\n private _parentRoutes: Routes | undefined;\n\n /*\n * State related to the current matching route.\n *\n * We keep this so that consuming code can access current parameters, and so\n * that we can propagate tail matches to child routes if they are added after\n * navigation / matching.\n */\n /** Monotonic goto counter; see the last-goto-wins note in goto(). */\n private _gotoSeq = 0;\n\n private _currentPathname: string | undefined;\n private _currentTail: string | undefined;\n /**\n * The search and hash of the current location.\n *\n * Ambient rather than tailed: only the pathname nests, so a child controller\n * is handed the parent's tail as its pathname but the *same* search and\n * hash. There is no meaningful way to split a fragment across a route tree.\n */\n private _currentSearch = '';\n private _currentHash = '';\n private _currentRoute: RouteConfig | undefined;\n private _currentParams: {\n [key: string]: string | undefined;\n } = {};\n\n /**\n * Callback to call when this controller is disconnected.\n *\n * It's critical to call this immediately in hostDisconnected so that this\n * controller instance doesn't receive a tail match meant for another route.\n */\n // TODO (justinfagnani): Do we need this now that we have a direct reference\n // to the parent? We can call `this._parentRoutes.disconnect(this)`.\n private _onDisconnect: (() => void) | undefined;\n\n constructor(\n host: ReactiveControllerHost & HTMLElement,\n routes: Array<RouteConfig>,\n options?: {fallback?: BaseRouteConfig}\n ) {\n (this._host = host).addController(this);\n this.routes = [...routes];\n this.fallback = options?.fallback;\n }\n\n /**\n * Returns a URL string of the current route, including parent routes,\n * optionally replacing the local path with `pathname`.\n */\n link(pathname?: string): string {\n if (pathname?.startsWith('/')) {\n return pathname;\n }\n if (pathname?.startsWith('.')) {\n throw new Error('Not implemented');\n }\n pathname ??= this._currentPathname;\n return (this._parentRoutes?.link() ?? '') + pathname;\n }\n\n /**\n * Navigates this routes controller to `pathname`.\n *\n * This does not navigate parent routes, so it isn't (yet) a general page\n * navigation API. It does navigate child routes if pathname matches a\n * pattern with a tail wildcard pattern (`/*`).\n *\n * Pass `options.signal` to make the navigation abandonable. `enter()` is\n * awaited, so a second `goto()` can start — and finish — while the first is\n * still resolving its route; without a signal the slower one commits last\n * and the outlet ends up on a route the URL has already left. `Router`\n * threads `NavigateEvent.signal` through for exactly this reason.\n */\n async goto(path: string, options?: {signal?: AbortSignal}) {\n // TODO (justinfagnani): handle absolute vs relative paths separately.\n\n const location = parseLocation(path);\n const {pathname} = location;\n\n // Last-goto-wins, per controller. The navigation signal alone is not\n // enough: a child controller mounts as a *result* of its parent's render,\n // so its first goto() comes from `_onRoutesConnected` — after the parent's\n // navigation has already finished, and therefore with a signal that will\n // never abort. Without this counter a slow first child load commits over a\n // newer one. This also keeps `Routes` correct when used on its own, with\n // no `Router` and no Navigation API in the picture.\n const seq = ++this._gotoSeq;\n let tail: string | undefined;\n\n if (this.routes.length === 0 && this.fallback === undefined) {\n // If a routes controller has none of its own routes it acts like it has\n // one route of `/*` so that it passes the whole pathname as a tail\n // match.\n tail = pathname;\n this._currentPathname = '';\n // Simulate a tail group with the whole pathname\n this._currentParams = {0: tail};\n } else {\n const match = this._match(location);\n if (match === undefined) {\n throw new Error(`No route found for ${path}`);\n }\n const {route, params} = match;\n tail = match.tail;\n if (typeof route.enter === 'function') {\n const success = await route.enter(params);\n // If enter() returns false, cancel this navigation\n if (success === false) {\n return;\n }\n }\n // A newer navigation superseded this one while `enter` was awaiting.\n // Committing now would swap the outlet onto a route the URL has left.\n if (options?.signal?.aborted === true || seq !== this._gotoSeq) {\n return;\n }\n // Only update route state if the enter handler completes successfully\n this._currentRoute = route;\n this._currentParams = params;\n this._currentPathname =\n tail === undefined\n ? pathname\n : pathname.substring(0, pathname.length - tail.length);\n }\n this._currentTail = tail;\n this._currentSearch = location.search;\n this._currentHash = location.hash;\n\n // Propagate the tail match to children — deliberately NOT awaited.\n //\n // Awaiting looks like it would make `navigation.finished` cover the whole\n // tree, and an earlier revision of this fork did it. It is wrong twice\n // over. At this point `requestUpdate()` has not run, so `_childRoutes`\n // still holds the *outgoing* branch's controller: awaiting it gates the\n // parent's outlet swap on an `enter()` for a tail that controller will\n // never render (a hung one blocks the navigation forever), and if that\n // child has no route for the new tail its `No route found` throw\n // propagates out of here and `requestUpdate()` below never runs — URL\n // committed, outlet stranded, i.e. this fork's own thesis bug one level\n // down. Nested supersession is handled by the goto counter above, not by\n // awaiting. `_routeChild` covers the per-child filtering and error policy.\n //\n // Runs whether or not there is a tail. A route without one has nothing for\n // the children to render, but they must still be superseded — otherwise a\n // child mid-`enter()` for the previous tail stays current and commits over\n // a URL that has moved on.\n for (const childRoutes of this._childRoutes) {\n this._routeChild(childRoutes, tail);\n }\n this._host.requestUpdate();\n }\n\n /**\n * The result of calling the current route's render() callback.\n */\n outlet() {\n return this._currentRoute?.render?.(this._currentParams);\n }\n\n /**\n * The current parsed route parameters.\n */\n get params() {\n return this._currentParams;\n }\n\n /**\n * Hands a tail match to a child controller. Shared by the propagation loop in\n * `goto()` and the late-mount path in `_onRoutesConnected`, so that identical\n * input cannot be silent on one and an uncaught global throw on the other.\n *\n * A child with no route for the new tail is the expected case, not an error —\n * the outgoing branch mid-swap, or a deep link to a path the child cannot\n * render. Filtered structurally rather than by swallowing every rejection, so\n * a genuine `enter()` rejection still surfaces the way it does upstream.\n * Skipping must still supersede: `goto()` is where the counter is bumped, so\n * returning without it would leave an in-flight child navigation current,\n * free to commit over a URL that has moved on. A parent route with no tail\n * at all is the same case: nothing to route, but still something to stand\n * down.\n *\n * No abort signal is threaded through, and the goto is deliberately not\n * awaited. The parent commits its own state before children run, so a child\n * handed an already-aborted signal stands down with no newer goto() arriving\n * to correct it, leaving the nested outlet stuck — reachable, because a\n * hash-only navigation aborts the outstanding one without producing a\n * replacement. Supersession is the counter's job.\n */\n private _routeChild(child: Routes, tail: string | undefined) {\n if (tail === undefined) {\n child._supersede();\n return;\n }\n const childPath = formatLocation(tail, {\n search: this._currentSearch,\n hash: this._currentHash,\n });\n if (!child.hasRouteFor(childPath)) {\n child._supersede();\n return;\n }\n void child.goto(childPath).catch((err) => {\n queueMicrotask(() => {\n throw err;\n });\n });\n }\n\n /**\n * Invalidate any in-flight `goto()` on this controller without starting a\n * new one. Same-class access, so `_gotoSeq` stays private to `Routes`.\n */\n private _supersede(seen: Set<Routes> = new Set()): void {\n // Unreachable defence in depth. Upstream *can* produce a `_childRoutes`\n // cycle — a host carrying two Routes controllers, disconnected and\n // reconnected, ends up with each registered as the other's child — but\n // `hostDisconnected` below removes the listener that causes it, and a test\n // asserts the cycle cannot form. Kept because an unguarded recursive walk\n // over a cycle is a stack overflow rather than a misrender.\n if (seen.has(this)) {\n return;\n }\n seen.add(this);\n this._gotoSeq++;\n // Recursive: on the navigating branch the child's own propagation loop\n // reaches the grandchildren, but a skipped child never runs one — so\n // without this an in-flight grandchild `enter()` stays current and commits\n // over a URL that has moved on, the same defect one level deeper.\n for (const child of this._childRoutes) {\n child._supersede(seen);\n }\n }\n\n /**\n * True when this controller, or any controller below it, has a route that\n * constrains the hash.\n *\n * `Router` gates interception of fragment-only navigation on this. Left\n * ungated, a pathname-only app would have every in-page anchor swallowed and\n * re-rendered instead of scrolled; gated, such an app behaves exactly as it\n * did before hash routes existed.\n *\n * Walks children because a nested controller may route on the hash while the\n * top-level `Router` does not — and only the top-level one sees the\n * navigate event.\n */\n protected _constrainsHash(seen: Set<Routes> = new Set()): boolean {\n // Cycle guard, matching `_supersede`; see the note there.\n if (seen.has(this)) {\n return false;\n }\n seen.add(this);\n return (\n this.routes.some((r) => getPattern(r).hash !== '*') ||\n this._childRoutes.some((c) => c._constrainsHash(seen))\n );\n }\n\n /**\n * True when this controller can render `path` — i.e. a route matches, or\n * a fallback is configured.\n *\n * `Router` gates interception on this: intercepting a path we cannot render\n * commits the URL and then throws out of `goto()`, leaving the address bar\n * moved and the outlet stale. Letting the browser handle it instead means a\n * server-rendered page, an export endpoint, or a GET form still works.\n */\n hasRouteFor(path: string): boolean {\n // A fallback matches everything, and a controller with no routes of its own\n // behaves as if it had a single `/*` route (goto()'s special case). Either\n // way the answer is yes without running a single pattern — worth\n // short-circuiting, since `Router` asks this on every navigation.\n if (this.fallback !== undefined || this.routes.length === 0) {\n return true;\n }\n // `test()`, not `_match()`: this only needs the yes/no, and `exec()` pays\n // ~8x on a hit to build a groups object the caller would throw away.\n const location = parseLocation(path);\n return this.routes.some((r) => getPattern(r).test(location));\n }\n\n /**\n * Matches `pathname` against the installed routes and returns the first match\n * with its parsed parameters, or the fallback's match if one is configured.\n *\n * One `exec()` per candidate rather than `test()` to select and `exec()` to\n * extract: that ran the winning pattern twice, and every caller that wants a\n * route wants its params too.\n */\n private _match(location: RouteLocation):\n | {\n route: RouteConfig;\n params: {[key: string]: string | undefined};\n tail: string | undefined;\n }\n | undefined {\n for (const route of this.routes) {\n const result = getPattern(route).exec(location);\n if (result !== null) {\n const params: {[key: string]: string | undefined} = {\n ...result.pathname.groups,\n };\n // Named groups only. A positional group is keyed by index in every\n // component independently, so `/child/*` with a hash of `*` yields a\n // \"0\" in both — and `tailOf` picks the tail by highest numeric key.\n // Merging them would let a fragment masquerade as the tail.\n for (const groups of [result.search.groups, result.hash.groups]) {\n for (const [key, value] of Object.entries(groups)) {\n if (!/^\\d+$/.test(key)) {\n params[key] = value;\n }\n }\n }\n return {route, params, tail: tailOf(route, result.pathname.groups)};\n }\n }\n if (this.fallback === undefined) {\n return undefined;\n }\n // The fallback route behaves like it has a \"/*\" path. This is hidden from\n // the public API; the `path` is there to return a valid RouteConfig. The\n // match itself is done by hand rather than with a real `/*` pattern: a\n // nested controller is handed its tail *without* a leading slash, which\n // `/*` does not match, so a nested fallback matched nothing — empty\n // params, no tail, and its own children never routed.\n const {pathname} = location;\n const tail = pathname.startsWith('/') ? pathname.slice(1) : pathname;\n return {route: {...this.fallback, path: '/*'}, params: {0: tail}, tail};\n }\n\n hostConnected() {\n this._host.addEventListener(\n RoutesConnectedEvent.eventName,\n this._onRoutesConnected\n );\n const event = new RoutesConnectedEvent(this);\n this._host.dispatchEvent(event);\n this._onDisconnect = event.onDisconnect;\n }\n\n hostDisconnected() {\n // Remove the listener hostConnected added. Without this a host that is\n // disconnected and reconnected (a repeat() reorder, a tab swap) leaves the\n // sibling controller's listener installed, so on the second connect it\n // claims the re-dispatching controller as *its* child and the pair point\n // at each other — a real `_childRoutes` cycle, which recursive walks turn\n // into a stack overflow.\n this._host.removeEventListener(\n RoutesConnectedEvent.eventName,\n this._onRoutesConnected\n );\n // When this child routes controller is disconnected because a parent\n // outlet rendered a different template, disconnecting will ensure that\n // this controller doesn't receive a tail match meant for another route.\n this._onDisconnect?.();\n this._parentRoutes = undefined;\n }\n\n private _onRoutesConnected = (e: RoutesConnectedEvent) => {\n // Don't handle the event fired by this routes controller, which we get\n // because we do this.dispatchEvent(...)\n if (e.routes === this) {\n return;\n }\n\n const childRoutes = e.routes;\n this._childRoutes.push(childRoutes);\n childRoutes._parentRoutes = this;\n\n e.stopImmediatePropagation();\n e.onDisconnect = () => {\n const index = this._childRoutes.indexOf(childRoutes);\n if (index !== -1) {\n this._childRoutes.splice(index, 1);\n }\n };\n\n // A child that mounts under an existing tail match has to be caught up to\n // it — it missed the propagation loop in goto() that ran before it existed.\n // With no tail there is nothing to catch up to, and `_routeChild` then only\n // supersedes, a no-op on a freshly mounted child.\n this._routeChild(childRoutes, this._currentTail);\n };\n}\n\n/**\n * This event is fired from Routes controllers when their host is connected to\n * announce the child route and potentially connect to a parent routes controller.\n */\nexport class RoutesConnectedEvent extends Event {\n static readonly eventName = 'lit-routes-connected';\n readonly routes: Routes;\n onDisconnect?: () => void;\n\n constructor(routes: Routes) {\n super(RoutesConnectedEvent.eventName, {\n bubbles: true,\n composed: true,\n cancelable: false,\n });\n this.routes = routes;\n }\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [RoutesConnectedEvent.eventName]: RoutesConnectedEvent;\n }\n}\n"]}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n *\n * Modifications Copyright 2026 VanLandingham Labs, same license. See NOTICE.md.\n */\n\n/// <reference types=\"urlpattern-polyfill\" />\n\nimport type {ReactiveController, ReactiveControllerHost} from 'lit';\n\nexport interface BaseRouteConfig {\n name?: string | undefined;\n render?: (params: {[key: string]: string | undefined}) => unknown;\n enter?: (params: {\n [key: string]: string | undefined;\n }) => Promise<boolean> | boolean;\n}\n\n/**\n * A RouteConfig that matches against a `path` string. `path` must be a\n * [`URLPattern` compatible pathname pattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/pathname).\n */\nexport interface PathRouteConfig extends BaseRouteConfig {\n path: string;\n}\n\n/**\n * A RouteConfig that matches against a given [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern).\n *\n * Routes are only checked within the current origin, so only `pathname`,\n * `search` and `hash` are matched.\n */\nexport interface URLPatternRouteConfig extends BaseRouteConfig {\n pattern: URLPatternLike;\n}\n\n/**\n * The part of `URLPattern` this router uses. Structural, not a reference to the\n * global: `URLPattern` is not in TypeScript's `lib.dom`, so typing against it\n * fails a consumer build with `TS2304`.\n */\nexport interface URLPatternLike {\n /** Read by `tailOf`, which the groups object alone cannot answer. */\n readonly pathname: string;\n /** `'*'` means unconstrained. `Router` gates hash interception on this. */\n readonly hash: string;\n test(input: RouteLocation): boolean;\n exec(input: RouteLocation): {\n pathname: {groups: {[key: string]: string | undefined}};\n search: {groups: {[key: string]: string | undefined}};\n hash: {groups: {[key: string]: string | undefined}};\n } | null;\n}\n\n/**\n * The parts of a location this router matches against. `search` and `hash`\n * carry no leading `?` or `#`: a real `URLPattern` canonicalises either form\n * away, but `URLPatternLike` admits implementations that do not.\n */\nexport interface RouteLocation {\n pathname: string;\n search: string;\n hash: string;\n}\n\n/**\n * Not `new URL(path, origin)`: a nested controller's path is a tail, a bare\n * relative segment like `abc`, which `URL` would resolve and mangle.\n */\nconst parseLocation = (path: string): RouteLocation => {\n const hashIndex = path.indexOf('#');\n const hash = hashIndex === -1 ? '' : path.slice(hashIndex + 1);\n const beforeHash = hashIndex === -1 ? path : path.slice(0, hashIndex);\n const searchIndex = beforeHash.indexOf('?');\n return {\n pathname: searchIndex === -1 ? beforeHash : beforeHash.slice(0, searchIndex),\n search: searchIndex === -1 ? '' : beforeHash.slice(searchIndex + 1),\n hash,\n };\n};\n\n/** Re-attaches `search` and `hash` to a pathname. Inverse of `parseLocation`. */\nconst formatLocation = (\n pathname: string,\n {search, hash}: {search: string; hash: string}\n): string =>\n pathname + (search === '' ? '' : `?${search}`) + (hash === '' ? '' : `#${hash}`);\n\nexport type RouteConfig = PathRouteConfig | URLPatternRouteConfig;\n\n// Keyed by config object so `routes` can stay a plain mutable array that users\n// push new PathRouteConfigs onto.\nconst patternCache = new WeakMap<PathRouteConfig, URLPatternLike>();\n\nconst isPatternConfig = (route: RouteConfig): route is URLPatternRouteConfig =>\n (route as URLPatternRouteConfig).pattern !== undefined;\n\nconst getPattern = (route: RouteConfig): URLPatternLike => {\n if (isPatternConfig(route)) {\n return route.pattern;\n }\n let pattern = patternCache.get(route);\n if (pattern === undefined) {\n patternCache.set(route, (pattern = new URLPattern({pathname: route.path})));\n }\n return pattern;\n};\n\n/**\n * A trailing wildcard as `URLPattern.prototype.pathname` regenerates it: `*` or\n * `{*}`, optionally `?`. Excludes an escaped `\\*` and a `*` modifying a group\n * or named param (`(\\d+)*`, `{/}*`, `:rest*`), which would otherwise let an\n * earlier group be taken for the tail. See #4.\n */\nconst TRAILING_WILDCARD = /(?:(?<![\\\\)}]|:[\\w$]+)\\*|\\{\\*\\})\\??$/;\n\n/**\n * What a trailing wildcard captured, or undefined when there is none. Decided\n * from the pattern, not the groups object: an unnamed group (`/post/(\\d+)`) and\n * a non-final wildcard are keyed by index exactly as a tail is. See #4.\n */\nconst tailOf = (\n route: RouteConfig,\n params: {[key: string]: string | undefined}\n): string | undefined => {\n if (!TRAILING_WILDCARD.test(getPattern(route).pathname)) {\n return undefined;\n }\n let tailIndex = -1;\n for (const key of Object.keys(params)) {\n // Numeric, not lexicographic: '9' > '10' as strings.\n if (/^\\d+$/.test(key) && Number(key) > tailIndex) {\n tailIndex = Number(key);\n }\n }\n return tailIndex < 0 ? undefined : params[String(tailIndex)];\n};\n\n/**\n * One piece of a pathname pattern, as `parsePattern` understands it.\n */\ntype PatternNode =\n | {kind: 'literal'; text: string}\n | {kind: 'param'; name: string; optional: boolean}\n | {kind: 'wildcard'; index: number; optional: boolean}\n | {kind: 'group'; nodes: Array<PatternNode>; optional: boolean};\n\n/**\n * Parses the subset of `URLPattern` pathname syntax that can be run backwards:\n * literals, `:name`, `*`, and `{...}` groups, each optionally `?`.\n *\n * A regex group cannot be reversed, and `+` or `*` repetition has no single\n * answer, so both throw rather than guess. Named the route, not the pattern,\n * because the caller passed a name and that is what they can act on.\n */\nconst parsePattern = (pattern: string, name: string): Array<PatternNode> => {\n let i = 0;\n let positional = 0;\n\n const takeModifier = (): boolean => {\n const mod = pattern[i];\n if (mod === '?') {\n i++;\n return true;\n }\n if (mod === '+' || mod === '*') {\n throw new Error(\n `Cannot build a link to '${name}': the repeating modifier '${mod}' in ` +\n `'${pattern}' has no single reverse.`\n );\n }\n return false;\n };\n\n const parseNodes = (untilBrace: boolean): Array<PatternNode> => {\n const nodes: Array<PatternNode> = [];\n let literal = '';\n const flush = () => {\n if (literal !== '') {\n nodes.push({kind: 'literal', text: literal});\n literal = '';\n }\n };\n\n while (i < pattern.length) {\n const c = pattern[i];\n if (untilBrace && c === '}') {\n break;\n }\n if (c === '\\\\') {\n literal += pattern[i + 1] ?? '';\n i += 2;\n continue;\n }\n if (c === '(') {\n throw new Error(\n `Cannot build a link to '${name}': '${pattern}' contains a regular ` +\n `expression group, which cannot be reversed. Use a named parameter.`\n );\n }\n if (c === '{') {\n flush();\n i++;\n const inner = parseNodes(true);\n if (pattern[i] !== '}') {\n throw new Error(\n `Cannot build a link to '${name}': unbalanced '{' in '${pattern}'.`\n );\n }\n i++;\n nodes.push({kind: 'group', nodes: inner, optional: takeModifier()});\n continue;\n }\n const named = c === ':' ? /^:([A-Za-z0-9_$]+)/.exec(pattern.slice(i)) : null;\n if (named !== null) {\n flush();\n i += named[0].length;\n nodes.push({kind: 'param', name: named[1], optional: takeModifier()});\n continue;\n }\n if (c === '*') {\n flush();\n i++;\n nodes.push({\n kind: 'wildcard',\n index: positional++,\n optional: takeModifier(),\n });\n continue;\n }\n literal += c;\n i++;\n }\n flush();\n return nodes;\n };\n\n return parseNodes(false);\n};\n\n/** The highest wildcard index in `nodes`, or -1 when there is none. */\nconst maxWildcard = (nodes: Array<PatternNode>): number =>\n nodes.reduce(\n (max, node) =>\n node.kind === 'wildcard'\n ? Math.max(max, node.index)\n : node.kind === 'group'\n ? Math.max(max, maxWildcard(node.nodes))\n : max,\n -1\n );\n\n/**\n * Builds a pathname from `nodes`, collecting the names of any parameters the\n * caller did not supply.\n *\n * `tailIndex` is the wildcard that a trailing `/*` produced, or -1. That one\n * may be left out: an empty tail is the index of a nested route space, which\n * is what `linkTo('docs')` should mean. Any other wildcard is required, since\n * dropping it would silently join the segments around it.\n */\nconst fillNodes = (\n nodes: Array<PatternNode>,\n params: {[key: string]: string | undefined},\n tailIndex: number,\n missing: Array<string>\n): string => {\n let out = '';\n for (const node of nodes) {\n switch (node.kind) {\n case 'literal':\n out += node.text;\n break;\n case 'param': {\n const value = params[node.name];\n if (value === undefined) {\n if (!node.optional) {\n missing.push(node.name);\n }\n } else {\n out += value;\n }\n break;\n }\n case 'wildcard': {\n const value = params[String(node.index)];\n if (value === undefined) {\n if (!node.optional && node.index !== tailIndex) {\n missing.push(String(node.index));\n }\n } else {\n out += value;\n }\n break;\n }\n case 'group': {\n const before = missing.length;\n const text = fillNodes(node.nodes, params, tailIndex, missing);\n if (missing.length > before && node.optional) {\n // The whole point of an optional group: drop it, and the parameters\n // it wanted stop being missing.\n missing.length = before;\n } else {\n out += text;\n }\n break;\n }\n }\n }\n return out;\n};\n\n/** Runs a pathname pattern backwards. Throws naming every missing parameter. */\nconst fillPattern = (\n pattern: string,\n params: {[key: string]: string | undefined},\n name: string\n): string => {\n const nodes = parsePattern(pattern, name);\n const missing: Array<string> = [];\n const tailIndex = TRAILING_WILDCARD.test(pattern) ? maxWildcard(nodes) : -1;\n const text = fillNodes(nodes, params, tailIndex, missing);\n if (missing.length > 0) {\n throw new Error(\n `Cannot build a link to '${name}': missing parameter` +\n `${missing.length > 1 ? 's' : ''} ` +\n missing.map((m) => `'${m}'`).join(', ') +\n ` for pattern '${pattern}'.`\n );\n }\n return text;\n};\n\n/**\n * A reactive controller that performs location-based routing using a\n * configuration of URL patterns and associated render callbacks.\n */\nexport class Routes implements ReactiveController {\n private readonly _host: ReactiveControllerHost & HTMLElement;\n\n /**\n * The installed routes, in precedence order. Mutable, but mutating it starts\n * no route transition; call `goto()` if a different route now matches.\n */\n routes: Array<RouteConfig> = [];\n\n /**\n * Matched when no route in {@link routes} does. Behaves like `/*`, so\n * `params[0]` is the whole pathname minus any leading slash.\n */\n fallback?: BaseRouteConfig;\n\n private readonly _childRoutes: Array<Routes> = [];\n\n private _parentRoutes: Routes | undefined;\n\n /** Monotonic goto counter; see the last-goto-wins note in goto(). */\n private _gotoSeq = 0;\n\n private _currentPathname: string | undefined;\n private _currentTail: string | undefined;\n /** Ambient, not tailed: only the pathname nests. */\n private _currentSearch = '';\n private _currentHash = '';\n private _currentRoute: RouteConfig | undefined;\n private _currentParams: {\n [key: string]: string | undefined;\n } = {};\n\n /** Must run in hostDisconnected, or this controller can receive another\n * route's tail match. */\n // TODO (justinfagnani): Do we need this now that we have a direct reference\n // to the parent? We can call `this._parentRoutes.disconnect(this)`.\n private _onDisconnect: (() => void) | undefined;\n\n constructor(\n host: ReactiveControllerHost & HTMLElement,\n routes: Array<RouteConfig>,\n options?: {fallback?: BaseRouteConfig}\n ) {\n (this._host = host).addController(this);\n this.routes = [...routes];\n this.fallback = options?.fallback;\n }\n\n /**\n * Returns a URL string of the current route, including parent routes,\n * optionally replacing the local path with `pathname`.\n */\n link(pathname?: string): string {\n if (pathname?.startsWith('/')) {\n return pathname;\n }\n if (pathname?.startsWith('.')) {\n throw new Error('Not implemented');\n }\n pathname ??= this._currentPathname;\n return (this._parentRoutes?.link() ?? '') + pathname;\n }\n\n /**\n * A URL for the route named `name`, with `params` substituted into its\n * pattern.\n *\n * Lets a component say which route it means instead of where that route\n * currently lives, so moving a route subtree does not silently break every\n * hardcoded link inside it.\n *\n * Resolution covers the mounted controller tree: this controller, its\n * ancestors, and any descendant that has rendered. A route in a branch that\n * has not mounted yet is not addressable, because the mapping from a parent\n * route to its child controller only exists once that parent has rendered.\n * An unknown or ambiguous name throws rather than producing a wrong URL.\n */\n linkTo(\n name: string,\n params: {[key: string]: string | undefined} = {}\n ): string {\n let root: Routes = this;\n while (root._parentRoutes !== undefined) {\n root = root._parentRoutes;\n }\n\n const found: Array<{owner: Routes; route: RouteConfig}> = [];\n const visit = (routes: Routes, seen: Set<Routes>) => {\n // Cycle guard, matching `_supersede`; see the note there.\n if (seen.has(routes)) {\n return;\n }\n seen.add(routes);\n for (const route of routes.routes) {\n if (route.name === name) {\n found.push({owner: routes, route});\n }\n }\n for (const child of routes._childRoutes) {\n visit(child, seen);\n }\n };\n visit(root, new Set());\n\n if (found.length === 0) {\n throw new Error(\n `No route named '${name}' in the mounted route tree. Names are only ` +\n `resolvable once the controller holding them has rendered.`\n );\n }\n if (found.length > 1) {\n throw new Error(\n `More than one route named '${name}' in the mounted route tree.`\n );\n }\n\n const {owner, route} = found[0];\n // The owner's own segment is being replaced by the generated one, so the\n // prefix is everything above it.\n const prefix = owner._parentRoutes?.link() ?? '';\n return prefix + fillPattern(getPattern(route).pathname, params, name);\n }\n\n /**\n * Navigates this controller to `path`, which may carry a search and hash.\n * Navigates child routes but not parent ones, so it is not yet a general page\n * navigation API.\n *\n * `options.signal` makes the navigation abandonable. `enter()` is awaited, so\n * a second `goto()` can finish while the first is still resolving; without a\n * signal the slower one commits last onto a route the URL has left.\n */\n async goto(path: string, options?: {signal?: AbortSignal}) {\n // TODO (justinfagnani): handle absolute vs relative paths separately.\n\n const location = parseLocation(path);\n const {pathname} = location;\n\n // Last-goto-wins. The signal alone is not enough: a child's first goto()\n // comes from `_onRoutesConnected`, after the parent's navigation finished,\n // so its signal never aborts. Also keeps `Routes` correct standalone.\n const seq = ++this._gotoSeq;\n let tail: string | undefined;\n\n if (this.routes.length === 0 && this.fallback === undefined) {\n // No routes of its own acts as a single `/*`, passing the whole pathname\n // on as a tail.\n tail = pathname;\n this._currentPathname = '';\n this._currentParams = {0: tail};\n } else {\n const match = this._match(location);\n if (match === undefined) {\n throw new Error(`No route found for ${path}`);\n }\n const {route, params} = match;\n tail = match.tail;\n if (typeof route.enter === 'function') {\n const success = await route.enter(params);\n if (success === false) {\n return;\n }\n }\n // Superseded while `enter` awaited; committing would strand the outlet.\n if (options?.signal?.aborted === true || seq !== this._gotoSeq) {\n return;\n }\n this._currentRoute = route;\n this._currentParams = params;\n this._currentPathname =\n tail === undefined\n ? pathname\n : pathname.substring(0, pathname.length - tail.length);\n }\n this._currentTail = tail;\n this._currentSearch = location.search;\n this._currentHash = location.hash;\n\n // Not awaited. `requestUpdate()` has not run, so `_childRoutes` still holds\n // the outgoing branch: awaiting gates the parent's swap on a controller\n // that will never render, and its `No route found` would skip\n // `requestUpdate()` below and strand the outlet on a committed URL.\n //\n // Runs even with no tail, so children still get superseded. See #7.\n for (const childRoutes of this._childRoutes) {\n this._routeChild(childRoutes, tail);\n }\n this._host.requestUpdate();\n }\n\n /**\n * The result of calling the current route's render() callback.\n */\n outlet() {\n return this._currentRoute?.render?.(this._currentParams);\n }\n\n /**\n * The current parsed route parameters.\n */\n get params() {\n return this._currentParams;\n }\n\n /**\n * Hands a tail match to a child. Shared by `goto()`'s propagation loop and the\n * late-mount path, so identical input behaves identically on both.\n *\n * A child with no route for the tail is expected, not an error: the outgoing\n * branch mid-swap, or a deep link it cannot render. Filtered structurally so\n * a genuine `enter()` rejection still surfaces. Skipping must still supersede.\n */\n private _routeChild(child: Routes, tail: string | undefined) {\n if (tail === undefined) {\n child._supersede();\n return;\n }\n const childPath = formatLocation(tail, {\n search: this._currentSearch,\n hash: this._currentHash,\n });\n if (!child.hasRouteFor(childPath)) {\n child._supersede();\n return;\n }\n void child.goto(childPath).catch((err) => {\n queueMicrotask(() => {\n throw err;\n });\n });\n }\n\n /** Invalidate any in-flight `goto()` here without starting a new one. */\n private _supersede(seen: Set<Routes> = new Set()): void {\n // Defence in depth: a `_childRoutes` cycle cannot form (hostDisconnected,\n // plus a test), but an unguarded walk over one is a stack overflow.\n if (seen.has(this)) {\n return;\n }\n seen.add(this);\n this._gotoSeq++;\n // A skipped child never runs its own propagation loop, so recurse or an\n // in-flight grandchild `enter()` stays current.\n for (const child of this._childRoutes) {\n child._supersede(seen);\n }\n }\n\n /**\n * True when this controller or any below it constrains the hash. `Router`\n * gates fragment-only interception on this, so a pathname-only app keeps\n * native scrolling. Walks children because only the root sees the event.\n */\n protected _constrainsHash(seen: Set<Routes> = new Set()): boolean {\n // Cycle guard, matching `_supersede`; see the note there.\n if (seen.has(this)) {\n return false;\n }\n seen.add(this);\n return (\n this.routes.some((r) => getPattern(r).hash !== '*') ||\n this._childRoutes.some((c) => c._constrainsHash(seen))\n );\n }\n\n /**\n * True when this controller can render `path`. `Router` gates interception on\n * this: intercepting what we cannot render commits the URL and then throws,\n * leaving the address bar moved and the outlet stale.\n */\n hasRouteFor(path: string): boolean {\n // A fallback matches everything, and no routes behaves as one `/*`. Worth\n // short-circuiting: `Router` asks this on every navigation.\n if (this.fallback !== undefined || this.routes.length === 0) {\n return true;\n }\n // `test()`, not `_match()`: `exec()` pays ~8x on a hit to build groups the\n // caller would throw away.\n const location = parseLocation(path);\n return this.routes.some((r) => getPattern(r).test(location));\n }\n\n /**\n * The first route matching `location`, or the fallback's match. One `exec()`\n * per candidate; selecting with `test()` first ran the winner twice.\n */\n private _match(location: RouteLocation):\n | {\n route: RouteConfig;\n params: {[key: string]: string | undefined};\n tail: string | undefined;\n }\n | undefined {\n for (const route of this.routes) {\n const result = getPattern(route).exec(location);\n if (result !== null) {\n const params: {[key: string]: string | undefined} = {\n ...result.pathname.groups,\n };\n // Named only. Every component numbers positional groups from zero, so\n // a merged \"0\" could masquerade as the tail. See #13.\n for (const groups of [result.search.groups, result.hash.groups]) {\n for (const [key, value] of Object.entries(groups)) {\n if (!/^\\d+$/.test(key)) {\n params[key] = value;\n }\n }\n }\n return {route, params, tail: tailOf(route, result.pathname.groups)};\n }\n }\n if (this.fallback === undefined) {\n return undefined;\n }\n // Matched by hand, not with a real `/*` pattern: a nested controller gets\n // its tail without a leading slash, which `/*` rejects. See #5.\n const {pathname} = location;\n const tail = pathname.startsWith('/') ? pathname.slice(1) : pathname;\n return {route: {...this.fallback, path: '/*'}, params: {0: tail}, tail};\n }\n\n hostConnected() {\n this._host.addEventListener(\n RoutesConnectedEvent.eventName,\n this._onRoutesConnected\n );\n const event = new RoutesConnectedEvent(this);\n this._host.dispatchEvent(event);\n this._onDisconnect = event.onDisconnect;\n }\n\n hostDisconnected() {\n // Without this, a disconnected and reconnected host leaves a sibling's\n // listener installed and the two claim each other as children: a\n // `_childRoutes` cycle, which recursive walks turn into a stack overflow.\n this._host.removeEventListener(\n RoutesConnectedEvent.eventName,\n this._onRoutesConnected\n );\n this._onDisconnect?.();\n this._parentRoutes = undefined;\n }\n\n private _onRoutesConnected = (e: RoutesConnectedEvent) => {\n // Ignore our own event, which we receive because we dispatch on the host.\n if (e.routes === this) {\n return;\n }\n\n const childRoutes = e.routes;\n this._childRoutes.push(childRoutes);\n childRoutes._parentRoutes = this;\n\n e.stopImmediatePropagation();\n e.onDisconnect = () => {\n const index = this._childRoutes.indexOf(childRoutes);\n if (index !== -1) {\n this._childRoutes.splice(index, 1);\n }\n };\n\n // Catch up a child that mounted after goto()'s propagation loop ran.\n this._routeChild(childRoutes, this._currentTail);\n };\n}\n\n/** Announces a Routes controller to its parent when the host connects. */\nexport class RoutesConnectedEvent extends Event {\n static readonly eventName = 'lit-routes-connected';\n readonly routes: Routes;\n onDisconnect?: () => void;\n\n constructor(routes: Routes) {\n super(RoutesConnectedEvent.eventName, {\n bubbles: true,\n composed: true,\n cancelable: false,\n });\n this.routes = routes;\n }\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [RoutesConnectedEvent.eventName]: RoutesConnectedEvent;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lit-navigation-router",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "A router for Lit built on the Navigation API. Fork of @lit-labs/router.",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
@@ -49,12 +49,12 @@
49
49
  "lit": "^3.0.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@open-wc/testing": "^4.0.0",
52
+ "@open-wc/testing": "^5.0.0",
53
53
  "@types/mocha": "^10.0.10",
54
- "@web/dev-server-esbuild": "^1.0.4",
55
- "@web/test-runner": "^0.20.0",
56
- "@web/test-runner-playwright": "^0.11.1",
57
- "typescript": "^5.7.0",
54
+ "@web/dev-server-esbuild": "^2.0.0",
55
+ "@web/test-runner": "^1.0.0",
56
+ "@web/test-runner-playwright": "^1.0.0",
57
+ "typescript": "^7.0.2",
58
58
  "urlpattern-polyfill": "^10.1.0"
59
59
  },
60
60
  "keywords": [
package/src/router.ts CHANGED
@@ -10,10 +10,9 @@
10
10
  import {Routes} from './routes.js';
11
11
 
12
12
  /**
13
- * The slice of `NavigateEvent` this router reads. Declared locally rather than
14
- * typing the handler `any`: these properties *are* the correctness boundary, so
15
- * a typo like `hashchange` for `hashChange` would silently disable a filter
16
- * forever. Names verified against Chromium's `NavigateEvent.prototype`.
13
+ * The slice of `NavigateEvent` this router reads. Typed rather than `any`
14
+ * because these properties are the correctness boundary: `hashchange` for
15
+ * `hashChange` would silently disable a filter forever.
17
16
  */
18
17
  interface NavigateEventLike {
19
18
  readonly canIntercept: boolean;
@@ -48,95 +47,50 @@ interface NavigationLike {
48
47
  const getNavigation = (): NavigationLike | undefined =>
49
48
  (window as unknown as {navigation?: NavigationLike}).navigation;
50
49
 
51
- /**
52
- * The current location as a path string, in the form `goto()` parses.
53
- *
54
- * Only the origin is dropped: this router matches within one origin, and
55
- * `_onNavigate` declines anything else before it gets here.
56
- */
50
+ /** The current location in the form `goto()` parses, minus the origin. */
57
51
  const currentPath = (): string =>
58
52
  window.location.pathname + window.location.search + window.location.hash;
59
53
 
60
54
  /**
61
- * True when the Navigation API is available — Baseline Newly Available since
62
- * January 2026 (Chrome/Edge, Safari 26.2, Firefox 147).
63
- *
64
- * This router **requires** it. Exported so an app can detect an unsupported
65
- * engine at boot and say so, rather than leaving the user to notice that every
66
- * link reloads the page.
55
+ * True when the Navigation API is available (Baseline Newly Available, January
56
+ * 2026). This router requires it; exported so an app can detect an unsupported
57
+ * engine at boot rather than leaving users to notice every link reloading.
67
58
  */
68
59
  export const supportsNavigationApi = (): boolean =>
69
60
  typeof window !== 'undefined' &&
70
61
  typeof getNavigation()?.addEventListener === 'function';
71
62
 
72
63
  /**
73
- * A root-level router that intercepts navigation via the Navigation API.
74
- *
75
- * This class extends Routes so that it can also have a route configuration.
76
- *
77
- * There should only be one Router instance on a page, since the Router
78
- * installs a global listener. Nested routes should be configured with the
79
- * `Routes` class.
64
+ * A root-level router that intercepts navigation via the Navigation API. Use one
65
+ * per page, since it installs a global listener, and `Routes` for nested spaces.
80
66
  *
81
- * ## Why the Navigation API
67
+ * Upstream committed with `history.pushState()` and reacted to `popstate`, but
68
+ * swapped the outlet only after awaiting `enter()`. The URL led and the outlet
69
+ * lagged, so the outgoing route re-rendered with stale params and quick
70
+ * navigations committed out of order. `intercept({handler})` collapses that:
71
+ * the browser holds the navigation unfinished while the handler runs and aborts
72
+ * `signal` when a newer one supersedes it.
82
73
  *
83
- * Upstream intercepted navigation with a global click listener plus `popstate`
84
- * and committed with `history.pushState()`. That is structurally racy:
85
- * `pushState` is synchronous and `popstate` fires *after* the URL has already
86
- * moved, but `goto()` awaits `route.enter()` before swapping the outlet. The
87
- * URL leads and the outlet lags, leaving two sources of truth — the outgoing
88
- * route re-renders with stale params, and two quick navigations commit in
89
- * whatever order their `enter()` hooks happen to resolve.
90
- *
91
- * `navigateEvent.intercept({handler})` collapses that. The browser commits the
92
- * URL and holds the navigation un-finished while the handler runs, and it
93
- * aborts `navigateEvent.signal` when a newer navigation supersedes this one —
94
- * which `goto()` honours, so a superseded route can no longer win the outlet.
95
- *
96
- * ## No legacy fallback
97
- *
98
- * An earlier version of this fork kept upstream's click/popstate path for
99
- * pre-2026 engines. It was removed deliberately. Ten review rounds found
100
- * divergences between the two paths and **every one was in the click handler**,
101
- * never in this one — which is structural, not luck: this handler reads a
102
- * decision the browser has already made, while the click handler had to
103
- * re-derive it, re-implementing the rules for choosing a navigable, the
104
- * fragment-navigation predicate, and the modifier-key rules. Each round found
105
- * another place where the re-implementation and the spec disagreed.
106
- *
107
- * On an engine without the API, links fall back to ordinary full page loads.
108
- * For an app whose server serves the shell on every route that still works —
109
- * it is slower, not broken — and `supportsNavigationApi()` lets you detect it.
110
- * If real pre-2026 support is ever needed, use a Navigation API polyfill: one
111
- * decision path, with compatibility isolated in a layer whose whole job is
112
- * spec accuracy.
74
+ * There is no legacy fallback for pre-2026 engines. Without the API links
75
+ * become full page loads, which `supportsNavigationApi()` detects. See the
76
+ * README for what that degrades and what it breaks.
113
77
  */
114
78
  export class Router extends Routes {
115
- /**
116
- * Options forwarded to `navigateEvent.intercept()`. Leaving these unset
117
- * gives the browser's default scroll and focus handling.
118
- */
79
+ /** Forwarded to `navigateEvent.intercept()`. Unset uses browser defaults. */
119
80
  interceptOptions?: InterceptOptions;
120
81
 
121
82
  private _listening = false;
122
83
 
123
84
  override hostConnected() {
124
85
  super.hostConnected();
125
- // Gated on the exported predicate, not on `navigation !== undefined`:
126
- // a stub or partial polyfill under that name would otherwise make this
127
- // branch throw out of connectedCallback while `supportsNavigationApi()`
128
- // told the app it was unsupported — and then even the initial render below
129
- // would not run.
86
+ // The predicate, not `navigation !== undefined`: a partial polyfill would
87
+ // otherwise throw out of connectedCallback and skip the render below.
130
88
  if (supportsNavigationApi()) {
131
89
  getNavigation()!.addEventListener('navigate', this._onNavigate);
132
90
  this._listening = true;
133
91
  }
134
- // Kick off routed rendering by going to the current URL. Done even without
135
- // the API: a full page load still renders the right route, which is what
136
- // makes the unsupported-engine degradation "slow" rather than "blank".
137
- // Surfaced rather than left as a bare unhandled rejection, matching the
138
- // convention in routes.ts: on an engine without the API this is the *only*
139
- // rendering path, and a deep link with no matching route throws here.
92
+ // Runs even without the API, which is what makes the degradation slow
93
+ // rather than blank. Surfaced because it is then the only rendering path.
140
94
  void this.goto(currentPath()).catch((err) => {
141
95
  queueMicrotask(() => {
142
96
  throw err;
@@ -157,58 +111,41 @@ export class Router extends Routes {
157
111
  * `navigation.navigate()`, `history.pushState()`, and back/forward.
158
112
  */
159
113
  private _onNavigate = (e: NavigateEventLike) => {
160
- // Not ours to handle: anything the browser says cannot be intercepted,
161
- // downloads, and POST form submissions.
162
- //
163
- // `!= null`, not `!== null`: the spec types both as nullable-but-present,
164
- // but a polyfill that leaves either unset would make a strict check true
165
- // for every ordinary link and silently decline the whole app.
114
+ // `!= null`: a polyfill leaving either unset would make a strict check
115
+ // true for every link and silently decline the whole app.
166
116
  if (!e.canIntercept || e.downloadRequest != null || e.formData != null) {
167
117
  return;
168
118
  }
169
119
 
170
- // Fragment-only moves belong to the browser unless a route actually reads
171
- // the fragment. Intercepting them unconditionally would cost every
172
- // pathname-only app its native in-page scrolling — and re-render the same
173
- // route to no effect — while declining them unconditionally is the
174
- // lit/lit#3517 bug this router inherited.
120
+ // Fragment-only moves are the browser's unless a route reads the fragment.
121
+ // Always intercepting costs native scrolling; never intercepting is
122
+ // lit/lit#3517. See #13.
175
123
  if (e.hashChange && !this._constrainsHash()) {
176
124
  return;
177
125
  }
178
126
 
179
127
  // Reloads must stay reloads. `canIntercept` is true for them, so without
180
- // this `location.reload()` silently degrades to re-running goto() on the
181
- // same path — the document is never replaced, breaking the standard
182
- // "new version available, reload" escape hatch. (It would also disagree
183
- // with the browser's own refresh button, which is not interceptable.)
128
+ // this `location.reload()` never replaces the document.
184
129
  if (e.navigationType === 'reload') {
185
130
  return;
186
131
  }
187
132
 
188
- // `rel="external"` is a convention this router honours — it is not defined
189
- // by HTML or by the Navigation API, so the browser will not decline these
190
- // for us. Best-effort: `sourceElement` is not in every engine, and is
191
- // absent for programmatic navigation.
133
+ // This router's convention, not HTML's, so the browser will not decline
134
+ // these for us. Best-effort: `sourceElement` is not everywhere.
192
135
  if (e.sourceElement?.getAttribute?.('rel') === 'external') {
193
136
  return;
194
137
  }
195
138
 
196
- // Read per navigation rather than cached at module scope: the value cannot
197
- // change, but reading it on import makes merely importing this module throw
198
- // where there is no `location` (SSR, a bundler evaluating for tree-shaking
199
- // under the package's `sideEffects: false` claim).
139
+ // Per navigation, not module scope: reading `location` on import throws
140
+ // under SSR, contradicting the package's `sideEffects: false`.
200
141
  const url = new URL(e.destination.url);
201
142
  if (url.origin !== window.location.origin) {
202
143
  return;
203
144
  }
204
145
 
205
- // Only intercept what we can actually render. `canIntercept` is true for
206
- // any same-origin URL, including cross-document ones — so without this a
207
- // link to a server-rendered page, an export endpoint, or a GET form
208
- // (whose `formData` is null) gets swallowed: the URL commits, goto()
209
- // throws "No route found", and the address bar is left pointing somewhere
210
- // the outlet never went. Declining lets the browser do the real
211
- // navigation, which is the correct outcome.
146
+ // `canIntercept` is true for cross-document same-origin URLs too, so
147
+ // without this a server-rendered page or GET form gets swallowed: the URL
148
+ // commits, goto() throws, and the outlet never moves.
212
149
  const path = url.pathname + url.search + url.hash;
213
150
  if (!this.hasRouteFor(path)) {
214
151
  return;
@@ -217,8 +154,7 @@ export class Router extends Routes {
217
154
  e.intercept({
218
155
  ...this.interceptOptions,
219
156
  handler: async () => {
220
- // `e.signal` aborts if another navigation starts before this handler
221
- // resolves; goto() checks it after `enter()` and stands down.
157
+ // `e.signal` aborts if a newer navigation starts; goto() checks it.
222
158
  await this.goto(path, {signal: e.signal});
223
159
  },
224
160
  });