@real-router/solid 0.1.2 → 0.2.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
@@ -192,6 +192,27 @@ Without `fallback`, no `<Suspense>` boundary is added. The prop is optional.
192
192
 
193
193
  > **Note:** `keepAlive` is not supported. Solid has no equivalent of React's `<Activity>` API. Components dispose completely when navigating away.
194
194
 
195
+ ### `<RouterErrorBoundary>`
196
+
197
+ Declarative error handling for navigation errors. Shows a fallback **alongside** children (not instead of) when a guard rejects or a route is not found.
198
+
199
+ ```tsx
200
+ import { RouterErrorBoundary } from "@real-router/solid";
201
+
202
+ <RouterErrorBoundary
203
+ fallback={(error, resetError) => (
204
+ <div class="toast">
205
+ {error.code} <button onClick={resetError}>Dismiss</button>
206
+ </div>
207
+ )}
208
+ onError={(error) => analytics.track("nav_error", { code: error.code })}
209
+ >
210
+ <Link routeName="protected">Go to Protected</Link>
211
+ </RouterErrorBoundary>;
212
+ ```
213
+
214
+ Auto-resets on next successful navigation. Works with both `<Link>` and imperative `router.navigate()`.
215
+
195
216
  ## Directives
196
217
 
197
218
  ### `use:link`
@@ -292,7 +313,7 @@ When enabled, a visually hidden `aria-live` region announces each navigation. Fo
292
313
 
