@xmachines/play-solid-router 2.0.0-alpha.1 → 2.1.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 +39 -34
- package/dist/create-play-router-provider.d.ts +30 -29
- package/dist/create-play-router-provider.d.ts.map +1 -1
- package/dist/create-play-router-provider.js +51 -0
- package/dist/create-play-router-provider.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -10
- package/dist/play-router-provider.d.ts +24 -23
- package/dist/play-router-provider.d.ts.map +1 -1
- package/dist/play-router-provider.js +47 -0
- package/dist/play-router-provider.js.map +1 -0
- package/dist/solid-router-bridge.d.ts +69 -54
- package/dist/solid-router-bridge.d.ts.map +1 -1
- package/dist/solid-router-bridge.js +178 -162
- package/dist/solid-router-bridge.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +21 -21
- package/dist/create-play-router-provider.jsx +0 -45
- package/dist/create-play-router-provider.jsx.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/play-router-provider.jsx +0 -41
- package/dist/play-router-provider.jsx.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SolidJS Router bridge
|
|
2
|
+
* The SolidJS Router bridge. It implements the RouterBridge protocol through RouterBridgeBase
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* The class extends RouterBridgeBase, and the base class does all the common
|
|
5
|
+
* lifecycle work and synchronization work. This class uses the native reactive
|
|
6
|
+
* primitives of Solid (createEffect) for the router-to-actor direction.
|
|
6
7
|
*
|
|
7
|
-
* **IMPORTANT:** `connect()`
|
|
8
|
-
*
|
|
9
|
-
* `createRoot()`, which
|
|
10
|
-
*
|
|
11
|
-
* `dispose()`
|
|
8
|
+
* **IMPORTANT:** call `connect()` inside a Solid reactive owner: a component, or
|
|
9
|
+
* createRoot. The `createEffect()` call in `watchRouterChanges()` runs inside
|
|
10
|
+
* `createRoot()`, which keeps the effect separate from every parent owner on
|
|
11
|
+
* purpose. Therefore the effect does NOT clean up by itself when the component
|
|
12
|
+
* unmounts. You MUST call `disconnect()` or `dispose()` yourself, usually in
|
|
13
|
+
* `onCleanup()`.
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```tsx
|
|
@@ -24,7 +26,7 @@
|
|
|
24
26
|
* const routeMap = new RouteMap([...]);
|
|
25
27
|
* const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
|
|
26
28
|
*
|
|
27
|
-
* // connect()
|
|
29
|
+
* // Call connect() inside a Solid reactive owner
|
|
28
30
|
* bridge.connect();
|
|
29
31
|
* onCleanup(() => bridge.disconnect());
|
|
30
32
|
*
|
|
@@ -38,97 +40,110 @@ import type { LocationLike } from "@xmachines/play-router";
|
|
|
38
40
|
import type { RoutableActor } from "@xmachines/play-router";
|
|
39
41
|
import type { RouteMap } from "@xmachines/play-router";
|
|
40
42
|
/**
|
|
41
|
-
* SolidJS Router integration bridge
|
|
43
|
+
* The SolidJS Router integration bridge. It extends RouterBridgeBase
|
|
42
44
|
*
|
|
43
|
-
*
|
|
44
|
-
* primitives. The actor
|
|
45
|
-
* The router
|
|
45
|
+
* The class implements the RouterBridge protocol for SolidJS Router with the
|
|
46
|
+
* reactive primitives of Solid. The actor-to-router direction uses the TC39 Signal
|
|
47
|
+
* watcher of the base class. The router-to-actor direction uses the Solid
|
|
48
|
+
* createEffect function for a native reactivity.
|
|
46
49
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
+
* The bridge reads each path parameter from the reactive `useParams()` proxy of
|
|
51
|
+
* Solid. It does not parse the URL again with URLPattern. Therefore a
|
|
52
|
+
* parameterized route works without the URLPattern polyfill, because the router of
|
|
53
|
+
* Solid holds the values already.
|
|
50
54
|
*/
|
|
51
55
|
export declare class SolidRouterBridge extends RouterBridgeBase {
|
|
52
56
|
private readonly solidNavigate;
|
|
53
57
|
private readonly location;
|
|
54
58
|
private disposeRouterWatcher;
|
|
55
59
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
60
|
+
* The live reactive params object from the `useParams()` function of Solid.
|
|
61
|
+
* The bridge reads it inside the createEffect callback, so the value always shows
|
|
62
|
+
* the current route.
|
|
58
63
|
*/
|
|
59
64
|
private readonly solidParams;
|
|
60
65
|
/**
|
|
61
|
-
*
|
|
66
|
+
* Creates a SolidJS Router bridge
|
|
62
67
|
*
|
|
63
|
-
* **CRITICAL:** `connect()`
|
|
68
|
+
* **CRITICAL:** call `connect()` inside a Solid component, where the hooks are available.
|
|
64
69
|
*
|
|
65
|
-
* @param solidNavigate -
|
|
66
|
-
* @param location -
|
|
67
|
-
* @param params -
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param
|
|
70
|
+
* @param solidNavigate - The result of the useNavigate() hook
|
|
71
|
+
* @param location - The result of the useLocation() hook
|
|
72
|
+
* @param params - The result of the useParams() hook. The bridge reads each path
|
|
73
|
+
* parameter directly from it. A parameterized route therefore does not need the
|
|
74
|
+
* URLPattern polyfill
|
|
75
|
+
* @param actor - The XMachines actor instance
|
|
76
|
+
* @param routeMap - The bidirectional map between the state IDs and the paths
|
|
71
77
|
*/
|
|
72
78
|
constructor(solidNavigate: Navigator, location: LocationLike, params: Params, actor: RoutableActor, routeMap: RouteMap);
|
|
73
79
|
/**
|
|
74
|
-
*
|
|
80
|
+
* Reads each path parameter from the values that `useParams()` of Solid parsed before.
|
|
75
81
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* `syncActorFromRouter` is safe
|
|
79
|
-
* route
|
|
82
|
+
* The router of Solid holds every named parameter of the matched route segment
|
|
83
|
+
* already. A read of `this.solidParams` inside the createEffect callback that
|
|
84
|
+
* drives `syncActorFromRouter` is safe, because the reactive proxy always shows the
|
|
85
|
+
* route of the moment when the effect runs.
|
|
80
86
|
*
|
|
81
|
-
*
|
|
82
|
-
* no
|
|
87
|
+
* The method returns to the URLPattern method of the base class only when Solid
|
|
88
|
+
* gives no param for this route, which means that the route has no `:param`
|
|
89
|
+
* segment.
|
|
83
90
|
*
|
|
84
|
-
* @param pathname - The
|
|
85
|
-
*
|
|
86
|
-
* @
|
|
91
|
+
* @param pathname - The real URL path. The method does not use it, because Solid
|
|
92
|
+
* parsed the params before
|
|
93
|
+
* @param stateId - The matched state ID. The method does not use it, because Solid
|
|
94
|
+
* parsed the params before
|
|
95
|
+
* @returns The normalized path parameters, without an undefined value and without
|
|
96
|
+
* an empty value
|
|
87
97
|
*/
|
|
88
98
|
protected extractParams(pathname: string, stateId: string): Record<string, string>;
|
|
89
99
|
/**
|
|
90
|
-
*
|
|
100
|
+
* Navigates SolidJS Router to the given path.
|
|
91
101
|
*/
|
|
92
102
|
protected navigateRouter(path: string): void;
|
|
93
103
|
/**
|
|
94
|
-
*
|
|
104
|
+
* Returns the current pathname of the router, for the first URL-to-actor synchronization in connect().
|
|
95
105
|
*/
|
|
96
106
|
protected getInitialRouterPath(): string | null;
|
|
97
107
|
/**
|
|
98
|
-
*
|
|
108
|
+
* Returns the initial URL search string, so that `connect()` can forward the query params.
|
|
99
109
|
*
|
|
100
|
-
*
|
|
101
|
-
* the same source
|
|
102
|
-
*
|
|
110
|
+
* The method reads `this.location.search` from the reactive `useLocation()` object
|
|
111
|
+
* of Solid, the same source as `getInitialRouterPath()`. For an empty string, which
|
|
112
|
+
* means no query param, it returns `undefined`. `syncActorFromRouter` then makes
|
|
113
|
+
* `query: {}`.
|
|
103
114
|
*/
|
|
104
115
|
protected getInitialRouterSearch(): string | undefined;
|
|
105
116
|
/**
|
|
106
|
-
*
|
|
117
|
+
* Subscribes to each location change of SolidJS Router with createEffect.
|
|
107
118
|
*
|
|
108
|
-
*
|
|
119
|
+
* Call this method inside a Solid reactive owner: a component, or createRoot.
|
|
109
120
|
*
|
|
110
|
-
* The effect runs inside `createRoot()
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* The
|
|
114
|
-
* effect
|
|
121
|
+
* The effect runs inside `createRoot()`. The effect then has a stable owner, and
|
|
122
|
+
* that owner is separate from the lifecycle of the component that calls the method.
|
|
123
|
+
* Solid therefore does not dispose of the effect when the component renders again
|
|
124
|
+
* while the bridge must stay active. The cost is that the unmount of the component
|
|
125
|
+
* does NOT clean up the effect. Call `disconnect()` or `dispose()` yourself, or the
|
|
126
|
+
* effect stays in memory.
|
|
115
127
|
*/
|
|
116
128
|
protected watchRouterChanges(): void;
|
|
117
129
|
/**
|
|
118
|
-
*
|
|
130
|
+
* Stops the watch of the SolidJS Router changes.
|
|
119
131
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
132
|
+
* The method calls the `dispose` function that `createRoot()` returned in
|
|
133
|
+
* `watchRouterChanges()`. This removes the reactive effect and frees the separate
|
|
134
|
+
* owner. This is the only path that cleans up. The unmount of the component does
|
|
135
|
+
* NOT start it.
|
|
123
136
|
*/
|
|
124
137
|
protected unwatchRouterChanges(): void;
|
|
125
138
|
/**
|
|
126
|
-
*
|
|
139
|
+
* Disposes of the bridge. This method is the alias of disconnect.
|
|
127
140
|
*
|
|
128
141
|
* @example
|
|
129
142
|
* ```tsx
|
|
130
143
|
* onCleanup(() => bridge.dispose());
|
|
131
144
|
* ```
|
|
145
|
+
*
|
|
146
|
+
* @deprecated Use {@link RouterBridgeBase.disconnect | disconnect}. Will be removed in the next major.
|
|
132
147
|
*/
|
|
133
148
|
dispose(): void;
|
|
134
149
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-router-bridge.d.ts","sourceRoot":"","sources":["../src/solid-router-bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"solid-router-bridge.d.ts","sourceRoot":"","sources":["../src/solid-router-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;IAwBrD,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAxB1B,OAAO,CAAC,oBAAoB,CAA6B;IAEzD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC;;;;;;;;;;;;OAYG;gBAEe,aAAa,EAAE,SAAS,EACxB,QAAQ,EAAE,YAAY,EACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,QAAQ;IASnB;;;;;;;;;;;;;;;;;;OAkBG;cACgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAY3F;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;cACgB,oBAAoB,IAAI,MAAM,GAAG,IAAI;IAIxD;;;;;;;OAOG;cACgB,sBAAsB,IAAI,MAAM,GAAG,SAAS;IAI/D;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAepC;;;;;;;OAOG;IACH,SAAS,CAAC,oBAAoB,IAAI,IAAI;IAKtC;;;;;;;;;OASG;IACH,OAAO,IAAI,IAAI;CAGf"}
|
|
@@ -1,166 +1,182 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SolidJS Router bridge implementing RouterBridge protocol via RouterBridgeBase
|
|
3
|
-
*
|
|
4
|
-
* Extends RouterBridgeBase to handle all common lifecycle and sync logic.
|
|
5
|
-
* Uses Solid's native reactive primitives (createEffect) for router→actor direction.
|
|
6
|
-
*
|
|
7
|
-
* **IMPORTANT:** `connect()` MUST be called inside a Solid reactive owner (component
|
|
8
|
-
* or createRoot). The `createEffect()` in `watchRouterChanges()` runs inside
|
|
9
|
-
* `createRoot()`, which deliberately isolates it from any parent owner — automatic
|
|
10
|
-
* cleanup on component unmount does NOT happen. You MUST call `disconnect()` (or
|
|
11
|
-
* `dispose()`) explicitly, typically in `onCleanup()`.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```tsx
|
|
15
|
-
* import { useNavigate, useLocation, useParams } from '@solidjs/router';
|
|
16
|
-
* import { onCleanup } from 'solid-js';
|
|
17
|
-
* import { SolidRouterBridge, RouteMap } from '@xmachines/play-solid-router';
|
|
18
|
-
*
|
|
19
|
-
* function App() {
|
|
20
|
-
* const navigate = useNavigate();
|
|
21
|
-
* const location = useLocation();
|
|
22
|
-
* const params = useParams();
|
|
23
|
-
*
|
|
24
|
-
* const routeMap = new RouteMap([...]);
|
|
25
|
-
* const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
|
|
26
|
-
*
|
|
27
|
-
* // connect() MUST be called inside a Solid reactive owner
|
|
28
|
-
* bridge.connect();
|
|
29
|
-
* onCleanup(() => bridge.disconnect());
|
|
30
|
-
*
|
|
31
|
-
* return <div>...</div>;
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
1
|
import { createEffect, createRoot, on } from "solid-js";
|
|
36
2
|
import { RouterBridgeBase } from "@xmachines/play-router";
|
|
3
|
+
//#region packages/play-solid-router/src/solid-router-bridge.ts
|
|
4
|
+
/**
|
|
5
|
+
* The SolidJS Router bridge. It implements the RouterBridge protocol through RouterBridgeBase
|
|
6
|
+
*
|
|
7
|
+
* The class extends RouterBridgeBase, and the base class does all the common
|
|
8
|
+
* lifecycle work and synchronization work. This class uses the native reactive
|
|
9
|
+
* primitives of Solid (createEffect) for the router-to-actor direction.
|
|
10
|
+
*
|
|
11
|
+
* **IMPORTANT:** call `connect()` inside a Solid reactive owner: a component, or
|
|
12
|
+
* createRoot. The `createEffect()` call in `watchRouterChanges()` runs inside
|
|
13
|
+
* `createRoot()`, which keeps the effect separate from every parent owner on
|
|
14
|
+
* purpose. Therefore the effect does NOT clean up by itself when the component
|
|
15
|
+
* unmounts. You MUST call `disconnect()` or `dispose()` yourself, usually in
|
|
16
|
+
* `onCleanup()`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { useNavigate, useLocation, useParams } from '@solidjs/router';
|
|
21
|
+
* import { onCleanup } from 'solid-js';
|
|
22
|
+
* import { SolidRouterBridge, RouteMap } from '@xmachines/play-solid-router';
|
|
23
|
+
*
|
|
24
|
+
* function App() {
|
|
25
|
+
* const navigate = useNavigate();
|
|
26
|
+
* const location = useLocation();
|
|
27
|
+
* const params = useParams();
|
|
28
|
+
*
|
|
29
|
+
* const routeMap = new RouteMap([...]);
|
|
30
|
+
* const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
|
|
31
|
+
*
|
|
32
|
+
* // Call connect() inside a Solid reactive owner
|
|
33
|
+
* bridge.connect();
|
|
34
|
+
* onCleanup(() => bridge.disconnect());
|
|
35
|
+
*
|
|
36
|
+
* return <div>...</div>;
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
37
40
|
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
41
|
+
* The SolidJS Router integration bridge. It extends RouterBridgeBase
|
|
42
|
+
*
|
|
43
|
+
* The class implements the RouterBridge protocol for SolidJS Router with the
|
|
44
|
+
* reactive primitives of Solid. The actor-to-router direction uses the TC39 Signal
|
|
45
|
+
* watcher of the base class. The router-to-actor direction uses the Solid
|
|
46
|
+
* createEffect function for a native reactivity.
|
|
47
|
+
*
|
|
48
|
+
* The bridge reads each path parameter from the reactive `useParams()` proxy of
|
|
49
|
+
* Solid. It does not parse the URL again with URLPattern. Therefore a
|
|
50
|
+
* parameterized route works without the URLPattern polyfill, because the router of
|
|
51
|
+
* Solid holds the values already.
|
|
52
|
+
*/
|
|
53
|
+
var SolidRouterBridge = class extends RouterBridgeBase {
|
|
54
|
+
solidNavigate;
|
|
55
|
+
location;
|
|
56
|
+
disposeRouterWatcher = null;
|
|
57
|
+
/**
|
|
58
|
+
* The live reactive params object from the `useParams()` function of Solid.
|
|
59
|
+
* The bridge reads it inside the createEffect callback, so the value always shows
|
|
60
|
+
* the current route.
|
|
61
|
+
*/
|
|
62
|
+
solidParams;
|
|
63
|
+
/**
|
|
64
|
+
* Creates a SolidJS Router bridge
|
|
65
|
+
*
|
|
66
|
+
* **CRITICAL:** call `connect()` inside a Solid component, where the hooks are available.
|
|
67
|
+
*
|
|
68
|
+
* @param solidNavigate - The result of the useNavigate() hook
|
|
69
|
+
* @param location - The result of the useLocation() hook
|
|
70
|
+
* @param params - The result of the useParams() hook. The bridge reads each path
|
|
71
|
+
* parameter directly from it. A parameterized route therefore does not need the
|
|
72
|
+
* URLPattern polyfill
|
|
73
|
+
* @param actor - The XMachines actor instance
|
|
74
|
+
* @param routeMap - The bidirectional map between the state IDs and the paths
|
|
75
|
+
*/
|
|
76
|
+
constructor(solidNavigate, location, params, actor, routeMap) {
|
|
77
|
+
super(actor, {
|
|
78
|
+
getStateIdByPath: (path) => routeMap.getStateIdByPath(path),
|
|
79
|
+
getPathByStateId: (id) => routeMap.getPathByStateId(id)
|
|
80
|
+
});
|
|
81
|
+
this.solidNavigate = solidNavigate;
|
|
82
|
+
this.location = location;
|
|
83
|
+
this.solidParams = params;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Reads each path parameter from the values that `useParams()` of Solid parsed before.
|
|
87
|
+
*
|
|
88
|
+
* The router of Solid holds every named parameter of the matched route segment
|
|
89
|
+
* already. A read of `this.solidParams` inside the createEffect callback that
|
|
90
|
+
* drives `syncActorFromRouter` is safe, because the reactive proxy always shows the
|
|
91
|
+
* route of the moment when the effect runs.
|
|
92
|
+
*
|
|
93
|
+
* The method returns to the URLPattern method of the base class only when Solid
|
|
94
|
+
* gives no param for this route, which means that the route has no `:param`
|
|
95
|
+
* segment.
|
|
96
|
+
*
|
|
97
|
+
* @param pathname - The real URL path. The method does not use it, because Solid
|
|
98
|
+
* parsed the params before
|
|
99
|
+
* @param stateId - The matched state ID. The method does not use it, because Solid
|
|
100
|
+
* parsed the params before
|
|
101
|
+
* @returns The normalized path parameters, without an undefined value and without
|
|
102
|
+
* an empty value
|
|
103
|
+
*/
|
|
104
|
+
extractParams(pathname, stateId) {
|
|
105
|
+
const entries = Object.entries(this.solidParams).filter((entry) => entry[1] !== void 0 && entry[1] !== null && entry[1] !== "");
|
|
106
|
+
if (entries.length > 0) return Object.fromEntries(entries);
|
|
107
|
+
return super.extractParams(pathname, stateId);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Navigates SolidJS Router to the given path.
|
|
111
|
+
*/
|
|
112
|
+
navigateRouter(path) {
|
|
113
|
+
this.solidNavigate(path);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Returns the current pathname of the router, for the first URL-to-actor synchronization in connect().
|
|
117
|
+
*/
|
|
118
|
+
getInitialRouterPath() {
|
|
119
|
+
return this.location.pathname ?? null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns the initial URL search string, so that `connect()` can forward the query params.
|
|
123
|
+
*
|
|
124
|
+
* The method reads `this.location.search` from the reactive `useLocation()` object
|
|
125
|
+
* of Solid, the same source as `getInitialRouterPath()`. For an empty string, which
|
|
126
|
+
* means no query param, it returns `undefined`. `syncActorFromRouter` then makes
|
|
127
|
+
* `query: {}`.
|
|
128
|
+
*/
|
|
129
|
+
getInitialRouterSearch() {
|
|
130
|
+
return this.location.search || void 0;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Subscribes to each location change of SolidJS Router with createEffect.
|
|
134
|
+
*
|
|
135
|
+
* Call this method inside a Solid reactive owner: a component, or createRoot.
|
|
136
|
+
*
|
|
137
|
+
* The effect runs inside `createRoot()`. The effect then has a stable owner, and
|
|
138
|
+
* that owner is separate from the lifecycle of the component that calls the method.
|
|
139
|
+
* Solid therefore does not dispose of the effect when the component renders again
|
|
140
|
+
* while the bridge must stay active. The cost is that the unmount of the component
|
|
141
|
+
* does NOT clean up the effect. Call `disconnect()` or `dispose()` yourself, or the
|
|
142
|
+
* effect stays in memory.
|
|
143
|
+
*/
|
|
144
|
+
watchRouterChanges() {
|
|
145
|
+
this.disposeRouterWatcher = createRoot((dispose) => {
|
|
146
|
+
createEffect(on(() => this.location.pathname, (pathname) => {
|
|
147
|
+
const search = this.location.search ?? "";
|
|
148
|
+
this.syncActorFromRouter(pathname, search);
|
|
149
|
+
}));
|
|
150
|
+
return dispose;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Stops the watch of the SolidJS Router changes.
|
|
155
|
+
*
|
|
156
|
+
* The method calls the `dispose` function that `createRoot()` returned in
|
|
157
|
+
* `watchRouterChanges()`. This removes the reactive effect and frees the separate
|
|
158
|
+
* owner. This is the only path that cleans up. The unmount of the component does
|
|
159
|
+
* NOT start it.
|
|
160
|
+
*/
|
|
161
|
+
unwatchRouterChanges() {
|
|
162
|
+
this.disposeRouterWatcher?.();
|
|
163
|
+
this.disposeRouterWatcher = null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Disposes of the bridge. This method is the alias of disconnect.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```tsx
|
|
170
|
+
* onCleanup(() => bridge.dispose());
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @deprecated Use {@link RouterBridgeBase.disconnect | disconnect}. Will be removed in the next major.
|
|
174
|
+
*/
|
|
175
|
+
dispose() {
|
|
176
|
+
this.disconnect();
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
export { SolidRouterBridge };
|
|
181
|
+
|
|
166
182
|
//# sourceMappingURL=solid-router-bridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-router-bridge.js","
|
|
1
|
+
{"version":3,"file":"solid-router-bridge.js","names":[],"sources":["../src/solid-router-bridge.ts"],"sourcesContent":["/**\n * The SolidJS Router bridge. It implements the RouterBridge protocol through RouterBridgeBase\n *\n * The class extends RouterBridgeBase, and the base class does all the common\n * lifecycle work and synchronization work. This class uses the native reactive\n * primitives of Solid (createEffect) for the router-to-actor direction.\n *\n * **IMPORTANT:** call `connect()` inside a Solid reactive owner: a component, or\n * createRoot. The `createEffect()` call in `watchRouterChanges()` runs inside\n * `createRoot()`, which keeps the effect separate from every parent owner on\n * purpose. Therefore the effect does NOT clean up by itself when the component\n * unmounts. You MUST call `disconnect()` or `dispose()` yourself, usually in\n * `onCleanup()`.\n *\n * @example\n * ```tsx\n * import { useNavigate, useLocation, useParams } from '@solidjs/router';\n * import { onCleanup } from 'solid-js';\n * import { SolidRouterBridge, RouteMap } from '@xmachines/play-solid-router';\n *\n * function App() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const params = useParams();\n *\n * const routeMap = new RouteMap([...]);\n * const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);\n *\n * // Call connect() inside a Solid reactive owner\n * bridge.connect();\n * onCleanup(() => bridge.disconnect());\n *\n * return <div>...</div>;\n * }\n * ```\n */\n\nimport { createEffect, createRoot, on } from \"solid-js\";\nimport type { Navigator, Params } from \"@solidjs/router\";\nimport { RouterBridgeBase } from \"@xmachines/play-router\";\nimport type { LocationLike } from \"@xmachines/play-router\";\nimport type { RoutableActor } from \"@xmachines/play-router\";\nimport type { RouteMap } from \"@xmachines/play-router\";\n\n/**\n * The SolidJS Router integration bridge. It extends RouterBridgeBase\n *\n * The class implements the RouterBridge protocol for SolidJS Router with the\n * reactive primitives of Solid. The actor-to-router direction uses the TC39 Signal\n * watcher of the base class. The router-to-actor direction uses the Solid\n * createEffect function for a native reactivity.\n *\n * The bridge reads each path parameter from the reactive `useParams()` proxy of\n * Solid. It does not parse the URL again with URLPattern. Therefore a\n * parameterized route works without the URLPattern polyfill, because the router of\n * Solid holds the values already.\n */\nexport class SolidRouterBridge extends RouterBridgeBase {\n\tprivate disposeRouterWatcher: (() => void) | null = null;\n\n\t/**\n\t * The live reactive params object from the `useParams()` function of Solid.\n\t * The bridge reads it inside the createEffect callback, so the value always shows\n\t * the current route.\n\t */\n\tprivate readonly solidParams: Params;\n\n\t/**\n\t * Creates a SolidJS Router bridge\n\t *\n\t * **CRITICAL:** call `connect()` inside a Solid component, where the hooks are available.\n\t *\n\t * @param solidNavigate - The result of the useNavigate() hook\n\t * @param location - The result of the useLocation() hook\n\t * @param params - The result of the useParams() hook. The bridge reads each path\n\t * parameter directly from it. A parameterized route therefore does not need the\n\t * URLPattern polyfill\n\t * @param actor - The XMachines actor instance\n\t * @param routeMap - The bidirectional map between the state IDs and the paths\n\t */\n\tconstructor(\n\t\tprivate readonly solidNavigate: Navigator,\n\t\tprivate readonly location: LocationLike,\n\t\tparams: Params,\n\t\tactor: RoutableActor,\n\t\trouteMap: RouteMap,\n\t) {\n\t\tsuper(actor, {\n\t\t\tgetStateIdByPath: (path: string) => routeMap.getStateIdByPath(path),\n\t\t\tgetPathByStateId: (id: string) => routeMap.getPathByStateId(id),\n\t\t});\n\t\tthis.solidParams = params;\n\t}\n\n\t/**\n\t * Reads each path parameter from the values that `useParams()` of Solid parsed before.\n\t *\n\t * The router of Solid holds every named parameter of the matched route segment\n\t * already. A read of `this.solidParams` inside the createEffect callback that\n\t * drives `syncActorFromRouter` is safe, because the reactive proxy always shows the\n\t * route of the moment when the effect runs.\n\t *\n\t * The method returns to the URLPattern method of the base class only when Solid\n\t * gives no param for this route, which means that the route has no `:param`\n\t * segment.\n\t *\n\t * @param pathname - The real URL path. The method does not use it, because Solid\n\t * parsed the params before\n\t * @param stateId - The matched state ID. The method does not use it, because Solid\n\t * parsed the params before\n\t * @returns The normalized path parameters, without an undefined value and without\n\t * an empty value\n\t */\n\tprotected override extractParams(pathname: string, stateId: string): Record<string, string> {\n\t\tconst entries = Object.entries(this.solidParams).filter(\n\t\t\t(entry): entry is [string, string] =>\n\t\t\t\tentry[1] !== undefined && entry[1] !== null && entry[1] !== \"\",\n\t\t);\n\t\tif (entries.length > 0) {\n\t\t\treturn Object.fromEntries(entries);\n\t\t}\n\t\t// Solid gives no param: use URLPattern for a route with no segment\n\t\treturn super.extractParams(pathname, stateId);\n\t}\n\n\t/**\n\t * Navigates SolidJS Router to the given path.\n\t */\n\tprotected navigateRouter(path: string): void {\n\t\tthis.solidNavigate(path);\n\t}\n\n\t/**\n\t * Returns the current pathname of the router, for the first URL-to-actor synchronization in connect().\n\t */\n\tprotected override getInitialRouterPath(): string | null {\n\t\treturn this.location.pathname ?? null;\n\t}\n\n\t/**\n\t * Returns the initial URL search string, so that `connect()` can forward the query params.\n\t *\n\t * The method reads `this.location.search` from the reactive `useLocation()` object\n\t * of Solid, the same source as `getInitialRouterPath()`. For an empty string, which\n\t * means no query param, it returns `undefined`. `syncActorFromRouter` then makes\n\t * `query: {}`.\n\t */\n\tprotected override getInitialRouterSearch(): string | undefined {\n\t\treturn this.location.search || undefined;\n\t}\n\n\t/**\n\t * Subscribes to each location change of SolidJS Router with createEffect.\n\t *\n\t * Call this method inside a Solid reactive owner: a component, or createRoot.\n\t *\n\t * The effect runs inside `createRoot()`. The effect then has a stable owner, and\n\t * that owner is separate from the lifecycle of the component that calls the method.\n\t * Solid therefore does not dispose of the effect when the component renders again\n\t * while the bridge must stay active. The cost is that the unmount of the component\n\t * does NOT clean up the effect. Call `disconnect()` or `dispose()` yourself, or the\n\t * effect stays in memory.\n\t */\n\tprotected watchRouterChanges(): void {\n\t\tthis.disposeRouterWatcher = createRoot((dispose) => {\n\t\t\tcreateEffect(\n\t\t\t\ton(\n\t\t\t\t\t() => this.location.pathname,\n\t\t\t\t\t(pathname: string) => {\n\t\t\t\t\t\tconst search = this.location.search ?? \"\";\n\t\t\t\t\t\tthis.syncActorFromRouter(pathname, search);\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn dispose;\n\t\t});\n\t}\n\n\t/**\n\t * Stops the watch of the SolidJS Router changes.\n\t *\n\t * The method calls the `dispose` function that `createRoot()` returned in\n\t * `watchRouterChanges()`. This removes the reactive effect and frees the separate\n\t * owner. This is the only path that cleans up. The unmount of the component does\n\t * NOT start it.\n\t */\n\tprotected unwatchRouterChanges(): void {\n\t\tthis.disposeRouterWatcher?.();\n\t\tthis.disposeRouterWatcher = null;\n\t}\n\n\t/**\n\t * Disposes of the bridge. This method is the alias of disconnect.\n\t *\n\t * @example\n\t * ```tsx\n\t * onCleanup(() => bridge.dispose());\n\t * ```\n\t *\n\t * @deprecated Use {@link RouterBridgeBase.disconnect | disconnect}. Will be removed in the next major.\n\t */\n\tdispose(): void {\n\t\tthis.disconnect();\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,IAAa,oBAAb,cAAuC,iBAAiB;CAwBrC;CACA;CAxBlB,uBAAoD;;;;;;CAOpD;;;;;;;;;;;;;;CAeA,YACC,eACA,UACA,QACA,OACA,UACC;EACD,MAAM,OAAO;GACZ,mBAAmB,SAAiB,SAAS,iBAAiB,IAAI;GAClE,mBAAmB,OAAe,SAAS,iBAAiB,EAAE;EAC/D,CAAC;EATgB,KAAA,gBAAA;EACA,KAAA,WAAA;EASjB,KAAK,cAAc;CACpB;;;;;;;;;;;;;;;;;;;;CAqBA,cAAiC,UAAkB,SAAyC;EAC3F,MAAM,UAAU,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,QAC/C,UACA,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,QAAQ,MAAM,OAAO,EAC9D;EACA,IAAI,QAAQ,SAAS,GACpB,OAAO,OAAO,YAAY,OAAO;EAGlC,OAAO,MAAM,cAAc,UAAU,OAAO;CAC7C;;;;CAKA,eAAyB,MAAoB;EAC5C,KAAK,cAAc,IAAI;CACxB;;;;CAKA,uBAAyD;EACxD,OAAO,KAAK,SAAS,YAAY;CAClC;;;;;;;;;CAUA,yBAAgE;EAC/D,OAAO,KAAK,SAAS,UAAU,KAAA;CAChC;;;;;;;;;;;;;CAcA,qBAAqC;EACpC,KAAK,uBAAuB,YAAY,YAAY;GACnD,aACC,SACO,KAAK,SAAS,WACnB,aAAqB;IACrB,MAAM,SAAS,KAAK,SAAS,UAAU;IACvC,KAAK,oBAAoB,UAAU,MAAM;GAC1C,CACD,CACD;GACA,OAAO;EACR,CAAC;CACF;;;;;;;;;CAUA,uBAAuC;EACtC,KAAK,uBAAuB;EAC5B,KAAK,uBAAuB;CAC7B;;;;;;;;;;;CAYA,UAAgB;EACf,KAAK,WAAW;CACjB;AACD"}
|
package/dist/types.d.ts
CHANGED