@solidjs/router 0.4.2 → 0.5.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.
package/README.md CHANGED
@@ -2,9 +2,6 @@
2
2
  <img src="https://assets.solidjs.com/banner?project=Router&type=core" alt="Solid Router" />
3
3
  </p>
4
4
 
5
- > 0.3.x only works with Solid v1.3.5 or later.
6
- > `useData` has been renamed to `useRouteData` and no longer takes arguments. Refer to documentation below.
7
-
8
5
  # Solid Router [![npm Version](https://img.shields.io/npm/v/@solidjs/router.svg?style=flat-square)](https://www.npmjs.org/package/@solidjs/router)
9
6
 
10
7
  A router lets you change your view based on the URL in the browser. This allows your "single-page" application to simulate a traditional multipage site. To use Solid Router, you specify components called Routes that depend on the value of the URL (the "path"), and the router handles the mechanism of swapping them in and out.
@@ -101,7 +98,7 @@ export default function App() {
101
98
 
102
99
  3. Lazy-load route components
103
100
 
104
- This way, the `Users` and `Home` components will only be loaded if you're navigating to `/users` or `/home`, respectively.
101
+ This way, the `Users` and `Home` components will only be loaded if you're navigating to `/users` or `/`, respectively.
105
102
 
106
103
  ```jsx
107
104
  import { lazy } from "solid-js";
@@ -123,11 +120,11 @@ export default function App() {
123
120
 
124
121
  ## Create Links to Your Routes
125
122
 
126
- Use the `Link` component to create an anchor tag that takes you to a route:
123
+ Use the `A` component to create an anchor tag that takes you to a route:
127
124
 
128
125
  ```jsx
129
126
  import { lazy } from "solid-js";
130
- import { Routes, Route, Link } from "@solidjs/router"
127
+ import { Routes, Route, A } from "@solidjs/router"
131
128
  const Users = lazy(() => import("./pages/Users"));
132
129
  const Home = lazy(() => import("./pages/Home"));
133
130
 
@@ -135,8 +132,8 @@ export default function App() {
135
132
  return <>
136
133
  <h1>My Site with Lots of Pages</h1>
137
134
  <nav>
138
- <Link href="/about">About</Link>
139
- <Link href="/">Home</Link>
135
+ <A href="/about">About</A>
136
+ <A href="/">Home</A>
140
137
  </nav>
141
138
  <Routes>
142
139
  <Route path="/users" component={Users} />
@@ -147,33 +144,21 @@ export default function App() {
147
144
  }
148
145
  ```
149
146
 
150
- If you use `NavLink` instead of `Link`, the anchor tag will have an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
147
+ The `<A>` tag also has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
151
148
 
152
- Both of these components have these props:
153
149
 
154
150
  | prop | type | description |
155
151
  |----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
156
152
  | href | string | The path of the route to navigate to. This will be resolved relative to the route that the link is in, but you can preface it with `/` to refer back to the root. |
157
153
  | noScroll | boolean | If true, turn off the default behavior of scrolling to the top of the new page |
158
154
  | replace | boolean | If true, don't add a new entry to the browser history. (By default, the new page will be added to the browser history, so pressing the back button will take you to the previous route.) |
159
- | state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating |
160
-
161
-
162
- `NavLink` additionally has:
163
-
164
- | prop | type | description |
165
- |----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
155
+ | state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating | |
166
156
  | inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) |
167
157
  | activeClass | string | The class to show when the link is active |
168
158
  | end | boolean | If `true`, only considers the link to be active when the curent location matches the `href` exactly; if `false`, check if the current location _starts with_ `href` |
169
159
 
170
-
171
-
172
-
173
- If you have a same-domain path that you want to link to _without_ going through the router, set `rel="external"` on the link component.
174
-
175
160
  ### The Navigate Component
176
- Solid Router provides a `Navigate` component that works similarly to `Link` and `NavLink`, but it will _immediately_ navigate to the provided path as soon as the component is rendered. It also uses the `href` prop, but you have the additional option of passing a function to `href` that returns a path to navigate to:
161
+ Solid Router provides a `Navigate` component that works similarly to `A`, but it will _immediately_ navigate to the provided path as soon as the component is rendered. It also uses the `href` prop, but you have the additional option of passing a function to `href` that returns a path to navigate to:
177
162
 
178
163
  ```jsx
179
164
  function getPath ({navigate, location}) {
@@ -183,9 +168,7 @@ function getPath ({navigate, location}) {
183
168
  }
184
169
 
185
170
  //Navigating to /redirect will redirect you to the result of getPath
186
- <Route path="/redirect">
187
- <Navigate href={getPath}/>
188
- </Route>
171
+ <Route path="/redirect" element={<Navigate href={getPath}/>}/>
189
172
  ```
190
173
 
191
174
  ## Dynamic Routes
@@ -201,7 +184,7 @@ const Home = lazy(() => import("./pages/Home"));
201
184
 
202
185
  export default function App() {
203
186
  return <>
204
- <h1>My Site with Lots of Pages<h1/>
187
+ <h1>My Site with Lots of Pages</h1>
205
188
  <Routes>
206
189
  <Route path="/users" component={Users} />
207
190
  <Route path="/users/:id" component={User} />
@@ -227,7 +210,7 @@ export default function User () {
227
210
 
228
211
  const [userData] = createResource(() => params.id, fetchUser);
229
212
 
230
- return <a href={userData.twitter}>{userData.name}</a>
213
+ return <A href={userData.twitter}>{userData.name}</A>
231
214
  }
232
215
  ```
233
216
 
@@ -276,9 +259,9 @@ To do this, create a function that fetches and returns the data using `createRes
276
259
  ```js
277
260
  import { lazy } from "solid-js";
278
261
  import { Route } from "@solidjs/router";
279
- import { fetchUser } ...
262
+ import { fetchUser } ...
280
263
 
281
- const User = lazy(() => import("/pages/users/[id].js"));
264
+ const User = lazy(() => import("./pages/users/[id].js"));
282
265
 
283
266
  //Data function
284
267
  function UserData({params, location, navigate, data}) {
@@ -364,7 +347,7 @@ function PageWrapper () {
364
347
  return <div>
365
348
  <h1> We love our users! </h1>
366
349
  <Outlet/>
367
- <Link href="/">Back Home</Link>
350
+ <A href="/">Back Home</A>
368
351
  </div>
369
352
  }
370
353
 
@@ -404,7 +387,7 @@ You don't have to use JSX to set up your routes; you can pass an object directly
404
387
  ```jsx
405
388
  import { lazy } from "solid-js";
406
389
  import { render } from "solid-js/web";
407
- import { Router, useRoutes, Link } from "@solidjs/router";
390
+ import { Router, useRoutes, A } from "@solidjs/router";
408
391
 
409
392
  const routes = [
410
393
  {
@@ -435,12 +418,12 @@ function App() {
435
418
  return (
436
419
  <>
437
420
  <h1>Awesome Site</h1>
438
- <Link class="nav" href="/">
421
+ <A class="nav" href="/">
439
422
  Home
440
- </Link>
441
- <Link class="nav" href="/users">
423
+ </A>
424
+ <A class="nav" href="/users">
442
425
  Users
443
- </Link>
426
+ </A>
444
427
  <Routes />
445
428
  </>
446
429
  );
@@ -6,6 +6,7 @@ declare module "solid-js" {
6
6
  state?: string;
7
7
  noScroll?: boolean;
8
8
  replace?: boolean;
9
+ link?: boolean;
9
10
  }
10
11
  }
11
12
  }
@@ -27,7 +28,7 @@ export interface RoutesProps {
27
28
  children: JSX.Element;
28
29
  }
29
30
  export declare const Routes: (props: RoutesProps) => JSX.Element;
30
- export declare const useRoutes: (routes: RouteDefinition | RouteDefinition[], base?: string | undefined) => () => JSX.Element;
31
+ export declare const useRoutes: (routes: RouteDefinition | RouteDefinition[], base?: string) => () => JSX.Element;
31
32
  export declare type RouteProps = {
32
33
  path: string | string[];
33
34
  children?: JSX.Element;
@@ -42,19 +43,17 @@ export declare type RouteProps = {
42
43
  });
43
44
  export declare const Route: (props: RouteProps) => JSX.Element;
44
45
  export declare const Outlet: () => JSX.Element;
45
- export interface LinkProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
46
+ export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
46
47
  href: string;
47
48
  replace?: boolean;
48
49
  noScroll?: boolean;
49
50
  state?: unknown;
50
- }
51
- export declare function Link(props: LinkProps): JSX.Element;
52
- export interface NavLinkProps extends LinkProps {
53
51
  inactiveClass?: string;
54
52
  activeClass?: string;
55
53
  end?: boolean;
56
54
  }
57
- export declare function NavLink(props: NavLinkProps): JSX.Element;
55
+ export declare function A(props: AnchorProps): JSX.Element;
56
+ export { A as Link, A as NavLink, AnchorProps as LinkProps, AnchorProps as NavLinkProps };
58
57
  export interface NavigateProps {
59
58
  href: ((args: {
60
59
  navigate: Navigator;
@@ -54,7 +54,7 @@ export const Routes = (props) => {
54
54
  return next;
55
55
  }));
56
56
  return (<Show when={routeStates() && root}>
57
- {route => <RouteContextObj.Provider value={route}>{route.outlet()}</RouteContextObj.Provider>}
57
+ {((route) => (<RouteContextObj.Provider value={route}>{route.outlet()}</RouteContextObj.Provider>))}
58
58
  </Show>);
59
59
  };
60
60
  export const useRoutes = (routes, base) => {
@@ -71,36 +71,31 @@ export const Route = (props) => {
71
71
  export const Outlet = () => {
72
72
  const route = useRoute();
73
73
  return (<Show when={route.child}>
74
- {child => <RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>}
74
+ {((child) => (<RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>))}
75
75
  </Show>);
76
76
  };
77
- function LinkBase(props) {
78
- const [, rest] = splitProps(props, ["children", "to", "href", "state"]);
79
- const href = useHref(() => props.to);
80
- return (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)}>
81
- {props.children}
82
- </a>);
83
- }
84
- export function Link(props) {
85
- const to = useResolvedPath(() => props.href);
86
- return <LinkBase {...props} to={to()}/>;
87
- }
88
- export function NavLink(props) {
77
+ export function A(props) {
89
78
  props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
90
- const [, rest] = splitProps(props, ["activeClass", "inactiveClass", "end"]);
91
- const location = useLocation();
79
+ const [, rest] = splitProps(props, ["href", "state", "activeClass", "inactiveClass", "end"]);
92
80
  const to = useResolvedPath(() => props.href);
81
+ const href = useHref(to);
82
+ const location = useLocation();
93
83
  const isActive = createMemo(() => {
94
84
  const to_ = to();
95
- if (to_ === undefined) {
85
+ if (to_ === undefined)
96
86
  return false;
97
- }
98
87
  const path = to_.split(/[?#]/, 1)[0].toLowerCase();
99
88
  const loc = location.pathname.toLowerCase();
100
89
  return props.end ? path === loc : loc.startsWith(path);
101
90
  });
102
- return (<LinkBase {...rest} to={to()} classList={{ [props.inactiveClass]: !isActive(), [props.activeClass]: isActive(), ...rest.classList }} aria-current={isActive() ? "page" : undefined}/>);
91
+ return (<a link {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
92
+ [props.inactiveClass]: !isActive(),
93
+ [props.activeClass]: isActive(),
94
+ ...rest.classList
95
+ }} aria-current={isActive() ? "page" : undefined}/>);
103
96
  }
97
+ // deprecated alias exports
98
+ export { A as Link, A as NavLink };
104
99
  export function Navigate(props) {
105
100
  const navigate = useNavigate();
106
101
  const location = useLocation();
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { isServer, createComponent as createComponent$1, mergeProps as mergeProps$1, spread, insert, effect, setAttribute, template } from 'solid-js/web';
2
- import { createSignal, onCleanup, runWithOwner, createMemo, getOwner, createContext, useContext, untrack, useTransition, on, resetErrorBoundaries, createRenderEffect, createComponent, children, createRoot, Show, mergeProps, splitProps } from 'solid-js';
1
+ import { isServer, delegateEvents, createComponent as createComponent$1, spread, effect, setAttribute, classList, template } from 'solid-js/web';
2
+ import { createSignal, onCleanup, getOwner, runWithOwner, createMemo, createContext, useContext, untrack, createRenderEffect, createComponent, on, startTransition, resetErrorBoundaries, children, createRoot, Show, mergeProps, splitProps } from 'solid-js';
3
3
 
4
4
  function bindEvent(target, type, handler) {
5
5
  target.addEventListener(type, handler);
@@ -307,10 +307,9 @@ const useSearchParams = () => {
307
307
 
308
308
  const setSearchParams = (params, options) => {
309
309
  const searchString = untrack(() => mergeSearchString(location.search, params));
310
- navigate(searchString, {
310
+ navigate(location.pathname + searchString, {
311
311
  scroll: false,
312
- ...options,
313
- resolve: true
312
+ ...options
314
313
  });
315
314
  };
316
315
 
@@ -485,7 +484,18 @@ function createRouterContext(integration, base = "", data, out) {
485
484
  });
486
485
  }
487
486
 
488
- const [isRouting, start] = useTransition();
487
+ const [isRouting, setIsRouting] = createSignal(false);
488
+
489
+ const start = async callback => {
490
+ setIsRouting(true);
491
+
492
+ try {
493
+ await startTransition(callback);
494
+ } finally {
495
+ setIsRouting(false);
496
+ }
497
+ };
498
+
489
499
  const [reference, setReference] = createSignal(source().value);
490
500
  const [state, setState] = createSignal(source().state);
491
501
  const location = createLocation(reference, state);
@@ -624,21 +634,15 @@ function createRouterContext(integration, base = "", data, out) {
624
634
  });
625
635
 
626
636
  if (!isServer) {
627
- function isSvg(el) {
628
- return el.namespaceURI === "http://www.w3.org/2000/svg";
629
- }
630
-
631
637
  function handleAnchorClick(evt) {
632
638
  if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
633
639
  const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
634
- if (!a) return;
635
- const svg = isSvg(a);
636
- const href = svg ? a.href.baseVal : a.href;
637
- const target = svg ? a.target.baseVal : a.target;
638
- if (target || !href && !a.hasAttribute("state")) return;
640
+ if (!a || !a.hasAttribute("link")) return;
641
+ const href = a.href;
642
+ if (a.target || !href && !a.hasAttribute("state")) return;
639
643
  const rel = (a.getAttribute("rel") || "").split(/\s+/);
640
644
  if (a.hasAttribute("download") || rel && rel.includes("external")) return;
641
- const url = svg ? new URL(href, document.baseURI) : new URL(href);
645
+ const url = new URL(href);
642
646
  const pathname = urlDecode(url.pathname);
643
647
  if (url.origin !== window.location.origin || basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
644
648
  const to = parsePath(pathname + urlDecode(url.search, true) + urlDecode(url.hash));
@@ -650,8 +654,10 @@ function createRouterContext(integration, base = "", data, out) {
650
654
  scroll: !a.hasAttribute("noscroll"),
651
655
  state: state && JSON.parse(state)
652
656
  });
653
- }
657
+ } // ensure delegated events run first
654
658
 
659
+
660
+ delegateEvents(["click"]);
655
661
  document.addEventListener("click", handleAnchorClick);
656
662
  onCleanup(() => document.removeEventListener("click", handleAnchorClick));
657
663
  }
@@ -717,7 +723,7 @@ function createRouteContext(router, parent, child, match) {
717
723
  return route;
718
724
  }
719
725
 
720
- const _tmpl$ = /*#__PURE__*/template(`<a></a>`, 2);
726
+ const _tmpl$ = /*#__PURE__*/template(`<a link></a>`, 2);
721
727
  const Router = props => {
722
728
  const {
723
729
  source,
@@ -841,80 +847,52 @@ const Outlet = () => {
841
847
  })
842
848
  });
843
849
  };
844
-
845
- function LinkBase(props) {
846
- const [, rest] = splitProps(props, ["children", "to", "href", "state"]);
847
- const href = useHref(() => props.to);
848
- return (() => {
849
- const _el$ = _tmpl$.cloneNode(true);
850
-
851
- spread(_el$, rest, false, true);
852
-
853
- insert(_el$, () => props.children);
854
-
855
- effect(_p$ => {
856
- const _v$ = href() || props.href,
857
- _v$2 = JSON.stringify(props.state);
858
-
859
- _v$ !== _p$._v$ && setAttribute(_el$, "href", _p$._v$ = _v$);
860
- _v$2 !== _p$._v$2 && setAttribute(_el$, "state", _p$._v$2 = _v$2);
861
- return _p$;
862
- }, {
863
- _v$: undefined,
864
- _v$2: undefined
865
- });
866
-
867
- return _el$;
868
- })();
869
- }
870
-
871
- function Link(props) {
872
- const to = useResolvedPath(() => props.href);
873
- return createComponent$1(LinkBase, mergeProps$1(props, {
874
- get to() {
875
- return to();
876
- }
877
-
878
- }));
879
- }
880
- function NavLink(props) {
850
+ function A(props) {
881
851
  props = mergeProps({
882
852
  inactiveClass: "inactive",
883
853
  activeClass: "active"
884
854
  }, props);
885
- const [, rest] = splitProps(props, ["activeClass", "inactiveClass", "end"]);
886
- const location = useLocation();
855
+ const [, rest] = splitProps(props, ["href", "state", "activeClass", "inactiveClass", "end"]);
887
856
  const to = useResolvedPath(() => props.href);
857
+ const href = useHref(to);
858
+ const location = useLocation();
888
859
  const isActive = createMemo(() => {
889
860
  const to_ = to();
890
-
891
- if (to_ === undefined) {
892
- return false;
893
- }
894
-
861
+ if (to_ === undefined) return false;
895
862
  const path = to_.split(/[?#]/, 1)[0].toLowerCase();
896
863
  const loc = location.pathname.toLowerCase();
897
864
  return props.end ? path === loc : loc.startsWith(path);
898
865
  });
899
- return createComponent$1(LinkBase, mergeProps$1(rest, {
900
- get to() {
901
- return to();
902
- },
866
+ return (() => {
867
+ const _el$ = _tmpl$.cloneNode(true);
903
868
 
904
- get classList() {
905
- return {
869
+ spread(_el$, rest, false, false);
870
+
871
+ effect(_p$ => {
872
+ const _v$ = href() || props.href,
873
+ _v$2 = JSON.stringify(props.state),
874
+ _v$3 = {
906
875
  [props.inactiveClass]: !isActive(),
907
876
  [props.activeClass]: isActive(),
908
877
  ...rest.classList
909
- };
910
- },
878
+ },
879
+ _v$4 = isActive() ? "page" : undefined;
911
880
 
912
- get ["aria-current"]() {
913
- return isActive() ? "page" : undefined;
914
- }
881
+ _v$ !== _p$._v$ && setAttribute(_el$, "href", _p$._v$ = _v$);
882
+ _v$2 !== _p$._v$2 && setAttribute(_el$, "state", _p$._v$2 = _v$2);
883
+ _p$._v$3 = classList(_el$, _v$3, _p$._v$3);
884
+ _v$4 !== _p$._v$4 && setAttribute(_el$, "aria-current", _p$._v$4 = _v$4);
885
+ return _p$;
886
+ }, {
887
+ _v$: undefined,
888
+ _v$2: undefined,
889
+ _v$3: undefined,
890
+ _v$4: undefined
891
+ });
915
892
 
916
- }));
917
- }
893
+ return _el$;
894
+ })();
895
+ } // deprecated alias exports
918
896
  function Navigate(props) {
919
897
  const navigate = useNavigate();
920
898
  const location = useLocation();
@@ -933,4 +911,4 @@ function Navigate(props) {
933
911
  return null;
934
912
  }
935
913
 
936
- export { Link, NavLink, Navigate, Outlet, Route, Router, Routes, mergeSearchString as _mergeSearchString, createIntegration, hashIntegration, normalizeIntegration, pathIntegration, staticIntegration, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useRouteData, useRoutes, useSearchParams };
914
+ export { A, A as Link, A as NavLink, Navigate, Outlet, Route, Router, Routes, mergeSearchString as _mergeSearchString, createIntegration, hashIntegration, normalizeIntegration, pathIntegration, staticIntegration, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useRouteData, useRoutes, useSearchParams };
package/dist/routing.d.ts CHANGED
@@ -13,7 +13,7 @@ export declare const useMatch: (path: () => string) => Accessor<import("./types"
13
13
  export declare const useParams: <T extends Params>() => T;
14
14
  declare type MaybeReturnType<T> = T extends (...args: any) => infer R ? R : T;
15
15
  export declare const useRouteData: <T>() => MaybeReturnType<T>;
16
- export declare const useSearchParams: <T extends Params>() => [T, (params: SetParams, options?: Partial<NavigateOptions<unknown>> | undefined) => void];
16
+ export declare const useSearchParams: <T extends Params>() => [T, (params: SetParams, options?: Partial<NavigateOptions>) => void];
17
17
  export declare function createRoutes(routeDef: RouteDefinition, base?: string, fallback?: Component): Route[];
18
18
  export declare function createBranch(routes: Route[], index?: number): Branch;
19
19
  export declare function createBranches(routeDef: RouteDefinition | RouteDefinition[], base?: string, fallback?: Component, stack?: Route[], branches?: Branch[]): Branch[];
package/dist/routing.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, useTransition, resetErrorBoundaries } from "solid-js";
2
- import { isServer } from "solid-js/web";
1
+ import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
2
+ import { isServer, delegateEvents } from "solid-js/web";
3
3
  import { normalizeIntegration } from "./integration";
4
4
  import { createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, urlDecode, expandOptionals } from "./utils";
5
5
  const MAX_REDIRECTS = 100;
@@ -34,7 +34,7 @@ export const useSearchParams = () => {
34
34
  const navigate = useNavigate();
35
35
  const setSearchParams = (params, options) => {
36
36
  const searchString = untrack(() => mergeSearchString(location.search, params));
37
- navigate(searchString, { scroll: false, ...options, resolve: true });
37
+ navigate(location.pathname + searchString, { scroll: false, ...options });
38
38
  };
39
39
  return [location.query, setSearchParams];
40
40
  };
@@ -179,7 +179,16 @@ export function createRouterContext(integration, base = "", data, out) {
179
179
  else if (basePath && !source().value) {
180
180
  setSource({ value: basePath, replace: true, scroll: false });
181
181
  }
182
- const [isRouting, start] = useTransition();
182
+ const [isRouting, setIsRouting] = createSignal(false);
183
+ const start = async (callback) => {
184
+ setIsRouting(true);
185
+ try {
186
+ await startTransition(callback);
187
+ }
188
+ finally {
189
+ setIsRouting(false);
190
+ }
191
+ };
183
192
  const [reference, setReference] = createSignal(source().value);
184
193
  const [state, setState] = createSignal(source().state);
185
194
  const location = createLocation(reference, state);
@@ -292,9 +301,6 @@ export function createRouterContext(integration, base = "", data, out) {
292
301
  });
293
302
  });
294
303
  if (!isServer) {
295
- function isSvg(el) {
296
- return el.namespaceURI === "http://www.w3.org/2000/svg";
297
- }
298
304
  function handleAnchorClick(evt) {
299
305
  if (evt.defaultPrevented ||
300
306
  evt.button !== 0 ||
@@ -306,17 +312,15 @@ export function createRouterContext(integration, base = "", data, out) {
306
312
  const a = evt
307
313
  .composedPath()
308
314
  .find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
309
- if (!a)
315
+ if (!a || !a.hasAttribute("link"))
310
316
  return;
311
- const svg = isSvg(a);
312
- const href = svg ? a.href.baseVal : a.href;
313
- const target = svg ? a.target.baseVal : a.target;
314
- if (target || (!href && !a.hasAttribute("state")))
317
+ const href = a.href;
318
+ if (a.target || (!href && !a.hasAttribute("state")))
315
319
  return;
316
320
  const rel = (a.getAttribute("rel") || "").split(/\s+/);
317
321
  if (a.hasAttribute("download") || (rel && rel.includes("external")))
318
322
  return;
319
- const url = svg ? new URL(href, document.baseURI) : new URL(href);
323
+ const url = new URL(href);
320
324
  const pathname = urlDecode(url.pathname);
321
325
  if (url.origin !== window.location.origin ||
322
326
  (basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())))
@@ -331,6 +335,8 @@ export function createRouterContext(integration, base = "", data, out) {
331
335
  state: state && JSON.parse(state)
332
336
  });
333
337
  }
338
+ // ensure delegated events run first
339
+ delegateEvents(["click"]);
334
340
  document.addEventListener("click", handleAnchorClick);
335
341
  onCleanup(() => document.removeEventListener("click", handleAnchorClick));
336
342
  }
package/dist/types.d.ts CHANGED
@@ -33,13 +33,13 @@ export interface RouterIntegration {
33
33
  signal: LocationChangeSignal;
34
34
  utils?: Partial<RouterUtils>;
35
35
  }
36
- export interface RouteDataFuncArgs {
37
- data: unknown;
36
+ export interface RouteDataFuncArgs<T = unknown> {
37
+ data: T extends RouteDataFunc ? ReturnType<T> : T;
38
38
  params: Params;
39
39
  location: Location;
40
40
  navigate: Navigator;
41
41
  }
42
- export declare type RouteDataFunc<T = unknown> = (args: RouteDataFuncArgs) => T;
42
+ export declare type RouteDataFunc<T = unknown, R = unknown> = (args: RouteDataFuncArgs<T>) => R;
43
43
  export declare type RouteDefinition = {
44
44
  path: string | string[];
45
45
  data?: RouteDataFunc;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.4.2",
9
+ "version": "0.5.0",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",
@@ -38,23 +38,24 @@
38
38
  "pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\""
39
39
  },
40
40
  "devDependencies": {
41
- "@babel/core": "^7.15.8",
42
- "@babel/preset-typescript": "^7.15.0",
43
- "@rollup/plugin-babel": "5.3.0",
44
- "@rollup/plugin-node-resolve": "13.0.5",
45
- "@types/jest": "^27.0.2",
46
- "@types/node": "^16.10.3",
47
- "babel-preset-solid": "^1.4.4",
48
- "jest": "^27.2.5",
49
- "prettier": "^2.5.1",
50
- "rollup": "^2.52.1",
41
+ "@babel/core": "^7.18.13",
42
+ "@babel/preset-typescript": "^7.18.6",
43
+ "@rollup/plugin-babel": "5.3.1",
44
+ "@rollup/plugin-node-resolve": "13.3.0",
45
+ "@types/jest": "^29.0.0",
46
+ "@types/node": "^18.7.14",
47
+ "babel-preset-solid": "^1.5.3",
48
+ "jest": "^29.0.1",
49
+ "jest-environment-jsdom": "^29.1.2",
50
+ "prettier": "^2.7.1",
51
+ "rollup": "^2.79.0",
51
52
  "rollup-plugin-terser": "^7.0.2",
52
53
  "solid-jest": "^0.2.0",
53
- "solid-js": "^1.4.4",
54
- "typescript": "^4.5.4"
54
+ "solid-js": "^1.5.3",
55
+ "typescript": "^4.8.2"
55
56
  },
56
57
  "peerDependencies": {
57
- "solid-js": "^1.3.5"
58
+ "solid-js": "^1.5.3"
58
59
  },
59
60
  "jest": {
60
61
  "preset": "solid-jest/preset/browser"