@nifrajs/web-solid 5.10.0 → 5.12.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/CHANGELOG.md +30 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -1
- package/dist/compose.js +1 -1
- package/dist/compose.js.map +1 -1
- package/dist/keep-alive-view.js +1 -1
- package/dist/keep-alive-view.js.map +1 -1
- package/dist/route-slot.d.ts +29 -0
- package/dist/route-slot.d.ts.map +1 -0
- package/dist/route-slot.jsx +75 -0
- package/dist/route-slot.jsx.map +1 -0
- package/dist/router-context.d.ts +5 -0
- package/dist/router-context.d.ts.map +1 -0
- package/dist/router-context.js +14 -0
- package/dist/router-context.js.map +1 -0
- package/dist/router.d.ts +6 -4
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +4 -11
- package/dist/router.js.map +1 -1
- package/package.json +5 -5
- package/src/client.ts +2 -0
- package/src/compose.ts +1 -1
- package/src/keep-alive-view.ts +1 -1
- package/src/route-slot.tsx +137 -0
- package/src/router-context.ts +20 -0
- package/src/router.ts +5 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @nifrajs/web-solid
|
|
2
2
|
|
|
3
|
+
## 5.12.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [d274304]
|
|
8
|
+
- Updated dependencies [3a42e07]
|
|
9
|
+
- Updated dependencies [91cc290]
|
|
10
|
+
- Updated dependencies [28bdd6c]
|
|
11
|
+
- Updated dependencies [878bb89]
|
|
12
|
+
- Updated dependencies [c4bd5b2]
|
|
13
|
+
- @nifrajs/core@5.12.0
|
|
14
|
+
- @nifrajs/web@5.12.0
|
|
15
|
+
|
|
16
|
+
## 5.11.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- 3c8024d: Add independently addressable route slots with typed targets, server allowlists, and framework bindings.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [3c8024d]
|
|
25
|
+
- Updated dependencies [d76f9d7]
|
|
26
|
+
- Updated dependencies [9a0f0a0]
|
|
27
|
+
- Updated dependencies [bc40a1d]
|
|
28
|
+
- Updated dependencies [97a55bf]
|
|
29
|
+
- Updated dependencies [abf5a0b]
|
|
30
|
+
- @nifrajs/web@5.11.0
|
|
31
|
+
- @nifrajs/core@5.11.0
|
|
32
|
+
|
|
3
33
|
## 5.10.0
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAkBnE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAE/F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CA2C7D"}
|
package/dist/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setRouteSlotRuntime } from "@nifrajs/web/client";
|
|
1
2
|
/**
|
|
2
3
|
* @nifrajs/web-solid/client - Solid client runtime. `hydrate` hydrates a single SSR'd route;
|
|
3
4
|
* `mountRouter` hydrates the initial route then drives navigation through a Solid signal - so a
|
|
@@ -32,6 +33,7 @@ export function hydrate(chain, props, container) {
|
|
|
32
33
|
*/
|
|
33
34
|
export function mountRouter(options) {
|
|
34
35
|
const { router, routes, searchSchemas, matchChains, container } = options;
|
|
36
|
+
setRouteSlotRuntime({ router, routes, searchSchemas, matchChains });
|
|
35
37
|
setMountedRouter(router); // expose it to createFetcher/useFetchers (same page, client-only)
|
|
36
38
|
const el = container;
|
|
37
39
|
let dispose;
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,sGAAsG;AACtG,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAoB,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IACzE,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,kEAAkE;IAC3F,MAAM,EAAE,GAAG,SAAoB,CAAA;IAE/B,IAAI,OAAiC,CAAA;IACrC,IAAI,cAAc,GAAkB,IAAI,CAAA;IACxC,oGAAoG;IACpG,IAAI,MAAM,GAAoE,IAAI,CAAA;IAElF,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QACjC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAA;QACnD,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE;YACtB,kGAAkG;YAClG,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrD,MAAM,GAAG,WAAW,CAAA;YACpB,kGAAkG;YAClG,2FAA2F;YAC3F,OAAO,OAAO,CACZ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAC7B,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAC7E,EAAE,CAAA;QACL,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC,CAAA;IAED,KAAK,CAAC,IAAI,CAAC,CAAA;IACX,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAClC,gGAAgG;QAChG,yFAAyF;QACzF,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc;YAAE,OAAM;QACnE,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA,CAAC,wEAAwE;QAC7F,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,EAAE,CAAA,CAAC,qDAAqD;YACjE,KAAK,CAAC,KAAK,CAAC,CAAA;QACd,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,sGAAsG;AACtG,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAoB,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IACzE,mBAAmB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,CAAA;IACnE,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,kEAAkE;IAC3F,MAAM,EAAE,GAAG,SAAoB,CAAA;IAE/B,IAAI,OAAiC,CAAA;IACrC,IAAI,cAAc,GAAkB,IAAI,CAAA;IACxC,oGAAoG;IACpG,IAAI,MAAM,GAAoE,IAAI,CAAA;IAElF,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QACjC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAA;QACnD,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE;YACtB,kGAAkG;YAClG,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrD,MAAM,GAAG,WAAW,CAAA;YACpB,kGAAkG;YAClG,2FAA2F;YAC3F,OAAO,OAAO,CACZ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAC7B,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAC7E,EAAE,CAAA;QACL,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC,CAAA;IAED,KAAK,CAAC,IAAI,CAAC,CAAA;IACX,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAClC,gGAAgG;QAChG,yFAAyF;QACzF,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc;YAAE,OAAM;QACnE,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA,CAAC,wEAAwE;QAC7F,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,EAAE,CAAA,CAAC,qDAAqD;YACjE,KAAK,CAAC,KAAK,CAAC,CAAA;QACd,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/compose.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createComponent } from "solid-js";
|
|
2
|
-
import { RenderPropsContext, SearchContext } from "./router.js";
|
|
2
|
+
import { RenderPropsContext, SearchContext } from "./router-context.js";
|
|
3
3
|
// Frozen empty search so a render with no search context has a stable provider value.
|
|
4
4
|
const EMPTY_SEARCH = Object.freeze({});
|
|
5
5
|
/**
|
package/dist/compose.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,eAAe,EAAY,MAAM,UAAU,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,eAAe,EAAY,MAAM,UAAU,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEvE,sFAAsF;AACtF,MAAM,YAAY,GAAsC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAEzE;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB;IACnE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7B,IAAI,IAAI,GAAsB,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAA2B,EAAE,KAAK,CAAC,CAAA;IACjG,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAyC,CAAA;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAA;QAClB,6FAA6F;QAC7F,mGAAmG;QACnG,kEAAkE;QAClE,0FAA0F;QAC1F,6EAA6E;QAC7E,IAAI,GAAG,GAAG,EAAE,CACV,eAAe,CAAC,MAAM,EAAE;YACtB,IAAI,IAAI;gBACN,OAAO,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAA;YACtC,CAAC;YACD,IAAI,UAAU;gBACZ,OAAO,KAAK,CAAC,UAAU,CAAA;YACzB,CAAC;YACD,QAAQ,EAAE,KAAK,EAAE;SAClB,CAAC,CAAA;IACN,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAA;IAClB,qGAAqG;IACrG,sFAAsF;IACtF,OAAO,GAAG,EAAE,CACV,eAAe,CAAC,aAAa,CAAC,QAAQ,EAAE;QACtC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,YAAY,CAA4B;QACtE,IAAI,QAAQ;YACV,OAAO,eAAe,CAAC,kBAAkB,CAAC,QAAQ,EAAE;gBAClD,KAAK,EAAE,KAAK;gBACZ,IAAI,QAAQ;oBACV,OAAO,KAAK,EAAE,CAAA;gBAChB,CAAC;aACF,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACN,CAAC"}
|
package/dist/keep-alive-view.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createComponent, createComputed, createMemo, For, on, untrack, } from "solid-js";
|
|
2
2
|
import { Dynamic } from "solid-js/web";
|
|
3
3
|
import { PageContext } from "./page-visibility.js";
|
|
4
|
-
import { RenderPropsContext, SearchContext } from "./router.js";
|
|
4
|
+
import { RenderPropsContext, SearchContext } from "./router-context.js";
|
|
5
5
|
const EMPTY_SEARCH = Object.freeze({});
|
|
6
6
|
// The providers `compose` puts around a chain, for one slot's props.
|
|
7
7
|
const withRouteContext = (props, children) => createComponent(SearchContext.Provider, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keep-alive-view.js","sourceRoot":"","sources":["../src/keep-alive-view.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,eAAe,EACf,cAAc,EACd,UAAU,EACV,GAAG,EAEH,EAAE,EACF,OAAO,GACR,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAiB,MAAM,sBAAsB,CAAA;AACjE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"keep-alive-view.js","sourceRoot":"","sources":["../src/keep-alive-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RenderProps, RouteSlotName, RouteSlotTarget } from "@nifrajs/web";
|
|
2
|
+
import { type LoadedRouteSlot, type RouteSlotStatus, rawHref } from "@nifrajs/web/client";
|
|
3
|
+
import { type JSX } from "solid-js";
|
|
4
|
+
export interface RouteSlotController {
|
|
5
|
+
readonly target: () => string | undefined;
|
|
6
|
+
readonly status: () => RouteSlotStatus;
|
|
7
|
+
readonly content: () => LoadedRouteSlot | undefined;
|
|
8
|
+
readonly error: () => string | undefined;
|
|
9
|
+
open(target: RouteSlotTarget): void;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface RouteSlotHooks {
|
|
13
|
+
createEffect(effect: () => void): void;
|
|
14
|
+
createMemo<T>(read: () => T): () => T;
|
|
15
|
+
createSignal<T>(initial: T): readonly [() => T, (next: T | ((previous: T) => T)) => void];
|
|
16
|
+
onCleanup(cleanup: () => void): void;
|
|
17
|
+
}
|
|
18
|
+
export interface RouteSlotProps {
|
|
19
|
+
readonly name: RouteSlotName;
|
|
20
|
+
readonly fallback?: JSX.Element;
|
|
21
|
+
readonly error?: JSX.Element | ((code: string) => JSX.Element);
|
|
22
|
+
}
|
|
23
|
+
/** Build the hook with its small reactive surface; the test seam avoids global module mocks. */
|
|
24
|
+
export declare function createRouteSlotBinding(readProps: () => RenderProps | undefined, navigate: (href: ReturnType<typeof rawHref>) => void, hooks: RouteSlotHooks): (name: RouteSlotName) => RouteSlotController;
|
|
25
|
+
/** Read or navigate one route slot without changing any sibling slot's URL state or component tree. */
|
|
26
|
+
export declare const useRouteSlot: (name: RouteSlotName) => RouteSlotController;
|
|
27
|
+
/** Render the registered route's complete layout and page chain in this independently navigable region. */
|
|
28
|
+
export declare function RouteSlot(props: RouteSlotProps): JSX.Element;
|
|
29
|
+
//# sourceMappingURL=route-slot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-slot.d.ts","sourceRoot":"","sources":["../src/route-slot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,eAAe,EACpB,OAAO,EAMR,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAKL,KAAK,GAAG,EAIT,MAAM,UAAU,CAAA;AAKjB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,eAAe,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IACxC,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IACnC,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IACtC,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAA;IACrC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAA;IACzF,SAAS,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,CAAA;CAC/D;AAED,gGAAgG;AAChG,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,WAAW,GAAG,SAAS,EACxC,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,IAAI,EACpD,KAAK,EAAE,cAAc,GACpB,CAAC,IAAI,EAAE,aAAa,KAAK,mBAAmB,CA+C9C;AAED,uGAAuG;AACvG,eAAO,MAAM,YAAY,SAlDf,aAAa,KAAK,mBAsD3B,CAAA;AAED,2GAA2G;AAE3G,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CAuB5D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getRouteSlotStore, rawHref, routeSlotSyncKey, routeSlotTargetFromPath, setRouteSlot, stripRouteSlots, syncRouteSlotStore, } from "@nifrajs/web/client";
|
|
2
|
+
import { navigateNow } from "@nifrajs/web/internal/navigate-runtime";
|
|
3
|
+
import { createComponent, createEffect, createMemo, createSignal, onCleanup, untrack, useContext, } from "solid-js";
|
|
4
|
+
import { Dynamic } from "solid-js/web";
|
|
5
|
+
import { compose } from "./compose.js";
|
|
6
|
+
import { RenderPropsContext } from "./router-context.js";
|
|
7
|
+
/** Build the hook with its small reactive surface; the test seam avoids global module mocks. */
|
|
8
|
+
export function createRouteSlotBinding(readProps, navigate, hooks) {
|
|
9
|
+
return function useRouteSlot(name) {
|
|
10
|
+
const props = readProps();
|
|
11
|
+
const path = () => props?.path ?? "/";
|
|
12
|
+
const pending = () => props?.pending === true;
|
|
13
|
+
const parsed = hooks.createMemo(() => routeSlotTargetFromPath(path(), name));
|
|
14
|
+
const basePath = hooks.createMemo(() => stripRouteSlots(path()));
|
|
15
|
+
const store = hooks.createMemo(() => getRouteSlotStore(basePath(), name));
|
|
16
|
+
const [snapshot, setSnapshot] = hooks.createSignal(store().getServerSnapshot());
|
|
17
|
+
const requestKey = hooks.createMemo(() => routeSlotSyncKey(basePath(), name, parsed().target, parsed().error, pending()));
|
|
18
|
+
hooks.createEffect(() => {
|
|
19
|
+
const currentStore = store();
|
|
20
|
+
setSnapshot(currentStore.getSnapshot());
|
|
21
|
+
const unsubscribe = currentStore.subscribe(() => setSnapshot(currentStore.getSnapshot()));
|
|
22
|
+
hooks.onCleanup(unsubscribe);
|
|
23
|
+
});
|
|
24
|
+
hooks.createEffect(() => {
|
|
25
|
+
const current = parsed();
|
|
26
|
+
syncRouteSlotStore(store(), basePath(), name, current.target, current.error, pending());
|
|
27
|
+
});
|
|
28
|
+
const current = hooks.createMemo(() => {
|
|
29
|
+
const value = snapshot();
|
|
30
|
+
return value.key === requestKey() ? value : undefined;
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
target: () => parsed().target,
|
|
34
|
+
status: () => current()?.status ??
|
|
35
|
+
(parsed().error !== undefined
|
|
36
|
+
? "error"
|
|
37
|
+
: pending() || parsed().target === undefined
|
|
38
|
+
? "idle"
|
|
39
|
+
: "loading"),
|
|
40
|
+
content: () => current()?.content,
|
|
41
|
+
error: () => current()?.error ?? parsed().error,
|
|
42
|
+
open: (target) => navigate(rawHref(setRouteSlot(path(), name, String(target)))),
|
|
43
|
+
close: () => navigate(rawHref(setRouteSlot(path(), name, null))),
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Read or navigate one route slot without changing any sibling slot's URL state or component tree. */
|
|
48
|
+
export const useRouteSlot = createRouteSlotBinding(() => useContext(RenderPropsContext), navigateNow, { createEffect, createMemo, createSignal, onCleanup });
|
|
49
|
+
/** Render the registered route's complete layout and page chain in this independently navigable region. */
|
|
50
|
+
export function RouteSlot(props) {
|
|
51
|
+
const slot = useRouteSlot(props.name);
|
|
52
|
+
const view = createMemo(() => {
|
|
53
|
+
const content = slot.content();
|
|
54
|
+
if (content !== undefined)
|
|
55
|
+
return untrack(() => compose(content.chain, content)());
|
|
56
|
+
if (slot.status() === "error") {
|
|
57
|
+
const code = slot.error() ?? "unavailable";
|
|
58
|
+
const error = props.error;
|
|
59
|
+
if (typeof error === "function")
|
|
60
|
+
return untrack(() => error(code));
|
|
61
|
+
if (error !== undefined)
|
|
62
|
+
return error;
|
|
63
|
+
return untrack(() => createComponent(Dynamic, {
|
|
64
|
+
component: "div",
|
|
65
|
+
role: "alert",
|
|
66
|
+
"data-route-slot-error": code,
|
|
67
|
+
children: "This panel is unavailable.",
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
return slot.target() !== undefined ? (props.fallback ?? null) : null;
|
|
71
|
+
});
|
|
72
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion lint/plugin/noChainedTypeAssertions: Solid inserts an accessor reactively as its child, while its JSX.Element type excludes functions.
|
|
73
|
+
return view;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=route-slot.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-slot.jsx","sourceRoot":"","sources":["../src/route-slot.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RenderProps } from "@nifrajs/web";
|
|
2
|
+
import { type Accessor, type Context } from "solid-js";
|
|
3
|
+
export declare const SearchContext: Context<Accessor<Record<string, unknown>> | undefined>;
|
|
4
|
+
export declare const RenderPropsContext: Context<RenderProps | undefined>;
|
|
5
|
+
//# sourceMappingURL=router-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-context.d.ts","sourceRoot":"","sources":["../src/router-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAiB,MAAM,UAAU,CAAA;AAQrE,eAAO,MAAM,aAAa,wDACoE,CAAA;AAO9F,eAAO,MAAM,kBAAkB,kCACuC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext } from "solid-js";
|
|
2
|
+
/** Shared provider identities across the Bun server and Vite's SSR module graph. */
|
|
3
|
+
const SEARCH_CONTEXT_SLOT = Symbol.for("nifra.web-solid.search-context");
|
|
4
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The namespaced Symbol.for key shares one matching Solid Context across Bun and Vite's duplicate module graphs in this SSR process.
|
|
5
|
+
const searchContextSlot = globalThis;
|
|
6
|
+
export const SearchContext = searchContextSlot[SEARCH_CONTEXT_SLOT] ?? createContext();
|
|
7
|
+
searchContextSlot[SEARCH_CONTEXT_SLOT] = SearchContext;
|
|
8
|
+
/** Props for the composed route chain; a global singleton for the same reason as SearchContext. */
|
|
9
|
+
const PROPS_CONTEXT_SLOT = Symbol.for("nifra.web-solid.props-context");
|
|
10
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The namespaced Symbol.for key shares one matching Solid Context across Bun and Vite's duplicate module graphs in this SSR process.
|
|
11
|
+
const propsContextSlot = globalThis;
|
|
12
|
+
export const RenderPropsContext = propsContextSlot[PROPS_CONTEXT_SLOT] ?? createContext();
|
|
13
|
+
propsContextSlot[PROPS_CONTEXT_SLOT] = RenderPropsContext;
|
|
14
|
+
//# sourceMappingURL=router-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-context.js","sourceRoot":"","sources":["../src/router-context.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,aAAa,EAAE,MAAM,UAAU,CAAA;AAErE,oFAAoF;AACpF,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;AACxE,oMAAoM;AACpM,MAAM,iBAAiB,GAAG,UAEzB,CAAA;AACD,MAAM,CAAC,MAAM,aAAa,GACxB,iBAAiB,CAAC,mBAAmB,CAAC,IAAI,aAAa,EAAqC,CAAA;AAC9F,iBAAiB,CAAC,mBAAmB,CAAC,GAAG,aAAa,CAAA;AAEtD,mGAAmG;AACnG,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;AACtE,oMAAoM;AACpM,MAAM,gBAAgB,GAAG,UAAyE,CAAA;AAClG,MAAM,CAAC,MAAM,kBAAkB,GAC7B,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,aAAa,EAAe,CAAA;AACtE,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAA"}
|
package/dist/router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { InferOutput, StandardSchemaV1 } from "@nifrajs/core/server";
|
|
2
|
-
import type { Blocker, BlockerFunction, BlockerState, NavigateFunction,
|
|
2
|
+
import type { Blocker, BlockerFunction, BlockerState, NavigateFunction, UIMatch } from "@nifrajs/web";
|
|
3
3
|
/**
|
|
4
4
|
* `@nifrajs/web-solid/router` - Solid routing bindings over the agnostic `@nifrajs/web` history layer:
|
|
5
5
|
* `useNavigate` (programmatic navigation), `useBlocker` (the unsaved-changes guard), and `useSearch`
|
|
@@ -7,12 +7,14 @@ import type { Blocker, BlockerFunction, BlockerState, NavigateFunction, RenderPr
|
|
|
7
7
|
* DOM-free bridges (`getBrowserNavigate` / `registerBlocker`, populated by `installHistory`); `useSearch`
|
|
8
8
|
* reads the accessor `compose` provides on SSR + client mount alike. Imports only `solid-js`. No JSX.
|
|
9
9
|
*/
|
|
10
|
-
import { type Accessor
|
|
10
|
+
import { type Accessor } from "solid-js";
|
|
11
|
+
import { RenderPropsContext, SearchContext } from "./router-context.js";
|
|
11
12
|
export { href, rawHref } from "@nifrajs/web/client";
|
|
12
13
|
export { onPageHide, onPageShow, usePageVisibility } from "./page-visibility.js";
|
|
14
|
+
export type { RouteSlotController, RouteSlotProps } from "./route-slot.tsx";
|
|
15
|
+
export { RouteSlot, useRouteSlot } from "./route-slot.tsx";
|
|
13
16
|
export type { Blocker, BlockerFunction, BlockerState, NavigateFunction, UIMatch };
|
|
14
|
-
export
|
|
15
|
-
export declare const RenderPropsContext: Context<RenderProps | undefined>;
|
|
17
|
+
export { RenderPropsContext, SearchContext };
|
|
16
18
|
/**
|
|
17
19
|
* The rendered chain - each layout, then the page - with the URL prefix, params and loader data each
|
|
18
20
|
* one owns, plus its `handle` export, as a reactive accessor. The same list on the server render and
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAIzE,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAIzE,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,OAAO,EACR,MAAM,cAAc,CAAA;AAOrB;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAmD,MAAM,UAAU,CAAA;AAEzF,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEvE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAChF,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC1D,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAA;AACjF,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAA;AAe5C;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,IAAI,QAAQ,CAAC,SAAS,OAAO,EAAE,CAAC,CAIzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAS,gBAAgB,GAAG,SAAS,GAAG,SAAS,KAAK,QAAQ,CAC5F,MAAM,SAAS,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAChF,CAIA;AAED;;kCAEkC;AAClC,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,OAAO,GAAG,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,CAYpF"}
|
package/dist/router.js
CHANGED
|
@@ -11,10 +11,13 @@ import { navigateNow } from "@nifrajs/web/internal/navigate-runtime";
|
|
|
11
11
|
* DOM-free bridges (`getBrowserNavigate` / `registerBlocker`, populated by `installHistory`); `useSearch`
|
|
12
12
|
* reads the accessor `compose` provides on SSR + client mount alike. Imports only `solid-js`. No JSX.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { createMemo, createSignal, onCleanup, useContext } from "solid-js";
|
|
15
15
|
import { PageContext } from "./page-visibility.js";
|
|
16
|
+
import { RenderPropsContext, SearchContext } from "./router-context.js";
|
|
16
17
|
export { href, rawHref } from "@nifrajs/web/client";
|
|
17
18
|
export { onPageHide, onPageShow, usePageVisibility } from "./page-visibility.js";
|
|
19
|
+
export { RouteSlot, useRouteSlot } from "./route-slot.jsx";
|
|
20
|
+
export { RenderPropsContext, SearchContext };
|
|
18
21
|
// Frozen empty search + a stable accessor for a `useSearch` used outside a nifra route tree.
|
|
19
22
|
const EMPTY_SEARCH = Object.freeze({});
|
|
20
23
|
const EMPTY_SEARCH_ACCESSOR = () => EMPTY_SEARCH;
|
|
@@ -25,16 +28,6 @@ const EMPTY_SEARCH_ACCESSOR = () => EMPTY_SEARCH;
|
|
|
25
28
|
* code under Bun provides; route modules through Vite's SSR runner read), and Solid matches provider
|
|
26
29
|
* to reader by context object identity - two `createContext` results make `useSearch` SSR-render its
|
|
27
30
|
* empty default in dev. */
|
|
28
|
-
const SEARCH_CONTEXT_SLOT = Symbol.for("nifra.web-solid.search-context");
|
|
29
|
-
const searchContextSlot = globalThis;
|
|
30
|
-
export const SearchContext = searchContextSlot[SEARCH_CONTEXT_SLOT] ?? createContext();
|
|
31
|
-
searchContextSlot[SEARCH_CONTEXT_SLOT] = SearchContext;
|
|
32
|
-
/** The props `compose` rendered the chain with - getters over the router snapshot on the client - which
|
|
33
|
-
* {@link useMatches} reads. A `globalThis` singleton for the same reason as {@link SearchContext}. */
|
|
34
|
-
const PROPS_CONTEXT_SLOT = Symbol.for("nifra.web-solid.props-context");
|
|
35
|
-
const propsContextSlot = globalThis;
|
|
36
|
-
export const RenderPropsContext = propsContextSlot[PROPS_CONTEXT_SLOT] ?? createContext();
|
|
37
|
-
propsContextSlot[PROPS_CONTEXT_SLOT] = RenderPropsContext;
|
|
38
31
|
const NO_MATCHES = Object.freeze([]);
|
|
39
32
|
/**
|
|
40
33
|
* The rendered chain - each layout, then the page - with the URL prefix, params and loader data each
|
package/dist/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAWA,mFAAmF;AACnF,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACnE,6EAA6E;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AACpE;;;;;;GAMG;AACH,OAAO,EAAiB,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEvE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAEhF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE1D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAA;AAE5C,6FAA6F;AAC7F,MAAM,YAAY,GAAsC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AACzE,MAAM,qBAAqB,GAAsC,GAAG,EAAE,CAAC,YAAY,CAAA;AAEnF;;;;;;2BAM2B;AAC3B,MAAM,UAAU,GAAuB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAA;IAC5C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,EAAE,CAAC,UAAU,CAAA;IAChD,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS;IAGvB,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAEzD,CAAA;AACH,CAAC;AAED;;kCAEkC;AAClC,MAAM,UAAU,WAAW;IACzB,OAAO,WAAW,CAAA;AACpB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,WAAsC;IAC/D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,YAAY,CAAU,YAAY,CAAC,CAAA;IACjE,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACpC,SAAS,CACP,eAAe,CACb,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI;QACvB,CAAC,OAAO,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EACvE,UAAU,CACX,CACF,CAAA;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nifrajs/web-solid",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.12.0",
|
|
4
4
|
"description": "Solid render adapter for @nifrajs/web - SSR + hydration, with the Solid Babel build plugin (@nifrajs/web-solid/plugin).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -132,16 +132,16 @@
|
|
|
132
132
|
"dependencies": {
|
|
133
133
|
"@babel/core": "^7.26.0",
|
|
134
134
|
"@babel/preset-typescript": "^7.26.0",
|
|
135
|
-
"@nifrajs/core": "5.
|
|
136
|
-
"@nifrajs/web": "5.
|
|
135
|
+
"@nifrajs/core": "5.12.0",
|
|
136
|
+
"@nifrajs/web": "5.12.0",
|
|
137
137
|
"babel-preset-solid": "^1.9.3",
|
|
138
138
|
"solid-refresh": "^0.7.8"
|
|
139
139
|
},
|
|
140
140
|
"peerDependencies": {
|
|
141
141
|
"@mdx-js/mdx": "^3",
|
|
142
142
|
"solid-js": "^1.9.0",
|
|
143
|
-
"@nifrajs/i18n": "^5.
|
|
144
|
-
"@nifrajs/image": "^5.
|
|
143
|
+
"@nifrajs/i18n": "^5.12.0",
|
|
144
|
+
"@nifrajs/image": "^5.12.0"
|
|
145
145
|
},
|
|
146
146
|
"peerDependenciesMeta": {
|
|
147
147
|
"@mdx-js/mdx": {
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MountRouterOptions, RenderProps } from "@nifrajs/web"
|
|
2
|
+
import { setRouteSlotRuntime } from "@nifrajs/web/client"
|
|
2
3
|
/**
|
|
3
4
|
* @nifrajs/web-solid/client - Solid client runtime. `hydrate` hydrates a single SSR'd route;
|
|
4
5
|
* `mountRouter` hydrates the initial route then drives navigation through a Solid signal - so a
|
|
@@ -36,6 +37,7 @@ export function hydrate(chain: readonly unknown[], props: RenderProps, container
|
|
|
36
37
|
*/
|
|
37
38
|
export function mountRouter(options: MountRouterOptions): void {
|
|
38
39
|
const { router, routes, searchSchemas, matchChains, container } = options
|
|
40
|
+
setRouteSlotRuntime({ router, routes, searchSchemas, matchChains })
|
|
39
41
|
setMountedRouter(router) // expose it to createFetcher/useFetchers (same page, client-only)
|
|
40
42
|
const el = container as Element
|
|
41
43
|
|
package/src/compose.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RenderProps } from "@nifrajs/web"
|
|
2
2
|
import { type Component, createComponent, type JSX } from "solid-js"
|
|
3
|
-
import { RenderPropsContext, SearchContext } from "./router.ts"
|
|
3
|
+
import { RenderPropsContext, SearchContext } from "./router-context.ts"
|
|
4
4
|
|
|
5
5
|
// Frozen empty search so a render with no search context has a stable provider value.
|
|
6
6
|
const EMPTY_SEARCH: Readonly<Record<string, unknown>> = Object.freeze({})
|
package/src/keep-alive-view.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "solid-js"
|
|
24
24
|
import { Dynamic } from "solid-js/web"
|
|
25
25
|
import { PageContext, type PageSlot } from "./page-visibility.ts"
|
|
26
|
-
import { RenderPropsContext, SearchContext } from "./router.ts"
|
|
26
|
+
import { RenderPropsContext, SearchContext } from "./router-context.ts"
|
|
27
27
|
|
|
28
28
|
/** What the view renders with: one per mount, on the server or in the browser. */
|
|
29
29
|
export interface KeepAliveViewMount {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { RenderProps, RouteSlotName, RouteSlotTarget } from "@nifrajs/web"
|
|
2
|
+
import {
|
|
3
|
+
getRouteSlotStore,
|
|
4
|
+
type LoadedRouteSlot,
|
|
5
|
+
type RouteSlotSnapshot,
|
|
6
|
+
type RouteSlotStatus,
|
|
7
|
+
rawHref,
|
|
8
|
+
routeSlotSyncKey,
|
|
9
|
+
routeSlotTargetFromPath,
|
|
10
|
+
setRouteSlot,
|
|
11
|
+
stripRouteSlots,
|
|
12
|
+
syncRouteSlotStore,
|
|
13
|
+
} from "@nifrajs/web/client"
|
|
14
|
+
import { navigateNow } from "@nifrajs/web/internal/navigate-runtime"
|
|
15
|
+
import {
|
|
16
|
+
createComponent,
|
|
17
|
+
createEffect,
|
|
18
|
+
createMemo,
|
|
19
|
+
createSignal,
|
|
20
|
+
type JSX,
|
|
21
|
+
onCleanup,
|
|
22
|
+
untrack,
|
|
23
|
+
useContext,
|
|
24
|
+
} from "solid-js"
|
|
25
|
+
import { Dynamic } from "solid-js/web"
|
|
26
|
+
import { compose } from "./compose.ts"
|
|
27
|
+
import { RenderPropsContext } from "./router-context.ts"
|
|
28
|
+
|
|
29
|
+
export interface RouteSlotController {
|
|
30
|
+
readonly target: () => string | undefined
|
|
31
|
+
readonly status: () => RouteSlotStatus
|
|
32
|
+
readonly content: () => LoadedRouteSlot | undefined
|
|
33
|
+
readonly error: () => string | undefined
|
|
34
|
+
open(target: RouteSlotTarget): void
|
|
35
|
+
close(): void
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface RouteSlotHooks {
|
|
39
|
+
createEffect(effect: () => void): void
|
|
40
|
+
createMemo<T>(read: () => T): () => T
|
|
41
|
+
createSignal<T>(initial: T): readonly [() => T, (next: T | ((previous: T) => T)) => void]
|
|
42
|
+
onCleanup(cleanup: () => void): void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface RouteSlotProps {
|
|
46
|
+
readonly name: RouteSlotName
|
|
47
|
+
readonly fallback?: JSX.Element
|
|
48
|
+
readonly error?: JSX.Element | ((code: string) => JSX.Element)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Build the hook with its small reactive surface; the test seam avoids global module mocks. */
|
|
52
|
+
export function createRouteSlotBinding(
|
|
53
|
+
readProps: () => RenderProps | undefined,
|
|
54
|
+
navigate: (href: ReturnType<typeof rawHref>) => void,
|
|
55
|
+
hooks: RouteSlotHooks,
|
|
56
|
+
): (name: RouteSlotName) => RouteSlotController {
|
|
57
|
+
return function useRouteSlot(name: RouteSlotName): RouteSlotController {
|
|
58
|
+
const props = readProps()
|
|
59
|
+
const path = (): string => props?.path ?? "/"
|
|
60
|
+
const pending = (): boolean => props?.pending === true
|
|
61
|
+
const parsed = hooks.createMemo(() => routeSlotTargetFromPath(path(), name))
|
|
62
|
+
const basePath = hooks.createMemo(() => stripRouteSlots(path()))
|
|
63
|
+
const store = hooks.createMemo(() => getRouteSlotStore(basePath(), name))
|
|
64
|
+
const [snapshot, setSnapshot] = hooks.createSignal<RouteSlotSnapshot>(
|
|
65
|
+
store().getServerSnapshot(),
|
|
66
|
+
)
|
|
67
|
+
const requestKey = hooks.createMemo(() =>
|
|
68
|
+
routeSlotSyncKey(basePath(), name, parsed().target, parsed().error, pending()),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
hooks.createEffect(() => {
|
|
72
|
+
const currentStore = store()
|
|
73
|
+
setSnapshot(currentStore.getSnapshot())
|
|
74
|
+
const unsubscribe = currentStore.subscribe(() => setSnapshot(currentStore.getSnapshot()))
|
|
75
|
+
hooks.onCleanup(unsubscribe)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
hooks.createEffect(() => {
|
|
79
|
+
const current = parsed()
|
|
80
|
+
syncRouteSlotStore(store(), basePath(), name, current.target, current.error, pending())
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const current = hooks.createMemo(() => {
|
|
84
|
+
const value = snapshot()
|
|
85
|
+
return value.key === requestKey() ? value : undefined
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
target: () => parsed().target,
|
|
90
|
+
status: () =>
|
|
91
|
+
current()?.status ??
|
|
92
|
+
(parsed().error !== undefined
|
|
93
|
+
? "error"
|
|
94
|
+
: pending() || parsed().target === undefined
|
|
95
|
+
? "idle"
|
|
96
|
+
: "loading"),
|
|
97
|
+
content: () => current()?.content,
|
|
98
|
+
error: () => current()?.error ?? parsed().error,
|
|
99
|
+
open: (target) => navigate(rawHref(setRouteSlot(path(), name, String(target)))),
|
|
100
|
+
close: () => navigate(rawHref(setRouteSlot(path(), name, null))),
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Read or navigate one route slot without changing any sibling slot's URL state or component tree. */
|
|
106
|
+
export const useRouteSlot = createRouteSlotBinding(
|
|
107
|
+
() => useContext(RenderPropsContext),
|
|
108
|
+
navigateNow,
|
|
109
|
+
{ createEffect, createMemo, createSignal, onCleanup },
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
/** Render the registered route's complete layout and page chain in this independently navigable region. */
|
|
113
|
+
|
|
114
|
+
export function RouteSlot(props: RouteSlotProps): JSX.Element {
|
|
115
|
+
const slot = useRouteSlot(props.name)
|
|
116
|
+
const view = createMemo(() => {
|
|
117
|
+
const content = slot.content()
|
|
118
|
+
if (content !== undefined) return untrack(() => compose(content.chain, content)())
|
|
119
|
+
if (slot.status() === "error") {
|
|
120
|
+
const code = slot.error() ?? "unavailable"
|
|
121
|
+
const error = props.error
|
|
122
|
+
if (typeof error === "function") return untrack(() => error(code))
|
|
123
|
+
if (error !== undefined) return error
|
|
124
|
+
return untrack(() =>
|
|
125
|
+
createComponent(Dynamic, {
|
|
126
|
+
component: "div",
|
|
127
|
+
role: "alert",
|
|
128
|
+
"data-route-slot-error": code,
|
|
129
|
+
children: "This panel is unavailable.",
|
|
130
|
+
}),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
return slot.target() !== undefined ? (props.fallback ?? null) : null
|
|
134
|
+
})
|
|
135
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion lint/plugin/noChainedTypeAssertions: Solid inserts an accessor reactively as its child, while its JSX.Element type excludes functions.
|
|
136
|
+
return view as unknown as JSX.Element
|
|
137
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RenderProps } from "@nifrajs/web"
|
|
2
|
+
import { type Accessor, type Context, createContext } from "solid-js"
|
|
3
|
+
|
|
4
|
+
/** Shared provider identities across the Bun server and Vite's SSR module graph. */
|
|
5
|
+
const SEARCH_CONTEXT_SLOT = Symbol.for("nifra.web-solid.search-context")
|
|
6
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The namespaced Symbol.for key shares one matching Solid Context across Bun and Vite's duplicate module graphs in this SSR process.
|
|
7
|
+
const searchContextSlot = globalThis as {
|
|
8
|
+
[SEARCH_CONTEXT_SLOT]?: Context<Accessor<Record<string, unknown>> | undefined>
|
|
9
|
+
}
|
|
10
|
+
export const SearchContext =
|
|
11
|
+
searchContextSlot[SEARCH_CONTEXT_SLOT] ?? createContext<Accessor<Record<string, unknown>>>()
|
|
12
|
+
searchContextSlot[SEARCH_CONTEXT_SLOT] = SearchContext
|
|
13
|
+
|
|
14
|
+
/** Props for the composed route chain; a global singleton for the same reason as SearchContext. */
|
|
15
|
+
const PROPS_CONTEXT_SLOT = Symbol.for("nifra.web-solid.props-context")
|
|
16
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The namespaced Symbol.for key shares one matching Solid Context across Bun and Vite's duplicate module graphs in this SSR process.
|
|
17
|
+
const propsContextSlot = globalThis as { [PROPS_CONTEXT_SLOT]?: Context<RenderProps | undefined> }
|
|
18
|
+
export const RenderPropsContext =
|
|
19
|
+
propsContextSlot[PROPS_CONTEXT_SLOT] ?? createContext<RenderProps>()
|
|
20
|
+
propsContextSlot[PROPS_CONTEXT_SLOT] = RenderPropsContext
|
package/src/router.ts
CHANGED
|
@@ -7,7 +7,6 @@ import type {
|
|
|
7
7
|
BlockerFunction,
|
|
8
8
|
BlockerState,
|
|
9
9
|
NavigateFunction,
|
|
10
|
-
RenderProps,
|
|
11
10
|
UIMatch,
|
|
12
11
|
} from "@nifrajs/web"
|
|
13
12
|
// `/client`, not the root - these are DOM values, and the root's graph carries the
|
|
@@ -23,20 +22,16 @@ import { navigateNow } from "@nifrajs/web/internal/navigate-runtime"
|
|
|
23
22
|
* DOM-free bridges (`getBrowserNavigate` / `registerBlocker`, populated by `installHistory`); `useSearch`
|
|
24
23
|
* reads the accessor `compose` provides on SSR + client mount alike. Imports only `solid-js`. No JSX.
|
|
25
24
|
*/
|
|
26
|
-
import {
|
|
27
|
-
type Accessor,
|
|
28
|
-
type Context,
|
|
29
|
-
createContext,
|
|
30
|
-
createMemo,
|
|
31
|
-
createSignal,
|
|
32
|
-
onCleanup,
|
|
33
|
-
useContext,
|
|
34
|
-
} from "solid-js"
|
|
25
|
+
import { type Accessor, createMemo, createSignal, onCleanup, useContext } from "solid-js"
|
|
35
26
|
import { PageContext } from "./page-visibility.ts"
|
|
27
|
+
import { RenderPropsContext, SearchContext } from "./router-context.ts"
|
|
36
28
|
|
|
37
29
|
export { href, rawHref } from "@nifrajs/web/client"
|
|
38
30
|
export { onPageHide, onPageShow, usePageVisibility } from "./page-visibility.ts"
|
|
31
|
+
export type { RouteSlotController, RouteSlotProps } from "./route-slot.tsx"
|
|
32
|
+
export { RouteSlot, useRouteSlot } from "./route-slot.tsx"
|
|
39
33
|
export type { Blocker, BlockerFunction, BlockerState, NavigateFunction, UIMatch }
|
|
34
|
+
export { RenderPropsContext, SearchContext }
|
|
40
35
|
|
|
41
36
|
// Frozen empty search + a stable accessor for a `useSearch` used outside a nifra route tree.
|
|
42
37
|
const EMPTY_SEARCH: Readonly<Record<string, unknown>> = Object.freeze({})
|
|
@@ -49,22 +44,6 @@ const EMPTY_SEARCH_ACCESSOR: Accessor<Record<string, unknown>> = () => EMPTY_SEA
|
|
|
49
44
|
* code under Bun provides; route modules through Vite's SSR runner read), and Solid matches provider
|
|
50
45
|
* to reader by context object identity - two `createContext` results make `useSearch` SSR-render its
|
|
51
46
|
* empty default in dev. */
|
|
52
|
-
const SEARCH_CONTEXT_SLOT = Symbol.for("nifra.web-solid.search-context")
|
|
53
|
-
const searchContextSlot = globalThis as {
|
|
54
|
-
[SEARCH_CONTEXT_SLOT]?: Context<Accessor<Record<string, unknown>> | undefined>
|
|
55
|
-
}
|
|
56
|
-
export const SearchContext =
|
|
57
|
-
searchContextSlot[SEARCH_CONTEXT_SLOT] ?? createContext<Accessor<Record<string, unknown>>>()
|
|
58
|
-
searchContextSlot[SEARCH_CONTEXT_SLOT] = SearchContext
|
|
59
|
-
|
|
60
|
-
/** The props `compose` rendered the chain with - getters over the router snapshot on the client - which
|
|
61
|
-
* {@link useMatches} reads. A `globalThis` singleton for the same reason as {@link SearchContext}. */
|
|
62
|
-
const PROPS_CONTEXT_SLOT = Symbol.for("nifra.web-solid.props-context")
|
|
63
|
-
const propsContextSlot = globalThis as { [PROPS_CONTEXT_SLOT]?: Context<RenderProps | undefined> }
|
|
64
|
-
export const RenderPropsContext =
|
|
65
|
-
propsContextSlot[PROPS_CONTEXT_SLOT] ?? createContext<RenderProps>()
|
|
66
|
-
propsContextSlot[PROPS_CONTEXT_SLOT] = RenderPropsContext
|
|
67
|
-
|
|
68
47
|
const NO_MATCHES: readonly UIMatch[] = Object.freeze([])
|
|
69
48
|
|
|
70
49
|
/**
|