293
314
  Full documentation: [Wiki](https://github.com/greydragon888/real-router/wiki)
294
315
 
295
- - [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [Link](https://github.com/greydragon888/real-router/wiki/Link)
316
+ - [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [RouterErrorBoundary](https://github.com/greydragon888/real-router/wiki/RouterErrorBoundary) · [Link](https://github.com/greydragon888/real-router/wiki/Link)
296
317
  - [useRouter](https://github.com/greydragon888/real-router/wiki/useRouter) · [useRoute](https://github.com/greydragon888/real-router/wiki/useRoute) · [useRouteNode](https://github.com/greydragon888/real-router/wiki/useRouteNode) · [useNavigator](https://github.com/greydragon888/real-router/wiki/useNavigator) · [useRouteUtils](https://github.com/greydragon888/real-router/wiki/useRouteUtils) · [useRouterTransition](https://github.com/greydragon888/real-router/wiki/useRouterTransition)
297
318
 
298
319
  ## Examples
@@ -1,7 +1,7 @@
1
1
  import * as solid_js from 'solid-js';
2
2
  import { JSX, Accessor, ParentProps } from 'solid-js';
3
3
  import * as _real_router_core from '@real-router/core';
4
- import { Params, NavigationOptions, State, Router, Navigator } from '@real-router/core';
4
+ import { Params, NavigationOptions, State, RouterError, Router, Navigator } from '@real-router/core';
5
5
  export { Navigator } from '@real-router/core';
6
6
  import { RouteUtils } from '@real-router/route-utils';
7
7
  import { RouterTransitionSnapshot, RouterSource } from '@real-router/sources';
@@ -56,6 +56,13 @@ interface LinkProps<P extends Params = Params> extends Omit<JSX.HTMLAttributes<H
56
56
 
57
57
  declare function Link<P extends Params = Params>(props: Readonly<LinkProps<P>>): JSX.Element;
58
58
 
59
+ interface RouterErrorBoundaryProps {
60
+ readonly children: JSX.Element;
61
+ readonly fallback: (error: RouterError, resetError: () => void) => JSX.Element;
62
+ readonly onError?: (error: RouterError, toRoute: State | null, fromRoute: State | null) => void;
63
+ }
64
+ declare function RouterErrorBoundary(props: RouterErrorBoundaryProps): JSX.Element;
65
+
59
66
  interface LinkDirectiveOptions<P extends Params = Params> {
60
67
  routeName: string;
61
68
  routeParams?: P;
@@ -100,5 +107,5 @@ declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>
100
107
 
101
108
  declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
102
109
 
103
- export { Link, RouteContext, RouteView, RouterContext, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
104
- export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps };
110
+ export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
111
+ export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, RouterErrorBoundaryProps };
package/dist/cjs/index.js CHANGED
@@ -208,6 +208,37 @@ function Link(props) {
208
208
  })();
209
209
  }
210
210
 
211
+ const cache = new WeakMap();
212
+ function useRouterError() {
213
+ const router = useRouter();
214
+ let source = cache.get(router);
215
+ if (!source) {
216
+ source = sources.createErrorSource(router);
217
+ cache.set(router, source);
218
+ }
219
+ return createSignalFromSource(source);
220
+ }
221
+
222
+ function RouterErrorBoundary(props) {
223
+ const snapshot = useRouterError();
224
+ const [dismissedVersion, setDismissedVersion] = solidJs.createSignal(-1);
225
+ solidJs.createEffect(() => {
226
+ const snap = snapshot();
227
+ if (snap.error) {
228
+ props.onError?.(snap.error, snap.toRoute, snap.fromRoute);
229
+ }
230
+ });
231
+ const visibleError = solidJs.createMemo(() => {
232
+ const snap = snapshot();
233
+ return snap.version > dismissedVersion() ? snap.error : null;
234
+ });
235
+ const resetError = () => setDismissedVersion(snapshot().version);
236
+ return [web.memo(() => props.children), web.memo(() => {
237
+ const error = visibleError();
238
+ return error ? props.fallback(error, resetError) : null;
239
+ })];
240
+ }
241
+
211
242
  function link(element, accessor) {
212
243
  const router = useRouter();
213
244
  const options = accessor();
@@ -337,6 +368,7 @@ exports.Link = Link;
337
368
  exports.RouteContext = RouteContext;
338
369
  exports.RouteView = RouteView;
339
370
  exports.RouterContext = RouterContext;
371
+ exports.RouterErrorBoundary = RouterErrorBoundary;
340
372
  exports.RouterProvider = RouterProvider;
341
373
  exports.createSignalFromSource = createSignalFromSource;
342
374
  exports.createStoreFromSource = createStoreFromSource;
@@ -1,7 +1,7 @@
1
1
  import * as solid_js from 'solid-js';
2
2
  import { JSX, Accessor, ParentProps } from 'solid-js';
3
3
  import * as _real_router_core from '@real-router/core';
4
- import { Params, NavigationOptions, State, Router, Navigator } from '@real-router/core';
4
+ import { Params, NavigationOptions, State, RouterError, Router, Navigator } from '@real-router/core';
5
5
  export { Navigator } from '@real-router/core';
6
6
  import { RouteUtils } from '@real-router/route-utils';
7
7
  import { RouterTransitionSnapshot, RouterSource } from '@real-router/sources';
@@ -56,6 +56,13 @@ interface LinkProps<P extends Params = Params> extends Omit<JSX.HTMLAttributes<H
56
56
 
57
57
  declare function Link<P extends Params = Params>(props: Readonly<LinkProps<P>>): JSX.Element;
58
58
 
59
+ interface RouterErrorBoundaryProps {
60
+ readonly children: JSX.Element;
61
+ readonly fallback: (error: RouterError, resetError: () => void) => JSX.Element;
62
+ readonly onError?: (error: RouterError, toRoute: State | null, fromRoute: State | null) => void;
63
+ }
64
+ declare function RouterErrorBoundary(props: RouterErrorBoundaryProps): JSX.Element;
65
+
59
66
  interface LinkDirectiveOptions<P extends Params = Params> {
60
67
  routeName: string;
61
68
  routeParams?: P;
@@ -100,5 +107,5 @@ declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>
100
107
 
101
108
  declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
102
109
 
103
- export { Link, RouteContext, RouteView, RouterContext, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
104
- export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps };
110
+ export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
111
+ export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, RouterErrorBoundaryProps };
@@ -1,5 +1,5 @@
1
1
  import { createComponent, memo, spread, mergeProps as mergeProps$1, insert, template } from 'solid-js/web';
2
- import { createRouteNodeSource, createActiveRouteSource, createRouteSource, createTransitionSource } from '@real-router/sources';
2
+ import { createRouteNodeSource, createActiveRouteSource, createErrorSource, createRouteSource, createTransitionSource } from '@real-router/sources';
3
3
  import { Suspense, createSignal, onCleanup, createContext, useContext, children, mergeProps, splitProps, createMemo, createEffect, onMount, createSelector } from 'solid-js';
4
4
  import { getPluginApi } from '@real-router/core/api';
5
5
  import { startsWithSegment, getRouteUtils } from '@real-router/route-utils';
@@ -206,6 +206,37 @@ function Link(props) {
206
206
  })();
207
207
  }
208
208
 
209
+ const cache = new WeakMap();
210
+ function useRouterError() {
211
+ const router = useRouter();
212
+ let source = cache.get(router);
213
+ if (!source) {
214
+ source = createErrorSource(router);
215
+ cache.set(router, source);
216
+ }
217
+ return createSignalFromSource(source);
218
+ }
219
+
220
+ function RouterErrorBoundary(props) {
221
+ const snapshot = useRouterError();
222
+ const [dismissedVersion, setDismissedVersion] = createSignal(-1);
223
+ createEffect(() => {
224
+ const snap = snapshot();
225
+ if (snap.error) {
226
+ props.onError?.(snap.error, snap.toRoute, snap.fromRoute);
227
+ }
228
+ });
229
+ const visibleError = createMemo(() => {
230
+ const snap = snapshot();
231
+ return snap.version > dismissedVersion() ? snap.error : null;
232
+ });
233
+ const resetError = () => setDismissedVersion(snapshot().version);
234
+ return [memo(() => props.children), memo(() => {
235
+ const error = visibleError();
236
+ return error ? props.fallback(error, resetError) : null;
237
+ })];
238
+ }
239
+
209
240
  function link(element, accessor) {
210
241
  const router = useRouter();
211
242
  const options = accessor();
@@ -331,4 +362,4 @@ function RouterProvider(props) {
331
362
  });
332
363
  }
333
364
 
334
- export { Link, RouteContext, RouteView, RouterContext, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
365
+ export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
@@ -0,0 +1,9 @@
1
+ import type { RouterError, State } from "@real-router/core";
2
+ import type { JSX } from "solid-js";
3
+ export interface RouterErrorBoundaryProps {
4
+ readonly children: JSX.Element;
5
+ readonly fallback: (error: RouterError, resetError: () => void) => JSX.Element;
6
+ readonly onError?: (error: RouterError, toRoute: State | null, fromRoute: State | null) => void;
7
+ }
8
+ export declare function RouterErrorBoundary(props: RouterErrorBoundaryProps): JSX.Element;
9
+ //# sourceMappingURL=RouterErrorBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/RouterErrorBoundary.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,IAAI,KACnB,GAAG,CAAC,OAAO,CAAC;IACjB,QAAQ,CAAC,OAAO,CAAC,EAAE,CACjB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,KAAK,GAAG,IAAI,EACrB,SAAS,EAAE,KAAK,GAAG,IAAI,KACpB,IAAI,CAAC;CACX;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,GAAG,CAAC,OAAO,CA8Bb"}
@@ -0,0 +1,4 @@
1
+ import type { RouterErrorSnapshot } from "@real-router/sources";
2
+ import type { Accessor } from "solid-js";
3
+ export declare function useRouterError(): Accessor<RouterErrorSnapshot>;
4
+ //# sourceMappingURL=useRouterError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRouterError.d.ts","sourceRoot":"","sources":["../../../src/hooks/useRouterError.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIzC,wBAAgB,cAAc,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAW9D"}
@@ -1,5 +1,6 @@
1
1
  export { RouteView } from "./components/RouteView";
2
2
  export { Link } from "./components/Link";
3
+ export { RouterErrorBoundary } from "./components/RouterErrorBoundary";
3
4
  export { link } from "./directives/link";
4
5
  export { useRouter } from "./hooks/useRouter";
5
6
  export { useNavigator } from "./hooks/useNavigator";
@@ -14,6 +15,7 @@ export { RouterContext, RouteContext } from "./context";
14
15
  export { createSignalFromSource } from "./createSignalFromSource";
15
16
  export { createStoreFromSource } from "./createStoreFromSource";
16
17
  export type { LinkProps, RouteState } from "./types";
18
+ export type { RouterErrorBoundaryProps } from "./components/RouterErrorBoundary";
17
19
  export type { LinkDirectiveOptions } from "./directives/link";
18
20
  export type { RouteViewProps, RouteViewMatchProps, RouteViewNotFoundProps, } from "./components/RouteView";
19
21
  export type { Navigator } from "@real-router/core";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErD,YAAY,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAEjF,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/solid",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "type": "commonjs",
5
5
  "description": "Solid.js integration for Real-Router",
6
6
  "main": "./dist/cjs/index.js",
@@ -51,9 +51,9 @@
51
51
  "license": "MIT",
52
52
  "sideEffects": false,
53
53
  "dependencies": {
54
- "@real-router/core": "^0.40.0",
55
54
  "@real-router/route-utils": "^0.1.6",
56
- "@real-router/sources": "^0.2.7",
55
+ "@real-router/core": "^0.40.1",
56
+ "@real-router/sources": "^0.3.0",
57
57
  "dom-utils": "^0.2.2"
58
58
  },
59
59
  "devDependencies": {
@@ -72,7 +72,7 @@
72
72
  "solid-js": "1.9.5",
73
73
  "vite-plugin-solid": "2.11.11",
74
74
  "vitest": "4.1.0",
75
- "@real-router/browser-plugin": "^0.10.5"
75
+ "@real-router/browser-plugin": "^0.10.6"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "solid-js": ">=1.7.0"
@@ -84,6 +84,7 @@
84
84
  "type-check": "tsc --noEmit",
85
85
  "lint": "eslint --cache --ext .ts,.tsx src/ tests/ --fix --max-warnings 0",
86
86
  "lint:package": "publint",
87
- "lint:types": "attw --pack ."
87
+ "lint:types": "attw --pack .",
88
+ "build:dist-only": "rimraf dist && tsc -p tsconfig.build.json && rollup -c rollup.config.mjs"
88
89
  }
89
90
  }
@@ -0,0 +1,53 @@
1
+ import { createEffect, createMemo, createSignal } from "solid-js";
2
+
3
+ import { useRouterError } from "../hooks/useRouterError";
4
+
5
+ import type { RouterError, State } from "@real-router/core";
6
+ import type { JSX } from "solid-js";
7
+
8
+ export interface RouterErrorBoundaryProps {
9
+ readonly children: JSX.Element;
10
+ readonly fallback: (
11
+ error: RouterError,
12
+ resetError: () => void,
13
+ ) => JSX.Element;
14
+ readonly onError?: (
15
+ error: RouterError,
16
+ toRoute: State | null,
17
+ fromRoute: State | null,
18
+ ) => void;
19
+ }
20
+
21
+ export function RouterErrorBoundary(
22
+ props: RouterErrorBoundaryProps,
23
+ ): JSX.Element {
24
+ const snapshot = useRouterError();
25
+ const [dismissedVersion, setDismissedVersion] = createSignal(-1);
26
+
27
+ createEffect(() => {
28
+ const snap = snapshot();
29
+
30
+ if (snap.error) {
31
+ props.onError?.(snap.error, snap.toRoute, snap.fromRoute);
32
+ }
33
+ });
34
+
35
+ const visibleError = createMemo(() => {
36
+ const snap = snapshot();
37
+
38
+ return snap.version > dismissedVersion() ? snap.error : null;
39
+ });
40
+
41
+ const resetError = () => setDismissedVersion(snapshot().version);
42
+
43
+ return (
44
+ <>
45
+ {props.children}
46
+ {(() => {
47
+ const error = visibleError();
48
+
49
+ return error ? props.fallback(error, resetError) : null;
50
+ })()}
51
+ </>
52
+ );
53
+ }
@@ -0,0 +1,23 @@
1
+ import { createErrorSource } from "@real-router/sources";
2
+
3
+ import { createSignalFromSource } from "../createSignalFromSource";
4
+ import { useRouter } from "./useRouter";
5
+
6
+ import type { Router } from "@real-router/core";
7
+ import type { RouterErrorSnapshot, RouterSource } from "@real-router/sources";
8
+ import type { Accessor } from "solid-js";
9
+
10
+ const cache = new WeakMap<Router, RouterSource<RouterErrorSnapshot>>();
11
+
12
+ export function useRouterError(): Accessor<RouterErrorSnapshot> {
13
+ const router = useRouter();
14
+
15
+ let source = cache.get(router);
16
+
17
+ if (!source) {
18
+ source = createErrorSource(router);
19
+ cache.set(router, source);
20
+ }
21
+
22
+ return createSignalFromSource(source);
23
+ }
package/src/index.tsx CHANGED
@@ -2,6 +2,8 @@ export { RouteView } from "./components/RouteView";
2
2
 
3
3
  export { Link } from "./components/Link";
4
4
 
5
+ export { RouterErrorBoundary } from "./components/RouterErrorBoundary";
6
+
5
7
  export { link } from "./directives/link";
6
8
 
7
9
  export { useRouter } from "./hooks/useRouter";
@@ -30,6 +32,8 @@ export { createStoreFromSource } from "./createStoreFromSource";
30
32
 
31
33
  export type { LinkProps, RouteState } from "./types";
32
34
 
35
+ export type { RouterErrorBoundaryProps } from "./components/RouterErrorBoundary";
36
+
33
37
  export type { LinkDirectiveOptions } from "./directives/link";
34
38
 
35
39
  export type {