@xmachines/play-solid-router 2.0.0 → 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 +34 -29
- 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 +19 -18
- package/dist/create-play-router-provider.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- 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 +11 -9
- package/dist/play-router-provider.js.map +1 -1
- 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 +69 -54
- package/dist/solid-router-bridge.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# @xmachines/play-solid-router
|
|
2
2
|
|
|
3
|
-
SolidJS Router adapter for the XMachines Universal Player Architecture.
|
|
3
|
+
SolidJS Router adapter for the XMachines Universal Player Architecture. It keeps the state machine routes of a `PlayerActor` and the browser URL in step, in both directions, through `@solidjs/router`.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT) [.
|
|
5
|
+
[](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@xmachines/play-solid-router)
|
|
8
6
|
|
|
9
7
|
## Installation
|
|
10
8
|
|
|
@@ -12,7 +10,7 @@ Part of the [xmachines-js monorepo](../../README.md).
|
|
|
12
10
|
pnpm add @xmachines/play-solid-router
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
**Peer dependencies
|
|
13
|
+
**Peer dependencies.** Install them separately:
|
|
16
14
|
|
|
17
15
|
```bash
|
|
18
16
|
pnpm add solid-js @solidjs/router xstate
|
|
@@ -36,6 +34,10 @@ actor.start();
|
|
|
36
34
|
|
|
37
35
|
const routeMap = createRouteMap(myMachine);
|
|
38
36
|
|
|
37
|
+
// Minimal app shell stub — a real app renders PlayUIProvider + PlayRenderer from
|
|
38
|
+
// @xmachines/play-solid here (see the workspace-only @xmachines/play-solid-demo Shell)
|
|
39
|
+
const MyApp = (props: { actor: typeof actor }) => <main />;
|
|
40
|
+
|
|
39
41
|
const Layout: ParentComponent = () => {
|
|
40
42
|
const navigate = useNavigate();
|
|
41
43
|
const location = useLocation();
|
|
@@ -62,7 +64,7 @@ export default function App() {
|
|
|
62
64
|
|
|
63
65
|
### `PlayRouterProvider`
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
This SolidJS component connects a `PlayerActor` to Solid Router. It creates and connects a `SolidRouterBridge` on mount. It disconnects the bridge with `onCleanup` on unmount.
|
|
66
68
|
|
|
67
69
|
```tsx
|
|
68
70
|
interface PlayRouterProviderProps<TActor extends PlayActor> {
|
|
@@ -83,14 +85,17 @@ interface PlayRouterProviderProps<TActor extends PlayActor> {
|
|
|
83
85
|
|
|
84
86
|
### `SolidRouterBridge`
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
The low-level class for a manual integration. It extends `RouterBridgeBase` from `@xmachines/play-router`. It uses the Solid `createEffect` to send each router change to the actor.
|
|
87
89
|
|
|
88
|
-
> **Important:** `connect()`
|
|
90
|
+
> **Important:** call `connect()` inside a Solid reactive owner: a component, or `createRoot`. The bridge does not clean up by itself. Call `disconnect()` or `dispose()` yourself, usually in `onCleanup()`.
|
|
89
91
|
|
|
90
92
|
```tsx
|
|
91
|
-
import { useNavigate, useLocation, useParams
|
|
93
|
+
import { useNavigate, useLocation, useParams } from "@solidjs/router";
|
|
94
|
+
import { onCleanup } from "solid-js";
|
|
92
95
|
import { SolidRouterBridge, RouteMap } from "@xmachines/play-solid-router";
|
|
93
96
|
|
|
97
|
+
// actor: your started player (see the Quick Start above)
|
|
98
|
+
|
|
94
99
|
function App() {
|
|
95
100
|
const navigate = useNavigate();
|
|
96
101
|
const location = useLocation();
|
|
@@ -111,7 +116,7 @@ function App() {
|
|
|
111
116
|
|
|
112
117
|
### `createRouteMap(machine)`
|
|
113
118
|
|
|
114
|
-
|
|
119
|
+
This factory builds a `RouteMap` directly from an XState machine definition. It comes from `@xmachines/play-router`.
|
|
115
120
|
|
|
116
121
|
```ts
|
|
117
122
|
import { createRouteMap } from "@xmachines/play-solid-router";
|
|
@@ -121,7 +126,7 @@ const routeMap = createRouteMap(myMachine);
|
|
|
121
126
|
|
|
122
127
|
### `RouteMap` / `RouteMapping`
|
|
123
128
|
|
|
124
|
-
|
|
129
|
+
The bidirectional map between the state IDs and the URL paths. It comes from `@xmachines/play-router`.
|
|
125
130
|
|
|
126
131
|
```ts
|
|
127
132
|
import { RouteMap } from "@xmachines/play-solid-router";
|
|
@@ -135,22 +140,22 @@ const routeMap = new RouteMap([
|
|
|
135
140
|
|
|
136
141
|
### Types
|
|
137
142
|
|
|
138
|
-
| Export | Description
|
|
139
|
-
| ------------------------- |
|
|
140
|
-
| `PlayActor` | `AbstractActor & Routable & Viewable` — canonical actor shape from `@xmachines/play-router`.
|
|
141
|
-
| `RoutableActor` | Deprecated alias for `PlayActor`. Use `PlayActor` from `@xmachines/play-router` in new code.
|
|
142
|
-
| `AbstractActor` |
|
|
143
|
-
| `SolidRouterHooks` | Shape of the `router` prop: `{ navigate, location, params }`
|
|
144
|
-
| `PlayRouterProviderProps` | Full props interface for `PlayRouterProvider`
|
|
145
|
-
| `PlayRouteEvent` |
|
|
146
|
-
| `RouterBridge` |
|
|
147
|
-
| `RouteMapOptions` |
|
|
143
|
+
| Export | Description |
|
|
144
|
+
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
145
|
+
| `PlayActor` | `AbstractActor & Routable & Viewable` — the canonical actor shape from `@xmachines/play-router`. `PlayRouterProvider` requires it, because it renders the current view spec and also keeps the routes in step. |
|
|
146
|
+
| `RoutableActor` | Deprecated alias for `PlayActor`. Use `PlayActor` from `@xmachines/play-router` in new code. |
|
|
147
|
+
| `AbstractActor` | It comes from `@xmachines/play-actor`. Use it for the type of a renderer callback. |
|
|
148
|
+
| `SolidRouterHooks` | Shape of the `router` prop: `{ navigate, location, params }` |
|
|
149
|
+
| `PlayRouterProviderProps` | Full props interface for `PlayRouterProvider` |
|
|
150
|
+
| `PlayRouteEvent` | The event type that the bridge sends to the actor on a URL change (`play.route`) |
|
|
151
|
+
| `RouterBridge` | The interface that `SolidRouterBridge` implements |
|
|
152
|
+
| `RouteMapOptions` | The options object for the `RouteMap` constructor. It comes from `@xmachines/play-router`. |
|
|
148
153
|
|
|
149
154
|
## Usage Patterns
|
|
150
155
|
|
|
151
156
|
### Protected Routes and Guards
|
|
152
157
|
|
|
153
|
-
|
|
158
|
+
The auth guards are inside the state machine only. Unauthorized content therefore never appears, not even for a moment:
|
|
154
159
|
|
|
155
160
|
```ts
|
|
156
161
|
const machineConfig = {
|
|
@@ -166,13 +171,13 @@ const machineConfig = {
|
|
|
166
171
|
};
|
|
167
172
|
```
|
|
168
173
|
|
|
169
|
-
|
|
174
|
+
A user navigates to `/dashboard`, and the user is not authenticated:
|
|
170
175
|
|
|
171
176
|
1. Solid Router updates the URL.
|
|
172
|
-
2.
|
|
173
|
-
3.
|
|
174
|
-
4.
|
|
175
|
-
5.
|
|
177
|
+
2. The bridge receives the change and sends `play.route` to the actor.
|
|
178
|
+
3. The actor evaluates the guard. The guard refuses the transition, and the actor moves to `login`.
|
|
179
|
+
4. The bridge reads the new actor route (`/login`) from the TC39 Signal.
|
|
180
|
+
5. The bridge calls `navigate("/login")`.
|
|
176
181
|
|
|
177
182
|
### Dynamic Routes with Parameters
|
|
178
183
|
|
|
@@ -186,7 +191,7 @@ const routeMap = new RouteMap([
|
|
|
186
191
|
// { type: "play.route", to: "#post", params: { userId: "123", postId: "456" }, query: {} }
|
|
187
192
|
```
|
|
188
193
|
|
|
189
|
-
|
|
194
|
+
The bridge reads the path parameters from the reactive `useParams()` proxy of Solid. A parameterized route therefore does not need the URLPattern polyfill.
|
|
190
195
|
|
|
191
196
|
## Testing
|
|
192
197
|
|
|
@@ -200,7 +205,7 @@ pnpm --filter @xmachines/play-solid-router test
|
|
|
200
205
|
pnpm test
|
|
201
206
|
```
|
|
202
207
|
|
|
203
|
-
**Browser tests** (`test/browser/**/*.browser.test.ts`) run
|
|
208
|
+
**Browser tests** (`test/browser/**/*.browser.test.ts`) run in real Chromium through Playwright. They cover the asynchronous sequences that jsdom cannot reproduce:
|
|
204
209
|
|
|
205
210
|
```bash
|
|
206
211
|
pnpm exec vitest --config vitest.browser.config.ts --project play-solid-router-browser
|
|
@@ -1,57 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* createPlayRouterProvider — factory
|
|
2
|
+
* createPlayRouterProvider — the factory of a Solid `PlayRouterProvider` component
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* factory.
|
|
4
|
+
* The factory holds the shape of the provider component of this package: it creates a
|
|
5
|
+
* bridge synchronously, during the evaluation of the component, it calls `connect()`,
|
|
6
|
+
* and it calls `disconnect()` in `onCleanup`. One call therefore wraps each Solid
|
|
7
|
+
* bridge with the standard `(router, actor, routeMap)` constructor in a provider. The
|
|
8
|
+
* bridge class, and therefore the type of the `router` prop, is the one difference
|
|
9
|
+
* between two providers of this factory.
|
|
11
10
|
*
|
|
12
11
|
* @packageDocumentation
|
|
13
12
|
*/
|
|
14
13
|
import { type JSX } from "solid-js";
|
|
15
14
|
import type { PlayActor, RouteMap, RouterBridge } from "@xmachines/play-router";
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
16
|
+
* The constructor shape that a bridge class must satisfy for
|
|
18
17
|
* `createPlayRouterProvider`: `(router, actor, routeMap) → RouterBridge`.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
* takes
|
|
22
|
-
* subclass
|
|
19
|
+
* A bridge with another constructor shape, for example `SolidRouterBridge`, which
|
|
20
|
+
* takes each hook result as a separate argument, receives a thin subclass. That
|
|
21
|
+
* subclass packs the `router` prop again.
|
|
23
22
|
*/
|
|
24
23
|
export type PlayRouterBridgeConstructor<TRouter> = new (router: TRouter, actor: PlayActor, routeMap: RouteMap) => RouterBridge;
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
25
|
+
* The props that every Solid `PlayRouterProvider` of the factory shares.
|
|
27
26
|
*
|
|
28
|
-
*
|
|
29
|
-
* router
|
|
27
|
+
* An adapter package re-exports a concrete alias, with `TRouter` bound to the type of
|
|
28
|
+
* its router. For example, `SolidRouterHooks` in `@xmachines/play-solid-router`.
|
|
30
29
|
*/
|
|
31
30
|
export interface PlayRouterProviderBaseProps<TRouter, TActor extends PlayActor = PlayActor> {
|
|
32
|
-
/** The actor to
|
|
31
|
+
/** The actor to keep in step with the router. */
|
|
33
32
|
actor: TActor;
|
|
34
|
-
/** The router the bridge
|
|
33
|
+
/** The router that the bridge keeps in step with the actor. */
|
|
35
34
|
router: TRouter;
|
|
36
|
-
/**
|
|
35
|
+
/** The route map of both directions, for the lookup between a state ID and a URL path. */
|
|
37
36
|
routeMap: RouteMap;
|
|
38
|
-
/**
|
|
37
|
+
/** The renderer callback receives the same concrete actor type as the prop. */
|
|
39
38
|
renderer: (actor: TActor, router: TRouter) => JSX.Element;
|
|
40
39
|
}
|
|
41
40
|
/**
|
|
42
|
-
*
|
|
41
|
+
* Creates a Solid `PlayRouterProvider` component of one bridge class.
|
|
43
42
|
*
|
|
44
|
-
* The
|
|
45
|
-
*
|
|
43
|
+
* The component of the return value connects a `PlayerActor` to the framework
|
|
44
|
+
* router. It keeps the actor state and the browser URL in step, in both directions.
|
|
46
45
|
*
|
|
47
|
-
* The
|
|
48
|
-
* execution model
|
|
49
|
-
*
|
|
50
|
-
*
|
|
46
|
+
* The component creates the bridge synchronously, during its own evaluation, because
|
|
47
|
+
* this is the execution model of Solid. It disconnects the bridge in `onCleanup`,
|
|
48
|
+
* when Solid disposes of the component. React is different: the stability of a prop
|
|
49
|
+
* is no concern here, because the `props` accessor of Solid is reactive already, and
|
|
50
|
+
* the component creates the bridge one time for each of its instances.
|
|
51
51
|
*
|
|
52
|
-
* @param BridgeCtor -
|
|
53
|
-
* @returns A `PlayRouterProvider` component
|
|
54
|
-
* `renderer` callback receives the same concrete actor type
|
|
52
|
+
* @param BridgeCtor - The bridge class. The provider builds it as `new BridgeCtor(router, actor, routeMap)`.
|
|
53
|
+
* @returns A `PlayRouterProvider` component. It is generic over the actor type.
|
|
54
|
+
* Therefore the `renderer` callback receives the same concrete actor type as the
|
|
55
|
+
* prop.
|
|
55
56
|
*
|
|
56
57
|
* @example
|
|
57
58
|
* ```tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-play-router-provider.d.ts","sourceRoot":"","sources":["../src/create-play-router-provider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"create-play-router-provider.d.ts","sourceRoot":"","sources":["../src/create-play-router-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAa,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,MAAM,2BAA2B,CAAC,OAAO,IAAI,KAClD,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,QAAQ,KACd,YAAY,CAAC;AAElB;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B,CAAC,OAAO,EAAE,MAAM,SAAS,SAAS,GAAG,SAAS;IACzF,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,MAAM,EAAE,OAAO,CAAC;IAChB,0FAA0F;IAC1F,QAAQ,EAAE,QAAQ,CAAC;IACnB,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAC/C,UAAU,EAAE,2BAA2B,CAAC,OAAO,CAAC,IAEb,MAAM,SAAS,SAAS,EAC1D,OAAO,2BAA2B,CAAC,OAAO,EAAE,MAAM,CAAC,SAWpD"}
|
|
@@ -2,32 +2,33 @@ import { onCleanup } from "solid-js";
|
|
|
2
2
|
import { memo } from "solid-js/web";
|
|
3
3
|
//#region packages/play-solid-router/src/create-play-router-provider.tsx
|
|
4
4
|
/**
|
|
5
|
-
* createPlayRouterProvider — factory
|
|
5
|
+
* createPlayRouterProvider — the factory of a Solid `PlayRouterProvider` component
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* factory.
|
|
7
|
+
* The factory holds the shape of the provider component of this package: it creates a
|
|
8
|
+
* bridge synchronously, during the evaluation of the component, it calls `connect()`,
|
|
9
|
+
* and it calls `disconnect()` in `onCleanup`. One call therefore wraps each Solid
|
|
10
|
+
* bridge with the standard `(router, actor, routeMap)` constructor in a provider. The
|
|
11
|
+
* bridge class, and therefore the type of the `router` prop, is the one difference
|
|
12
|
+
* between two providers of this factory.
|
|
14
13
|
*
|
|
15
14
|
* @packageDocumentation
|
|
16
15
|
*/
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Creates a Solid `PlayRouterProvider` component of one bridge class.
|
|
19
18
|
*
|
|
20
|
-
* The
|
|
21
|
-
*
|
|
19
|
+
* The component of the return value connects a `PlayerActor` to the framework
|
|
20
|
+
* router. It keeps the actor state and the browser URL in step, in both directions.
|
|
22
21
|
*
|
|
23
|
-
* The
|
|
24
|
-
* execution model
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* The component creates the bridge synchronously, during its own evaluation, because
|
|
23
|
+
* this is the execution model of Solid. It disconnects the bridge in `onCleanup`,
|
|
24
|
+
* when Solid disposes of the component. React is different: the stability of a prop
|
|
25
|
+
* is no concern here, because the `props` accessor of Solid is reactive already, and
|
|
26
|
+
* the component creates the bridge one time for each of its instances.
|
|
27
27
|
*
|
|
28
|
-
* @param BridgeCtor -
|
|
29
|
-
* @returns A `PlayRouterProvider` component
|
|
30
|
-
* `renderer` callback receives the same concrete actor type
|
|
28
|
+
* @param BridgeCtor - The bridge class. The provider builds it as `new BridgeCtor(router, actor, routeMap)`.
|
|
29
|
+
* @returns A `PlayRouterProvider` component. It is generic over the actor type.
|
|
30
|
+
* Therefore the `renderer` callback receives the same concrete actor type as the
|
|
31
|
+
* prop.
|
|
31
32
|
*
|
|
32
33
|
* @example
|
|
33
34
|
* ```tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-play-router-provider.js","names":["onCleanup","JSX","PlayActor","RouteMap","RouterBridge","PlayRouterBridgeConstructor","router","TRouter","actor","routeMap","PlayRouterProviderBaseProps","TActor","renderer","Element","createPlayRouterProvider","BridgeCtor","PlayRouterProvider","props","bridge","connect","disconnect","_$memo"],"sources":["../src/create-play-router-provider.tsx"],"sourcesContent":["/**\n * createPlayRouterProvider — factory
|
|
1
|
+
{"version":3,"file":"create-play-router-provider.js","names":["onCleanup","JSX","PlayActor","RouteMap","RouterBridge","PlayRouterBridgeConstructor","router","TRouter","actor","routeMap","PlayRouterProviderBaseProps","TActor","renderer","Element","createPlayRouterProvider","BridgeCtor","PlayRouterProvider","props","bridge","connect","disconnect","_$memo"],"sources":["../src/create-play-router-provider.tsx"],"sourcesContent":["/**\n * createPlayRouterProvider — the factory of a Solid `PlayRouterProvider` component\n *\n * The factory holds the shape of the provider component of this package: it creates a\n * bridge synchronously, during the evaluation of the component, it calls `connect()`,\n * and it calls `disconnect()` in `onCleanup`. One call therefore wraps each Solid\n * bridge with the standard `(router, actor, routeMap)` constructor in a provider. The\n * bridge class, and therefore the type of the `router` prop, is the one difference\n * between two providers of this factory.\n *\n * @packageDocumentation\n */\nimport { onCleanup, type JSX } from \"solid-js\";\nimport type { PlayActor, RouteMap, RouterBridge } from \"@xmachines/play-router\";\n\n/**\n * The constructor shape that a bridge class must satisfy for\n * `createPlayRouterProvider`: `(router, actor, routeMap) → RouterBridge`.\n *\n * A bridge with another constructor shape, for example `SolidRouterBridge`, which\n * takes each hook result as a separate argument, receives a thin subclass. That\n * subclass packs the `router` prop again.\n */\nexport type PlayRouterBridgeConstructor<TRouter> = new (\n\trouter: TRouter,\n\tactor: PlayActor,\n\trouteMap: RouteMap,\n) => RouterBridge;\n\n/**\n * The props that every Solid `PlayRouterProvider` of the factory shares.\n *\n * An adapter package re-exports a concrete alias, with `TRouter` bound to the type of\n * its router. For example, `SolidRouterHooks` in `@xmachines/play-solid-router`.\n */\nexport interface PlayRouterProviderBaseProps<TRouter, TActor extends PlayActor = PlayActor> {\n\t/** The actor to keep in step with the router. */\n\tactor: TActor;\n\t/** The router that the bridge keeps in step with the actor. */\n\trouter: TRouter;\n\t/** The route map of both directions, for the lookup between a state ID and a URL path. */\n\trouteMap: RouteMap;\n\t/** The renderer callback receives the same concrete actor type as the prop. */\n\trenderer: (actor: TActor, router: TRouter) => JSX.Element;\n}\n\n/**\n * Creates a Solid `PlayRouterProvider` component of one bridge class.\n *\n * The component of the return value connects a `PlayerActor` to the framework\n * router. It keeps the actor state and the browser URL in step, in both directions.\n *\n * The component creates the bridge synchronously, during its own evaluation, because\n * this is the execution model of Solid. It disconnects the bridge in `onCleanup`,\n * when Solid disposes of the component. React is different: the stability of a prop\n * is no concern here, because the `props` accessor of Solid is reactive already, and\n * the component creates the bridge one time for each of its instances.\n *\n * @param BridgeCtor - The bridge class. The provider builds it as `new BridgeCtor(router, actor, routeMap)`.\n * @returns A `PlayRouterProvider` component. It is generic over the actor type.\n * Therefore the `renderer` callback receives the same concrete actor type as the\n * prop.\n *\n * @example\n * ```tsx\n * export const PlayRouterProvider = createPlayRouterProvider(MySolidRouterBridge);\n * ```\n */\nexport function createPlayRouterProvider<TRouter>(\n\tBridgeCtor: PlayRouterBridgeConstructor<TRouter>,\n) {\n\treturn function PlayRouterProvider<TActor extends PlayActor>(\n\t\tprops: PlayRouterProviderBaseProps<TRouter, TActor>,\n\t) {\n\t\tconst bridge = new BridgeCtor(props.router, props.actor, props.routeMap);\n\t\tvoid bridge.connect();\n\n\t\tonCleanup(() => {\n\t\t\tvoid bridge.disconnect();\n\t\t});\n\n\t\treturn <>{props.renderer(props.actor, props.router)}</>;\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,SAAgBc,yBACfC,YACC;CACD,OAAO,SAASC,mBACfC,OACC;EACD,MAAMC,SAAS,IAAIH,WAAWE,MAAMX,QAAQW,MAAMT,OAAOS,MAAMR,QAAQ;EACvE,OAAYU,QAAQ;EAEpBnB,gBAAgB;GACf,OAAYoB,WAAW;EACxB,CAAC;EAED,OAAAC,WAAUJ,MAAML,SAASK,MAAMT,OAAOS,MAAMX,MAAM,CAAC;CACpD;AACD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @xmachines/play-solid-router
|
|
3
3
|
*
|
|
4
|
-
* SolidJS Router adapter for XMachines Universal Player Architecture
|
|
4
|
+
* SolidJS Router adapter for the XMachines Universal Player Architecture
|
|
5
5
|
*/
|
|
6
6
|
export { SolidRouterBridge } from "./solid-router-bridge.js";
|
|
7
7
|
export { PlayRouterProvider } from "./play-router-provider.js";
|
|
8
|
-
export type { PlayRouterProviderProps, PlayActor, RoutableActor, // @deprecated — use PlayActor
|
|
8
|
+
export type { PlayRouterProviderProps, PlayActor, RoutableActor, // @deprecated — use PlayActor of @xmachines/play-router
|
|
9
9
|
SolidRouterHooks, } from "./play-router-provider.js";
|
|
10
10
|
export { createPlayRouterProvider } from "./create-play-router-provider.js";
|
|
11
11
|
export type { PlayRouterProviderBaseProps, PlayRouterBridgeConstructor, } from "./create-play-router-provider.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACX,uBAAuB,EACvB,SAAS,EACT,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACX,uBAAuB,EACvB,SAAS,EACT,aAAa,EAAE,wDAAwD;AACvE,gBAAgB,GAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,YAAY,EACX,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACN,QAAQ,EACR,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,eAAe,GACpB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PlayRouterProvider — Solid
|
|
2
|
+
* PlayRouterProvider — the Solid wrapper of SolidRouterBridge
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `onCleanup
|
|
4
|
+
* The shared `createPlayRouterProvider` factory makes this component: it creates the
|
|
5
|
+
* bridge synchronously, during the evaluation of the component, and it disconnects the
|
|
6
|
+
* bridge in `onCleanup`, when Solid disposes of the component.
|
|
7
7
|
*/
|
|
8
8
|
import type { Navigator, Location, Params } from "@solidjs/router";
|
|
9
9
|
import type { PlayActor } from "@xmachines/play-router";
|
|
10
10
|
import { type PlayRouterProviderBaseProps } from "./create-play-router-provider.js";
|
|
11
11
|
export type { PlayActor };
|
|
12
|
-
/** @deprecated Use `PlayActor` from `@xmachines/play-router`.
|
|
12
|
+
/** @deprecated Use `PlayActor` from `@xmachines/play-router`. The next major version removes this alias. */
|
|
13
13
|
export type RoutableActor = PlayActor;
|
|
14
14
|
/**
|
|
15
|
-
* The three Solid Router
|
|
16
|
-
*
|
|
15
|
+
* The three results of the Solid Router hooks that `PlayRouterProvider` and
|
|
16
|
+
* `SolidRouterBridge` need. Give them directly from the hook calls of your component:
|
|
17
17
|
*
|
|
18
18
|
* ```tsx
|
|
19
19
|
* const navigate = useNavigate(); // → SolidRouterHooks.navigate
|
|
@@ -21,11 +21,11 @@ export type RoutableActor = PlayActor;
|
|
|
21
21
|
* const params = useParams(); // → SolidRouterHooks.params
|
|
22
22
|
* ```
|
|
23
23
|
*
|
|
24
|
-
* - `navigate` —
|
|
25
|
-
* - `location` — `pathname` and `search`
|
|
26
|
-
*
|
|
27
|
-
* - `params` —
|
|
28
|
-
* directly in `extractParams()
|
|
24
|
+
* - `navigate` — the bridge pushes each URL change with it, when the `currentRoute` of the actor changes.
|
|
25
|
+
* - `location` — the bridge reads `pathname` and `search` at the moment of `connect()`, for a deep link.
|
|
26
|
+
* Each later change of the pathname then goes to the actor, through `createEffect`.
|
|
27
|
+
* - `params` — the path parameters of the current route segment, which Solid parsed already. The bridge
|
|
28
|
+
* uses them directly in `extractParams()`, and it parses them not again with URLPattern.
|
|
29
29
|
*/
|
|
30
30
|
export type SolidRouterHooks = {
|
|
31
31
|
navigate: Navigator;
|
|
@@ -33,24 +33,25 @@ export type SolidRouterHooks = {
|
|
|
33
33
|
params: Params;
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* The props of the `PlayRouterProvider` of Solid Router.
|
|
37
37
|
*
|
|
38
|
-
* `router`
|
|
39
|
-
*
|
|
40
|
-
* in the parent component
|
|
38
|
+
* `router` holds the three results of the Solid Router hooks that drive the work in
|
|
39
|
+
* both directions. Take them from `useNavigate()`, from `useLocation()`, and from
|
|
40
|
+
* `useParams()` in the parent component. Call each hook inside a router context.
|
|
41
41
|
*/
|
|
42
42
|
export interface PlayRouterProviderProps<TActor extends PlayActor = PlayActor> extends PlayRouterProviderBaseProps<SolidRouterHooks, TActor> {
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* Connects a `PlayerActor` to Solid Router
|
|
46
|
-
* in
|
|
45
|
+
* Connects a `PlayerActor` to Solid Router. It keeps the actor state and the browser
|
|
46
|
+
* URL in step, in both directions.
|
|
47
47
|
*
|
|
48
|
-
* The
|
|
49
|
-
* execution model
|
|
50
|
-
*
|
|
51
|
-
*
|
|
48
|
+
* The component creates the bridge synchronously, during its own evaluation, because
|
|
49
|
+
* this is the execution model of Solid. It disconnects the bridge in `onCleanup`,
|
|
50
|
+
* when Solid disposes of the component. React is different: the stability of a prop
|
|
51
|
+
* is no concern here, because the `props` accessor of Solid is reactive already, and
|
|
52
|
+
* the component creates the bridge one time for each of its instances.
|
|
52
53
|
*
|
|
53
|
-
*
|
|
54
|
+
* Take the `router` prop from the Solid Router hooks in the parent component:
|
|
54
55
|
*
|
|
55
56
|
* ```tsx
|
|
56
57
|
* function AppShell() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play-router-provider.d.ts","sourceRoot":"","sources":["../src/play-router-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAEN,KAAK,2BAA2B,EAChC,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,4GAA4G;AAC5G,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB,CACvC,MAAM,SAAS,SAAS,GAAG,SAAS,CACnC,SAAQ,2BAA2B,CAAC,gBAAgB,EAAE,MAAM,CAAC;CAAG;
|
|
1
|
+
{"version":3,"file":"play-router-provider.d.ts","sourceRoot":"","sources":["../src/play-router-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAEN,KAAK,2BAA2B,EAChC,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,4GAA4G;AAC5G,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB,CACvC,MAAM,SAAS,SAAS,GAAG,SAAS,CACnC,SAAQ,2BAA2B,CAAC,gBAAgB,EAAE,MAAM,CAAC;CAAG;AAalE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,kBAAkB,iGAAmD,CAAC"}
|
|
@@ -2,8 +2,9 @@ import { SolidRouterBridge } from "./solid-router-bridge.js";
|
|
|
2
2
|
import { createPlayRouterProvider } from "./create-play-router-provider.js";
|
|
3
3
|
//#region packages/play-solid-router/src/play-router-provider.tsx
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* `(router, actor, routeMap)` shape
|
|
5
|
+
* The adapter binds the constructor of `SolidRouterBridge`, which takes the hook
|
|
6
|
+
* results, to the `(router, actor, routeMap)` shape of
|
|
7
|
+
* `createPlayRouterProvider`.
|
|
7
8
|
*/
|
|
8
9
|
var SolidHooksRouterBridge = class extends SolidRouterBridge {
|
|
9
10
|
constructor(router, actor, routeMap) {
|
|
@@ -11,15 +12,16 @@ var SolidHooksRouterBridge = class extends SolidRouterBridge {
|
|
|
11
12
|
}
|
|
12
13
|
};
|
|
13
14
|
/**
|
|
14
|
-
* Connects a `PlayerActor` to Solid Router
|
|
15
|
-
* in
|
|
15
|
+
* Connects a `PlayerActor` to Solid Router. It keeps the actor state and the browser
|
|
16
|
+
* URL in step, in both directions.
|
|
16
17
|
*
|
|
17
|
-
* The
|
|
18
|
-
* execution model
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* The component creates the bridge synchronously, during its own evaluation, because
|
|
19
|
+
* this is the execution model of Solid. It disconnects the bridge in `onCleanup`,
|
|
20
|
+
* when Solid disposes of the component. React is different: the stability of a prop
|
|
21
|
+
* is no concern here, because the `props` accessor of Solid is reactive already, and
|
|
22
|
+
* the component creates the bridge one time for each of its instances.
|
|
21
23
|
*
|
|
22
|
-
*
|
|
24
|
+
* Take the `router` prop from the Solid Router hooks in the parent component:
|
|
23
25
|
*
|
|
24
26
|
* ```tsx
|
|
25
27
|
* function AppShell() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play-router-provider.js","names":["Navigator","Location","Params","PlayActor","RouteMap","SolidRouterBridge","createPlayRouterProvider","PlayRouterProviderBaseProps","RoutableActor","SolidRouterHooks","navigate","location","params","PlayRouterProviderProps","TActor","SolidHooksRouterBridge","constructor","router","actor","routeMap","PlayRouterProvider"],"sources":["../src/play-router-provider.tsx"],"sourcesContent":["/**\n * PlayRouterProvider — Solid
|
|
1
|
+
{"version":3,"file":"play-router-provider.js","names":["Navigator","Location","Params","PlayActor","RouteMap","SolidRouterBridge","createPlayRouterProvider","PlayRouterProviderBaseProps","RoutableActor","SolidRouterHooks","navigate","location","params","PlayRouterProviderProps","TActor","SolidHooksRouterBridge","constructor","router","actor","routeMap","PlayRouterProvider"],"sources":["../src/play-router-provider.tsx"],"sourcesContent":["/**\n * PlayRouterProvider — the Solid wrapper of SolidRouterBridge\n *\n * The shared `createPlayRouterProvider` factory makes this component: it creates the\n * bridge synchronously, during the evaluation of the component, and it disconnects the\n * bridge in `onCleanup`, when Solid disposes of the component.\n */\nimport type { Navigator, Location, Params } from \"@solidjs/router\";\nimport type { PlayActor, RouteMap } from \"@xmachines/play-router\";\nimport { SolidRouterBridge } from \"./solid-router-bridge.js\";\nimport {\n\tcreatePlayRouterProvider,\n\ttype PlayRouterProviderBaseProps,\n} from \"./create-play-router-provider.js\";\n\nexport type { PlayActor };\n\n/** @deprecated Use `PlayActor` from `@xmachines/play-router`. The next major version removes this alias. */\nexport type RoutableActor = PlayActor;\n\n/**\n * The three results of the Solid Router hooks that `PlayRouterProvider` and\n * `SolidRouterBridge` need. Give them directly from the hook calls of your component:\n *\n * ```tsx\n * const navigate = useNavigate(); // → SolidRouterHooks.navigate\n * const location = useLocation(); // → SolidRouterHooks.location\n * const params = useParams(); // → SolidRouterHooks.params\n * ```\n *\n * - `navigate` — the bridge pushes each URL change with it, when the `currentRoute` of the actor changes.\n * - `location` — the bridge reads `pathname` and `search` at the moment of `connect()`, for a deep link.\n * Each later change of the pathname then goes to the actor, through `createEffect`.\n * - `params` — the path parameters of the current route segment, which Solid parsed already. The bridge\n * uses them directly in `extractParams()`, and it parses them not again with URLPattern.\n */\nexport type SolidRouterHooks = {\n\tnavigate: Navigator;\n\tlocation: Location;\n\tparams: Params;\n};\n\n/**\n * The props of the `PlayRouterProvider` of Solid Router.\n *\n * `router` holds the three results of the Solid Router hooks that drive the work in\n * both directions. Take them from `useNavigate()`, from `useLocation()`, and from\n * `useParams()` in the parent component. Call each hook inside a router context.\n */\nexport interface PlayRouterProviderProps<\n\tTActor extends PlayActor = PlayActor,\n> extends PlayRouterProviderBaseProps<SolidRouterHooks, TActor> {}\n\n/**\n * The adapter binds the constructor of `SolidRouterBridge`, which takes the hook\n * results, to the `(router, actor, routeMap)` shape of\n * `createPlayRouterProvider`.\n */\nclass SolidHooksRouterBridge extends SolidRouterBridge {\n\tconstructor(router: SolidRouterHooks, actor: PlayActor, routeMap: RouteMap) {\n\t\tsuper(router.navigate, router.location, router.params, actor, routeMap);\n\t}\n}\n\n/**\n * Connects a `PlayerActor` to Solid Router. It keeps the actor state and the browser\n * URL in step, in both directions.\n *\n * The component creates the bridge synchronously, during its own evaluation, because\n * this is the execution model of Solid. It disconnects the bridge in `onCleanup`,\n * when Solid disposes of the component. React is different: the stability of a prop\n * is no concern here, because the `props` accessor of Solid is reactive already, and\n * the component creates the bridge one time for each of its instances.\n *\n * Take the `router` prop from the Solid Router hooks in the parent component:\n *\n * ```tsx\n * function AppShell() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const params = useParams();\n *\n * return (\n * <PlayRouterProvider\n * actor={actor}\n * routeMap={routeMap}\n * router={{ navigate, location, params }}\n * renderer={(a) => <PlayRenderer actor={a} registry={registry} />}\n * />\n * );\n * }\n * ```\n */\nexport const PlayRouterProvider = createPlayRouterProvider(SolidHooksRouterBridge);\n"],"mappings":";;;;;;;;AA0DA,IAAMe,yBAAN,cAAqCV,kBAAkB;CACtDW,YAAYC,QAA0BC,OAAkBC,UAAoB;EAC3E,MAAMF,OAAOP,UAAUO,OAAON,UAAUM,OAAOL,QAAQM,OAAOC,QAAQ;CACvE;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAaC,qBAAqBd,yBAAyBS,sBAAsB"}
|
|
@@ -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"}
|
|
@@ -2,16 +2,18 @@ import { createEffect, createRoot, on } from "solid-js";
|
|
|
2
2
|
import { RouterBridgeBase } from "@xmachines/play-router";
|
|
3
3
|
//#region packages/play-solid-router/src/solid-router-bridge.ts
|
|
4
4
|
/**
|
|
5
|
-
* SolidJS Router bridge
|
|
5
|
+
* The SolidJS Router bridge. It implements the RouterBridge protocol through RouterBridgeBase
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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.
|
|
9
10
|
*
|
|
10
|
-
* **IMPORTANT:** `connect()`
|
|
11
|
-
*
|
|
12
|
-
* `createRoot()`, which
|
|
13
|
-
*
|
|
14
|
-
* `dispose()`
|
|
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()`.
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
17
19
|
* ```tsx
|
|
@@ -27,7 +29,7 @@ import { RouterBridgeBase } from "@xmachines/play-router";
|
|
|
27
29
|
* const routeMap = new RouteMap([...]);
|
|
28
30
|
* const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
|
|
29
31
|
*
|
|
30
|
-
* // connect()
|
|
32
|
+
* // Call connect() inside a Solid reactive owner
|
|
31
33
|
* bridge.connect();
|
|
32
34
|
* onCleanup(() => bridge.disconnect());
|
|
33
35
|
*
|
|
@@ -36,36 +38,40 @@ import { RouterBridgeBase } from "@xmachines/play-router";
|
|
|
36
38
|
* ```
|
|
37
39
|
*/
|
|
38
40
|
/**
|
|
39
|
-
* SolidJS Router integration bridge
|
|
41
|
+
* The SolidJS Router integration bridge. It extends RouterBridgeBase
|
|
40
42
|
*
|
|
41
|
-
*
|
|
42
|
-
* primitives. The actor
|
|
43
|
-
* The router
|
|
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.
|
|
44
47
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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.
|
|
48
52
|
*/
|
|
49
53
|
var SolidRouterBridge = class extends RouterBridgeBase {
|
|
50
54
|
solidNavigate;
|
|
51
55
|
location;
|
|
52
56
|
disposeRouterWatcher = null;
|
|
53
57
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
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.
|
|
56
61
|
*/
|
|
57
62
|
solidParams;
|
|
58
63
|
/**
|
|
59
|
-
*
|
|
64
|
+
* Creates a SolidJS Router bridge
|
|
60
65
|
*
|
|
61
|
-
* **CRITICAL:** `connect()`
|
|
66
|
+
* **CRITICAL:** call `connect()` inside a Solid component, where the hooks are available.
|
|
62
67
|
*
|
|
63
|
-
* @param solidNavigate -
|
|
64
|
-
* @param location -
|
|
65
|
-
* @param params -
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* @param
|
|
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
|
|
69
75
|
*/
|
|
70
76
|
constructor(solidNavigate, location, params, actor, routeMap) {
|
|
71
77
|
super(actor, {
|
|
@@ -77,19 +83,23 @@ var SolidRouterBridge = class extends RouterBridgeBase {
|
|
|
77
83
|
this.solidParams = params;
|
|
78
84
|
}
|
|
79
85
|
/**
|
|
80
|
-
*
|
|
86
|
+
* Reads each path parameter from the values that `useParams()` of Solid parsed before.
|
|
81
87
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* `syncActorFromRouter` is safe
|
|
85
|
-
* route
|
|
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.
|
|
86
92
|
*
|
|
87
|
-
*
|
|
88
|
-
* no
|
|
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.
|
|
89
96
|
*
|
|
90
|
-
* @param pathname - The
|
|
91
|
-
*
|
|
92
|
-
* @
|
|
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
|
|
93
103
|
*/
|
|
94
104
|
extractParams(pathname, stateId) {
|
|
95
105
|
const entries = Object.entries(this.solidParams).filter((entry) => entry[1] !== void 0 && entry[1] !== null && entry[1] !== "");
|
|
@@ -97,37 +107,39 @@ var SolidRouterBridge = class extends RouterBridgeBase {
|
|
|
97
107
|
return super.extractParams(pathname, stateId);
|
|
98
108
|
}
|
|
99
109
|
/**
|
|
100
|
-
*
|
|
110
|
+
* Navigates SolidJS Router to the given path.
|
|
101
111
|
*/
|
|
102
112
|
navigateRouter(path) {
|
|
103
113
|
this.solidNavigate(path);
|
|
104
114
|
}
|
|
105
115
|
/**
|
|
106
|
-
*
|
|
116
|
+
* Returns the current pathname of the router, for the first URL-to-actor synchronization in connect().
|
|
107
117
|
*/
|
|
108
118
|
getInitialRouterPath() {
|
|
109
119
|
return this.location.pathname ?? null;
|
|
110
120
|
}
|
|
111
121
|
/**
|
|
112
|
-
*
|
|
122
|
+
* Returns the initial URL search string, so that `connect()` can forward the query params.
|
|
113
123
|
*
|
|
114
|
-
*
|
|
115
|
-
* the same source
|
|
116
|
-
*
|
|
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: {}`.
|
|
117
128
|
*/
|
|
118
129
|
getInitialRouterSearch() {
|
|
119
130
|
return this.location.search || void 0;
|
|
120
131
|
}
|
|
121
132
|
/**
|
|
122
|
-
*
|
|
133
|
+
* Subscribes to each location change of SolidJS Router with createEffect.
|
|
123
134
|
*
|
|
124
|
-
*
|
|
135
|
+
* Call this method inside a Solid reactive owner: a component, or createRoot.
|
|
125
136
|
*
|
|
126
|
-
* The effect runs inside `createRoot()
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* The
|
|
130
|
-
* effect
|
|
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.
|
|
131
143
|
*/
|
|
132
144
|
watchRouterChanges() {
|
|
133
145
|
this.disposeRouterWatcher = createRoot((dispose) => {
|
|
@@ -139,23 +151,26 @@ var SolidRouterBridge = class extends RouterBridgeBase {
|
|
|
139
151
|
});
|
|
140
152
|
}
|
|
141
153
|
/**
|
|
142
|
-
*
|
|
154
|
+
* Stops the watch of the SolidJS Router changes.
|
|
143
155
|
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
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.
|
|
147
160
|
*/
|
|
148
161
|
unwatchRouterChanges() {
|
|
149
162
|
this.disposeRouterWatcher?.();
|
|
150
163
|
this.disposeRouterWatcher = null;
|
|
151
164
|
}
|
|
152
165
|
/**
|
|
153
|
-
*
|
|
166
|
+
* Disposes of the bridge. This method is the alias of disconnect.
|
|
154
167
|
*
|
|
155
168
|
* @example
|
|
156
169
|
* ```tsx
|
|
157
170
|
* onCleanup(() => bridge.dispose());
|
|
158
171
|
* ```
|
|
172
|
+
*
|
|
173
|
+
* @deprecated Use {@link RouterBridgeBase.disconnect | disconnect}. Will be removed in the next major.
|
|
159
174
|
*/
|
|
160
175
|
dispose() {
|
|
161
176
|
this.disconnect();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-router-bridge.js","names":[],"sources":["../src/solid-router-bridge.ts"],"sourcesContent":["/**\n * SolidJS Router bridge
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmachines/play-solid-router",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "SolidJS Router adapter for XMachines Universal Player Architecture",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "XMachines Contributors",
|
|
@@ -33,14 +33,15 @@
|
|
|
33
33
|
"lint": "oxlint .",
|
|
34
34
|
"format": "oxfmt .",
|
|
35
35
|
"test": "vitest",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
36
37
|
"test:watch": "vitest",
|
|
37
38
|
"clean": "rm -rf dist *.tsbuildinfo coverage node_modules/.svelte2tsx-* node_modules/.vite*"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@xmachines/play": "2.
|
|
41
|
-
"@xmachines/play-actor": "2.
|
|
42
|
-
"@xmachines/play-router": "2.
|
|
43
|
-
"@xmachines/play-signals": "2.
|
|
41
|
+
"@xmachines/play": "2.1.0",
|
|
42
|
+
"@xmachines/play-actor": "2.1.0",
|
|
43
|
+
"@xmachines/play-router": "2.1.0",
|
|
44
|
+
"@xmachines/play-signals": "2.1.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@solidjs/router": "^0.16.1",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@testing-library/jest-dom": "^6.9.1",
|
|
49
50
|
"@types/node": "^26.2.0",
|
|
50
51
|
"@vitest/browser-playwright": "^4.1.11",
|
|
51
|
-
"@xmachines/play-xstate": "2.
|
|
52
|
+
"@xmachines/play-xstate": "2.1.0",
|
|
52
53
|
"jsdom": "^29.1.0",
|
|
53
54
|
"oxfmt": "^0.64.0",
|
|
54
55
|
"oxlint": "^1.79.0",
|