@real-router/solid 0.2.8 → 0.2.10
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/dist/cjs/index.d.ts +2 -2
- package/dist/esm/index.d.mts +2 -2
- package/dist/types/context.d.ts +1 -1
- package/dist/types/context.d.ts.map +1 -1
- package/package.json +10 -9
- package/src/RouterProvider.tsx +60 -0
- package/src/components/Link.tsx +96 -0
- package/src/components/RouteView/RouteView.tsx +53 -0
- package/src/components/RouteView/components.tsx +50 -0
- package/src/components/RouteView/helpers.tsx +108 -0
- package/src/components/RouteView/index.ts +7 -0
- package/src/components/RouteView/types.ts +17 -0
- package/src/components/RouterErrorBoundary.tsx +53 -0
- package/src/constants.ts +9 -0
- package/src/context.ts +15 -0
- package/src/createSignalFromSource.ts +20 -0
- package/src/createStoreFromSource.ts +20 -0
- package/src/directives/link.tsx +86 -0
- package/src/directives.d.ts +10 -0
- package/src/hooks/useNavigator.tsx +15 -0
- package/src/hooks/useRoute.tsx +16 -0
- package/src/hooks/useRouteNode.tsx +14 -0
- package/src/hooks/useRouteNodeStore.tsx +12 -0
- package/src/hooks/useRouteStore.tsx +20 -0
- package/src/hooks/useRouteUtils.tsx +12 -0
- package/src/hooks/useRouter.tsx +15 -0
- package/src/hooks/useRouterError.tsx +23 -0
- package/src/hooks/useRouterTransition.tsx +14 -0
- package/src/index.tsx +47 -0
- package/src/types.ts +21 -0
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as solid_js from 'solid-js';
|
|
2
2
|
import { JSX, Accessor, ParentProps } from 'solid-js';
|
|
3
|
-
import * as _real_router_core from '@real-router/core';
|
|
4
3
|
import { Params, NavigationOptions, State, RouterError, Router, Navigator } from '@real-router/core';
|
|
5
4
|
export { Navigator } from '@real-router/core';
|
|
6
5
|
import { RouteUtils } from '@real-router/route-utils';
|
|
7
6
|
import { RouterTransitionSnapshot, RouterSource } from '@real-router/sources';
|
|
8
7
|
export { RouterTransitionSnapshot } from '@real-router/sources';
|
|
8
|
+
import * as _real_router_types from '@real-router/types';
|
|
9
9
|
|
|
10
10
|
interface RouteViewProps {
|
|
11
11
|
readonly nodeName: string;
|
|
@@ -101,7 +101,7 @@ interface RouterContextValue {
|
|
|
101
101
|
routeSelector: (routeName: string) => boolean;
|
|
102
102
|
}
|
|
103
103
|
declare const RouterContext: solid_js.Context<RouterContextValue | null>;
|
|
104
|
-
declare const RouteContext: solid_js.Context<Accessor<RouteState<
|
|
104
|
+
declare const RouteContext: solid_js.Context<Accessor<RouteState<_real_router_types.Params>> | null>;
|
|
105
105
|
|
|
106
106
|
declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>;
|
|
107
107
|
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as solid_js from 'solid-js';
|
|
2
2
|
import { JSX, Accessor, ParentProps } from 'solid-js';
|
|
3
|
-
import * as _real_router_core from '@real-router/core';
|
|
4
3
|
import { Params, NavigationOptions, State, RouterError, Router, Navigator } from '@real-router/core';
|
|
5
4
|
export { Navigator } from '@real-router/core';
|
|
6
5
|
import { RouteUtils } from '@real-router/route-utils';
|
|
7
6
|
import { RouterTransitionSnapshot, RouterSource } from '@real-router/sources';
|
|
8
7
|
export { RouterTransitionSnapshot } from '@real-router/sources';
|
|
8
|
+
import * as _real_router_types from '@real-router/types';
|
|
9
9
|
|
|
10
10
|
interface RouteViewProps {
|
|
11
11
|
readonly nodeName: string;
|
|
@@ -101,7 +101,7 @@ interface RouterContextValue {
|
|
|
101
101
|
routeSelector: (routeName: string) => boolean;
|
|
102
102
|
}
|
|
103
103
|
declare const RouterContext: solid_js.Context<RouterContextValue | null>;
|
|
104
|
-
declare const RouteContext: solid_js.Context<Accessor<RouteState<
|
|
104
|
+
declare const RouteContext: solid_js.Context<Accessor<RouteState<_real_router_types.Params>> | null>;
|
|
105
105
|
|
|
106
106
|
declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>;
|
|
107
107
|
|
package/dist/types/context.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export interface RouterContextValue {
|
|
|
7
7
|
routeSelector: (routeName: string) => boolean;
|
|
8
8
|
}
|
|
9
9
|
export declare const RouterContext: import("solid-js", { with: { "resolution-mode": "import" } }).Context<RouterContextValue | null>;
|
|
10
|
-
export declare const RouteContext: import("solid-js", { with: { "resolution-mode": "import" } }).Context<Accessor<RouteState<import("@real-router/
|
|
10
|
+
export declare const RouteContext: import("solid-js", { with: { "resolution-mode": "import" } }).Context<Accessor<RouteState<import("@real-router/types").Params>> | null>;
|
|
11
11
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC/C;AAED,eAAO,MAAM,aAAa,kGAAiD,CAAC;AAE5E,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC/C;AAED,eAAO,MAAM,aAAa,kGAAiD,CAAC;AAE5E,eAAO,MAAM,YAAY,yIAAmD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@real-router/solid",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "Solid.js integration for Real-Router",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"types": "./dist/cjs/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"development": "./src/index.tsx",
|
|
12
11
|
"types": {
|
|
13
12
|
"import": "./dist/esm/index.d.mts",
|
|
14
13
|
"require": "./dist/cjs/index.d.ts"
|
|
@@ -18,7 +17,8 @@
|
|
|
18
17
|
}
|
|
19
18
|
},
|
|
20
19
|
"files": [
|
|
21
|
-
"dist"
|
|
20
|
+
"dist",
|
|
21
|
+
"src"
|
|
22
22
|
],
|
|
23
23
|
"homepage": "https://github.com/greydragon888/real-router",
|
|
24
24
|
"repository": {
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"sideEffects": false,
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@real-router/core": "^0.
|
|
54
|
-
"@real-router/route-utils": "^0.1.
|
|
55
|
-
"@real-router/sources": "^0.4.
|
|
53
|
+
"@real-router/core": "^0.46.0",
|
|
54
|
+
"@real-router/route-utils": "^0.1.14",
|
|
55
|
+
"@real-router/sources": "^0.4.4"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@babel/core": "7.29.0",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"solid-js": "1.9.12",
|
|
71
71
|
"vite-plugin-solid": "2.11.11",
|
|
72
72
|
"vitest": "4.1.0",
|
|
73
|
-
"dom-utils": "^0.2.
|
|
74
|
-
"@real-router/browser-plugin": "^0.11.
|
|
73
|
+
"dom-utils": "^0.2.8",
|
|
74
|
+
"@real-router/browser-plugin": "^0.11.7"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"solid-js": ">=1.7.0"
|
|
@@ -79,10 +79,11 @@
|
|
|
79
79
|
"scripts": {
|
|
80
80
|
"build": "rimraf dist && tsc -p tsconfig.build.json && rollup -c rollup.config.mjs",
|
|
81
81
|
"test": "vitest",
|
|
82
|
+
"test:properties": "vitest run --config vitest.config.properties.mts",
|
|
82
83
|
"test:stress": "vitest run --config vitest.config.stress.mts",
|
|
83
84
|
"type-check": "tsc --noEmit",
|
|
84
85
|
"lint": "eslint --cache --ext .ts,.tsx src/ tests/ --fix --max-warnings 0",
|
|
85
|
-
"lint:package": "
|
|
86
|
+
"lint:package": "publint",
|
|
86
87
|
"lint:types": "attw --pack .",
|
|
87
88
|
"build:dist-only": "rimraf dist && tsc -p tsconfig.build.json && rollup -c rollup.config.mjs"
|
|
88
89
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getNavigator } from "@real-router/core";
|
|
2
|
+
import { createRouteSource } from "@real-router/sources";
|
|
3
|
+
import { createRouteAnnouncer } from "dom-utils";
|
|
4
|
+
import { createSelector, onCleanup, onMount } from "solid-js";
|
|
5
|
+
|
|
6
|
+
import { RouterContext, RouteContext } from "./context";
|
|
7
|
+
import { createSignalFromSource } from "./createSignalFromSource";
|
|
8
|
+
|
|
9
|
+
import type { Router } from "@real-router/core";
|
|
10
|
+
import type { ParentProps, JSX } from "solid-js";
|
|
11
|
+
|
|
12
|
+
export interface RouteProviderProps {
|
|
13
|
+
router: Router;
|
|
14
|
+
announceNavigation?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isRouteActive(
|
|
18
|
+
linkRouteName: string,
|
|
19
|
+
currentRouteName: string,
|
|
20
|
+
): boolean {
|
|
21
|
+
return (
|
|
22
|
+
currentRouteName === linkRouteName ||
|
|
23
|
+
currentRouteName.startsWith(`${linkRouteName}.`)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function RouterProvider(
|
|
28
|
+
props: ParentProps<RouteProviderProps>,
|
|
29
|
+
): JSX.Element {
|
|
30
|
+
onMount(() => {
|
|
31
|
+
if (!props.announceNavigation) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const announcer = createRouteAnnouncer(props.router);
|
|
36
|
+
|
|
37
|
+
onCleanup(() => {
|
|
38
|
+
announcer.destroy();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const navigator = getNavigator(props.router);
|
|
43
|
+
const routeSource = createRouteSource(props.router);
|
|
44
|
+
const routeSignal = createSignalFromSource(routeSource);
|
|
45
|
+
|
|
46
|
+
const routeSelector = createSelector(
|
|
47
|
+
() => routeSignal().route?.name ?? "",
|
|
48
|
+
isRouteActive,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<RouterContext.Provider
|
|
53
|
+
value={{ router: props.router, navigator, routeSelector }}
|
|
54
|
+
>
|
|
55
|
+
<RouteContext.Provider value={routeSignal}>
|
|
56
|
+
{props.children}
|
|
57
|
+
</RouteContext.Provider>
|
|
58
|
+
</RouterContext.Provider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createActiveRouteSource } from "@real-router/sources";
|
|
2
|
+
import { shouldNavigate, buildHref, buildActiveClassName } from "dom-utils";
|
|
3
|
+
import { createMemo, mergeProps, splitProps, useContext } from "solid-js";
|
|
4
|
+
|
|
5
|
+
import { EMPTY_PARAMS, EMPTY_OPTIONS } from "../constants";
|
|
6
|
+
import { RouterContext } from "../context";
|
|
7
|
+
import { createSignalFromSource } from "../createSignalFromSource";
|
|
8
|
+
import { useRouter } from "../hooks/useRouter";
|
|
9
|
+
|
|
10
|
+
import type { LinkProps } from "../types";
|
|
11
|
+
import type { Params } from "@real-router/core";
|
|
12
|
+
import type { JSX } from "solid-js";
|
|
13
|
+
|
|
14
|
+
export function Link<P extends Params = Params>(
|
|
15
|
+
props: Readonly<LinkProps<P>>,
|
|
16
|
+
): JSX.Element {
|
|
17
|
+
const merged = mergeProps(
|
|
18
|
+
{
|
|
19
|
+
routeParams: EMPTY_PARAMS as P,
|
|
20
|
+
routeOptions: EMPTY_OPTIONS,
|
|
21
|
+
activeClassName: "active",
|
|
22
|
+
activeStrict: false,
|
|
23
|
+
ignoreQueryParams: true,
|
|
24
|
+
},
|
|
25
|
+
props,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const [local, rest] = splitProps(merged, [
|
|
29
|
+
"routeName",
|
|
30
|
+
"routeParams",
|
|
31
|
+
"routeOptions",
|
|
32
|
+
"activeClassName",
|
|
33
|
+
"activeStrict",
|
|
34
|
+
"ignoreQueryParams",
|
|
35
|
+
"onClick",
|
|
36
|
+
"target",
|
|
37
|
+
"class",
|
|
38
|
+
"children",
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
const router = useRouter();
|
|
42
|
+
const ctx = useContext(RouterContext);
|
|
43
|
+
|
|
44
|
+
const useFastPath =
|
|
45
|
+
ctx?.routeSelector &&
|
|
46
|
+
!local.activeStrict &&
|
|
47
|
+
local.ignoreQueryParams &&
|
|
48
|
+
local.routeParams === EMPTY_PARAMS;
|
|
49
|
+
|
|
50
|
+
const isActive = useFastPath
|
|
51
|
+
? () => ctx.routeSelector(local.routeName)
|
|
52
|
+
: createSignalFromSource(
|
|
53
|
+
createActiveRouteSource(router, local.routeName, local.routeParams, {
|
|
54
|
+
strict: local.activeStrict,
|
|
55
|
+
ignoreQueryParams: local.ignoreQueryParams,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const href = createMemo(() =>
|
|
60
|
+
buildHref(router, local.routeName, local.routeParams),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const handleClick = (evt: MouseEvent) => {
|
|
64
|
+
if (local.onClick) {
|
|
65
|
+
local.onClick(evt);
|
|
66
|
+
|
|
67
|
+
if (evt.defaultPrevented) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!shouldNavigate(evt) || local.target === "_blank") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
evt.preventDefault();
|
|
77
|
+
router
|
|
78
|
+
.navigate(local.routeName, local.routeParams, local.routeOptions)
|
|
79
|
+
.catch(() => {});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const finalClassName = createMemo(() =>
|
|
83
|
+
buildActiveClassName(isActive(), local.activeClassName, local.class),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<a
|
|
88
|
+
{...(rest as JSX.HTMLAttributes<HTMLAnchorElement>)}
|
|
89
|
+
href={href()}
|
|
90
|
+
class={finalClassName()}
|
|
91
|
+
onClick={handleClick}
|
|
92
|
+
>
|
|
93
|
+
{local.children}
|
|
94
|
+
</a>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { children as resolveChildren } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import { Match, NotFound } from "./components";
|
|
4
|
+
import { buildRenderList, collectElements } from "./helpers";
|
|
5
|
+
import { useRouteNode } from "../../hooks/useRouteNode";
|
|
6
|
+
|
|
7
|
+
import type { RouteViewMarker } from "./components";
|
|
8
|
+
import type { RouteViewProps } from "./types";
|
|
9
|
+
import type { JSX } from "solid-js";
|
|
10
|
+
|
|
11
|
+
function RouteViewRoot(props: Readonly<RouteViewProps>): JSX.Element {
|
|
12
|
+
const routeState = useRouteNode(props.nodeName);
|
|
13
|
+
|
|
14
|
+
const resolved = resolveChildren(() => props.children);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
{(() => {
|
|
19
|
+
const state = routeState();
|
|
20
|
+
|
|
21
|
+
if (!state.route) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const elements: RouteViewMarker[] = [];
|
|
26
|
+
|
|
27
|
+
collectElements(resolved(), elements);
|
|
28
|
+
|
|
29
|
+
const { rendered } = buildRenderList(
|
|
30
|
+
elements,
|
|
31
|
+
state.route.name,
|
|
32
|
+
props.nodeName,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (rendered.length > 0) {
|
|
36
|
+
return rendered;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
})()}
|
|
41
|
+
</>
|
|
42
|
+
) as unknown as JSX.Element;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
RouteViewRoot.displayName = "RouteView";
|
|
46
|
+
|
|
47
|
+
export const RouteView = Object.assign(RouteViewRoot, { Match, NotFound });
|
|
48
|
+
|
|
49
|
+
export type {
|
|
50
|
+
RouteViewProps,
|
|
51
|
+
MatchProps as RouteViewMatchProps,
|
|
52
|
+
NotFoundProps as RouteViewNotFoundProps,
|
|
53
|
+
} from "./types";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { MatchProps, NotFoundProps } from "./types";
|
|
2
|
+
import type { JSX } from "solid-js";
|
|
3
|
+
|
|
4
|
+
export const MATCH_MARKER = Symbol.for("RouteView.Match");
|
|
5
|
+
|
|
6
|
+
export const NOT_FOUND_MARKER = Symbol.for("RouteView.NotFound");
|
|
7
|
+
|
|
8
|
+
export interface MatchMarker {
|
|
9
|
+
$$type: typeof MATCH_MARKER;
|
|
10
|
+
segment: string;
|
|
11
|
+
exact: boolean;
|
|
12
|
+
fallback?: JSX.Element;
|
|
13
|
+
children: JSX.Element;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface NotFoundMarker {
|
|
17
|
+
$$type: typeof NOT_FOUND_MARKER;
|
|
18
|
+
children: JSX.Element;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type RouteViewMarker = MatchMarker | NotFoundMarker;
|
|
22
|
+
|
|
23
|
+
export function Match(props: MatchProps): JSX.Element {
|
|
24
|
+
const result = {
|
|
25
|
+
$$type: MATCH_MARKER,
|
|
26
|
+
segment: props.segment,
|
|
27
|
+
exact: props.exact ?? false,
|
|
28
|
+
fallback: props.fallback,
|
|
29
|
+
get children(): JSX.Element {
|
|
30
|
+
return props.children;
|
|
31
|
+
},
|
|
32
|
+
} as MatchMarker;
|
|
33
|
+
|
|
34
|
+
return result as unknown as JSX.Element;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Match.displayName = "RouteView.Match";
|
|
38
|
+
|
|
39
|
+
export function NotFound(props: NotFoundProps): JSX.Element {
|
|
40
|
+
const result = {
|
|
41
|
+
$$type: NOT_FOUND_MARKER,
|
|
42
|
+
get children(): JSX.Element {
|
|
43
|
+
return props.children;
|
|
44
|
+
},
|
|
45
|
+
} as NotFoundMarker;
|
|
46
|
+
|
|
47
|
+
return result as unknown as JSX.Element;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
NotFound.displayName = "RouteView.NotFound";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { UNKNOWN_ROUTE } from "@real-router/core";
|
|
2
|
+
import { startsWithSegment } from "@real-router/route-utils";
|
|
3
|
+
import { Suspense } from "solid-js";
|
|
4
|
+
|
|
5
|
+
import { MATCH_MARKER, NOT_FOUND_MARKER } from "./components";
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
MatchMarker,
|
|
9
|
+
NotFoundMarker,
|
|
10
|
+
RouteViewMarker,
|
|
11
|
+
} from "./components";
|
|
12
|
+
import type { JSX } from "solid-js";
|
|
13
|
+
|
|
14
|
+
function isSegmentMatch(
|
|
15
|
+
routeName: string,
|
|
16
|
+
fullSegmentName: string,
|
|
17
|
+
exact: boolean,
|
|
18
|
+
): boolean {
|
|
19
|
+
if (exact) {
|
|
20
|
+
return routeName === fullSegmentName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return startsWithSegment(routeName, fullSegmentName);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isMatchMarker(value: unknown): value is MatchMarker {
|
|
27
|
+
return (
|
|
28
|
+
value != null &&
|
|
29
|
+
typeof value === "object" &&
|
|
30
|
+
"$$type" in value &&
|
|
31
|
+
value.$$type === MATCH_MARKER
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isNotFoundMarker(value: unknown): value is NotFoundMarker {
|
|
36
|
+
return (
|
|
37
|
+
value != null &&
|
|
38
|
+
typeof value === "object" &&
|
|
39
|
+
"$$type" in value &&
|
|
40
|
+
value.$$type === NOT_FOUND_MARKER
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function collectElements(
|
|
45
|
+
children: unknown,
|
|
46
|
+
result: RouteViewMarker[],
|
|
47
|
+
): void {
|
|
48
|
+
if (children == null) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(children)) {
|
|
53
|
+
for (const child of children) {
|
|
54
|
+
collectElements(child, result);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isMatchMarker(children) || isNotFoundMarker(children)) {
|
|
61
|
+
result.push(children);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function buildRenderList(
|
|
66
|
+
elements: RouteViewMarker[],
|
|
67
|
+
routeName: string,
|
|
68
|
+
nodeName: string,
|
|
69
|
+
): { rendered: JSX.Element[]; activeMatchFound: boolean } {
|
|
70
|
+
let notFoundChildren: JSX.Element | null = null;
|
|
71
|
+
let activeMatchFound = false;
|
|
72
|
+
const rendered: JSX.Element[] = [];
|
|
73
|
+
|
|
74
|
+
for (const child of elements) {
|
|
75
|
+
if (isNotFoundMarker(child)) {
|
|
76
|
+
notFoundChildren = child.children;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { segment, exact, fallback } = child;
|
|
81
|
+
const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
|
|
82
|
+
const isActive =
|
|
83
|
+
!activeMatchFound && isSegmentMatch(routeName, fullSegmentName, exact);
|
|
84
|
+
|
|
85
|
+
if (isActive) {
|
|
86
|
+
activeMatchFound = true;
|
|
87
|
+
const matchContent = child.children;
|
|
88
|
+
const content =
|
|
89
|
+
fallback === undefined ? (
|
|
90
|
+
matchContent
|
|
91
|
+
) : (
|
|
92
|
+
<Suspense fallback={fallback}>{matchContent}</Suspense>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
rendered.push(content);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
!activeMatchFound &&
|
|
101
|
+
routeName === UNKNOWN_ROUTE &&
|
|
102
|
+
notFoundChildren !== null
|
|
103
|
+
) {
|
|
104
|
+
rendered.push(notFoundChildren);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { rendered, activeMatchFound };
|
|
108
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { JSX } from "solid-js";
|
|
2
|
+
|
|
3
|
+
export interface RouteViewProps {
|
|
4
|
+
readonly nodeName: string;
|
|
5
|
+
readonly children: JSX.Element;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface MatchProps {
|
|
9
|
+
readonly segment: string;
|
|
10
|
+
readonly exact?: boolean;
|
|
11
|
+
readonly fallback?: JSX.Element;
|
|
12
|
+
readonly children: JSX.Element;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface NotFoundProps {
|
|
16
|
+
readonly children: JSX.Element;
|
|
17
|
+
}
|
|
@@ -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
|
+
}
|
package/src/constants.ts
ADDED
package/src/context.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createContext } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import type { RouteState } from "./types";
|
|
4
|
+
import type { Router, Navigator } from "@real-router/core";
|
|
5
|
+
import type { Accessor } from "solid-js";
|
|
6
|
+
|
|
7
|
+
export interface RouterContextValue {
|
|
8
|
+
router: Router;
|
|
9
|
+
navigator: Navigator;
|
|
10
|
+
routeSelector: (routeName: string) => boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const RouterContext = createContext<RouterContextValue | null>(null);
|
|
14
|
+
|
|
15
|
+
export const RouteContext = createContext<Accessor<RouteState> | null>(null);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createSignal, onCleanup } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import type { RouterSource } from "@real-router/sources";
|
|
4
|
+
import type { Accessor } from "solid-js";
|
|
5
|
+
|
|
6
|
+
export function createSignalFromSource<T>(
|
|
7
|
+
source: RouterSource<T>,
|
|
8
|
+
): Accessor<T> {
|
|
9
|
+
const [value, setValue] = createSignal<T>(source.getSnapshot());
|
|
10
|
+
|
|
11
|
+
const unsubscribe = source.subscribe(() => {
|
|
12
|
+
setValue(() => source.getSnapshot());
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
onCleanup(() => {
|
|
16
|
+
unsubscribe();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { onCleanup } from "solid-js";
|
|
2
|
+
import { createStore, reconcile } from "solid-js/store";
|
|
3
|
+
|
|
4
|
+
import type { RouterSource } from "@real-router/sources";
|
|
5
|
+
|
|
6
|
+
export function createStoreFromSource<T extends object>(
|
|
7
|
+
source: RouterSource<T>,
|
|
8
|
+
): T {
|
|
9
|
+
const [state, setState] = createStore<T>(
|
|
10
|
+
structuredClone(source.getSnapshot()),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const unsubscribe = source.subscribe(() => {
|
|
14
|
+
setState(reconcile(source.getSnapshot()));
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
onCleanup(unsubscribe);
|
|
18
|
+
|
|
19
|
+
return state;
|
|
20
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createActiveRouteSource } from "@real-router/sources";
|
|
2
|
+
import { shouldNavigate, applyLinkA11y, buildHref } from "dom-utils";
|
|
3
|
+
import { createEffect, onCleanup } from "solid-js";
|
|
4
|
+
|
|
5
|
+
import { EMPTY_PARAMS, EMPTY_OPTIONS } from "../constants";
|
|
6
|
+
import { createSignalFromSource } from "../createSignalFromSource";
|
|
7
|
+
import { useRouter } from "../hooks/useRouter";
|
|
8
|
+
|
|
9
|
+
import type { Params } from "@real-router/core";
|
|
10
|
+
|
|
11
|
+
export interface LinkDirectiveOptions<P extends Params = Params> {
|
|
12
|
+
routeName: string;
|
|
13
|
+
routeParams?: P;
|
|
14
|
+
routeOptions?: Record<string, unknown>;
|
|
15
|
+
activeClassName?: string;
|
|
16
|
+
activeStrict?: boolean;
|
|
17
|
+
ignoreQueryParams?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function link<P extends Params = Params>(
|
|
21
|
+
element: HTMLElement,
|
|
22
|
+
accessor: () => LinkDirectiveOptions<P>,
|
|
23
|
+
): void {
|
|
24
|
+
const router = useRouter();
|
|
25
|
+
const options = accessor();
|
|
26
|
+
|
|
27
|
+
// Set href on <a> elements
|
|
28
|
+
if (element instanceof HTMLAnchorElement) {
|
|
29
|
+
const href = buildHref(
|
|
30
|
+
router,
|
|
31
|
+
options.routeName,
|
|
32
|
+
options.routeParams ?? (EMPTY_PARAMS as P),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (href === undefined) {
|
|
36
|
+
element.removeAttribute("href");
|
|
37
|
+
} else {
|
|
38
|
+
element.href = href;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
applyLinkA11y(element);
|
|
43
|
+
|
|
44
|
+
// Active class tracking (reactive)
|
|
45
|
+
if (options.activeClassName) {
|
|
46
|
+
const activeClassName = options.activeClassName;
|
|
47
|
+
const activeSource = createActiveRouteSource(
|
|
48
|
+
router,
|
|
49
|
+
options.routeName,
|
|
50
|
+
options.routeParams ?? (EMPTY_PARAMS as P),
|
|
51
|
+
{
|
|
52
|
+
strict: options.activeStrict ?? false,
|
|
53
|
+
ignoreQueryParams: options.ignoreQueryParams ?? true,
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
const isActive = createSignalFromSource(activeSource);
|
|
57
|
+
|
|
58
|
+
createEffect(() => {
|
|
59
|
+
element.classList.toggle(activeClassName, isActive());
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Click handler
|
|
64
|
+
function handleClick(evt: MouseEvent) {
|
|
65
|
+
if (!shouldNavigate(evt)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (element instanceof HTMLAnchorElement) {
|
|
69
|
+
evt.preventDefault();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
router
|
|
73
|
+
.navigate(
|
|
74
|
+
options.routeName,
|
|
75
|
+
options.routeParams ?? (EMPTY_PARAMS as P),
|
|
76
|
+
options.routeOptions ?? EMPTY_OPTIONS,
|
|
77
|
+
)
|
|
78
|
+
.catch(() => {});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
element.addEventListener("click", handleClick);
|
|
82
|
+
|
|
83
|
+
onCleanup(() => {
|
|
84
|
+
element.removeEventListener("click", handleClick);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useContext } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import { RouterContext } from "../context";
|
|
4
|
+
|
|
5
|
+
import type { Navigator } from "@real-router/core";
|
|
6
|
+
|
|
7
|
+
export const useNavigator = (): Navigator => {
|
|
8
|
+
const ctx = useContext(RouterContext);
|
|
9
|
+
|
|
10
|
+
if (!ctx) {
|
|
11
|
+
throw new Error("useNavigator must be used within a RouterProvider");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return ctx.navigator;
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useContext } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import { RouteContext } from "../context";
|
|
4
|
+
|
|
5
|
+
import type { RouteState } from "../types";
|
|
6
|
+
import type { Accessor } from "solid-js";
|
|
7
|
+
|
|
8
|
+
export const useRoute = (): Accessor<RouteState> => {
|
|
9
|
+
const routeSignal = useContext(RouteContext);
|
|
10
|
+
|
|
11
|
+
if (!routeSignal) {
|
|
12
|
+
throw new Error("useRoute must be used within a RouterProvider");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return routeSignal;
|
|
16
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createRouteNodeSource } from "@real-router/sources";
|
|
2
|
+
|
|
3
|
+
import { createSignalFromSource } from "../createSignalFromSource";
|
|
4
|
+
import { useRouter } from "./useRouter";
|
|
5
|
+
|
|
6
|
+
import type { RouteState } from "../types";
|
|
7
|
+
import type { Accessor } from "solid-js";
|
|
8
|
+
|
|
9
|
+
export function useRouteNode(nodeName: string): Accessor<RouteState> {
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
const store = createRouteNodeSource(router, nodeName);
|
|
12
|
+
|
|
13
|
+
return createSignalFromSource(store);
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createRouteNodeSource } from "@real-router/sources";
|
|
2
|
+
|
|
3
|
+
import { createStoreFromSource } from "../createStoreFromSource";
|
|
4
|
+
import { useRouter } from "./useRouter";
|
|
5
|
+
|
|
6
|
+
import type { RouteState } from "../types";
|
|
7
|
+
|
|
8
|
+
export function useRouteNodeStore(nodeName: string): RouteState {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
|
|
11
|
+
return createStoreFromSource(createRouteNodeSource(router, nodeName));
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createRouteSource } from "@real-router/sources";
|
|
2
|
+
import { useContext } from "solid-js";
|
|
3
|
+
|
|
4
|
+
import { RouteContext } from "../context";
|
|
5
|
+
import { createStoreFromSource } from "../createStoreFromSource";
|
|
6
|
+
import { useRouter } from "./useRouter";
|
|
7
|
+
|
|
8
|
+
import type { RouteState } from "../types";
|
|
9
|
+
|
|
10
|
+
export function useRouteStore(): RouteState {
|
|
11
|
+
const ctx = useContext(RouteContext);
|
|
12
|
+
|
|
13
|
+
if (!ctx) {
|
|
14
|
+
throw new Error("useRouteStore must be used within a RouterProvider");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const router = useRouter();
|
|
18
|
+
|
|
19
|
+
return createStoreFromSource(createRouteSource(router));
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getPluginApi } from "@real-router/core/api";
|
|
2
|
+
import { getRouteUtils } from "@real-router/route-utils";
|
|
3
|
+
|
|
4
|
+
import { useRouter } from "./useRouter";
|
|
5
|
+
|
|
6
|
+
import type { RouteUtils } from "@real-router/route-utils";
|
|
7
|
+
|
|
8
|
+
export const useRouteUtils = (): RouteUtils => {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
|
|
11
|
+
return getRouteUtils(getPluginApi(router).getTree());
|
|
12
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useContext } from "solid-js";
|
|
2
|
+
|
|
3
|
+
import { RouterContext } from "../context";
|
|
4
|
+
|
|
5
|
+
import type { Router } from "@real-router/core";
|
|
6
|
+
|
|
7
|
+
export const useRouter = (): Router => {
|
|
8
|
+
const ctx = useContext(RouterContext);
|
|
9
|
+
|
|
10
|
+
if (!ctx) {
|
|
11
|
+
throw new Error("useRouter must be used within a RouterProvider");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return ctx.router;
|
|
15
|
+
};
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createTransitionSource } from "@real-router/sources";
|
|
2
|
+
|
|
3
|
+
import { createSignalFromSource } from "../createSignalFromSource";
|
|
4
|
+
import { useRouter } from "./useRouter";
|
|
5
|
+
|
|
6
|
+
import type { RouterTransitionSnapshot } from "@real-router/sources";
|
|
7
|
+
import type { Accessor } from "solid-js";
|
|
8
|
+
|
|
9
|
+
export function useRouterTransition(): Accessor<RouterTransitionSnapshot> {
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
const store = createTransitionSource(router);
|
|
12
|
+
|
|
13
|
+
return createSignalFromSource(store);
|
|
14
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export { RouteView } from "./components/RouteView";
|
|
2
|
+
|
|
3
|
+
export { Link } from "./components/Link";
|
|
4
|
+
|
|
5
|
+
export { RouterErrorBoundary } from "./components/RouterErrorBoundary";
|
|
6
|
+
|
|
7
|
+
export { link } from "./directives/link";
|
|
8
|
+
|
|
9
|
+
export { useRouter } from "./hooks/useRouter";
|
|
10
|
+
|
|
11
|
+
export { useNavigator } from "./hooks/useNavigator";
|
|
12
|
+
|
|
13
|
+
export { useRouteUtils } from "./hooks/useRouteUtils";
|
|
14
|
+
|
|
15
|
+
export { useRoute } from "./hooks/useRoute";
|
|
16
|
+
|
|
17
|
+
export { useRouteNode } from "./hooks/useRouteNode";
|
|
18
|
+
|
|
19
|
+
export { useRouteStore } from "./hooks/useRouteStore";
|
|
20
|
+
|
|
21
|
+
export { useRouteNodeStore } from "./hooks/useRouteNodeStore";
|
|
22
|
+
|
|
23
|
+
export { useRouterTransition } from "./hooks/useRouterTransition";
|
|
24
|
+
|
|
25
|
+
export { RouterProvider } from "./RouterProvider";
|
|
26
|
+
|
|
27
|
+
export { RouterContext, RouteContext } from "./context";
|
|
28
|
+
|
|
29
|
+
export { createSignalFromSource } from "./createSignalFromSource";
|
|
30
|
+
|
|
31
|
+
export { createStoreFromSource } from "./createStoreFromSource";
|
|
32
|
+
|
|
33
|
+
export type { LinkProps, RouteState } from "./types";
|
|
34
|
+
|
|
35
|
+
export type { RouterErrorBoundaryProps } from "./components/RouterErrorBoundary";
|
|
36
|
+
|
|
37
|
+
export type { LinkDirectiveOptions } from "./directives/link";
|
|
38
|
+
|
|
39
|
+
export type {
|
|
40
|
+
RouteViewProps,
|
|
41
|
+
RouteViewMatchProps,
|
|
42
|
+
RouteViewNotFoundProps,
|
|
43
|
+
} from "./components/RouteView";
|
|
44
|
+
|
|
45
|
+
export type { Navigator } from "@real-router/core";
|
|
46
|
+
|
|
47
|
+
export type { RouterTransitionSnapshot } from "@real-router/sources";
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { NavigationOptions, Params, State } from "@real-router/core";
|
|
2
|
+
import type { JSX } from "solid-js";
|
|
3
|
+
|
|
4
|
+
export interface RouteState<P extends Params = Params> {
|
|
5
|
+
route: State<P> | undefined;
|
|
6
|
+
previousRoute?: State | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface LinkProps<P extends Params = Params> extends Omit<
|
|
10
|
+
JSX.HTMLAttributes<HTMLAnchorElement>,
|
|
11
|
+
"onClick"
|
|
12
|
+
> {
|
|
13
|
+
routeName: string;
|
|
14
|
+
routeParams?: P;
|
|
15
|
+
routeOptions?: NavigationOptions;
|
|
16
|
+
activeClassName?: string;
|
|
17
|
+
activeStrict?: boolean;
|
|
18
|
+
ignoreQueryParams?: boolean;
|
|
19
|
+
target?: string;
|
|
20
|
+
onClick?: (evt: MouseEvent) => void;
|
|
21
|
+
}
|