@real-router/solid 0.14.2 → 0.14.3

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.
Files changed (41) hide show
  1. package/dist/cjs/index.js +0 -0
  2. package/dist/esm/index.mjs +0 -0
  3. package/dist/types/dom-utils/link-utils.d.ts.map +1 -1
  4. package/dist/types/dom-utils/scroll-spy.d.ts.map +1 -1
  5. package/package.json +7 -8
  6. package/src/RouterProvider.tsx +0 -112
  7. package/src/components/Await.tsx +0 -56
  8. package/src/components/ClientOnly.tsx +0 -20
  9. package/src/components/HttpStatusCode.tsx +0 -65
  10. package/src/components/HttpStatusProvider.tsx +0 -21
  11. package/src/components/Link.tsx +0 -140
  12. package/src/components/RouteView/RouteView.tsx +0 -59
  13. package/src/components/RouteView/components.tsx +0 -85
  14. package/src/components/RouteView/helpers.tsx +0 -0
  15. package/src/components/RouteView/index.ts +0 -8
  16. package/src/components/RouteView/types.ts +0 -24
  17. package/src/components/RouterErrorBoundary.tsx +0 -45
  18. package/src/components/ServerOnly.tsx +0 -20
  19. package/src/components/Streamed.tsx +0 -23
  20. package/src/constants.ts +0 -27
  21. package/src/context.ts +0 -35
  22. package/src/createSignalFromSource.ts +0 -71
  23. package/src/createStoreFromSource.ts +0 -65
  24. package/src/directives/link.tsx +0 -111
  25. package/src/directives.d.ts +0 -10
  26. package/src/hooks/useDeferred.tsx +0 -36
  27. package/src/hooks/useNavigator.tsx +0 -6
  28. package/src/hooks/useRoute.tsx +0 -27
  29. package/src/hooks/useRouteEnter.tsx +0 -121
  30. package/src/hooks/useRouteExit.tsx +0 -123
  31. package/src/hooks/useRouteNode.tsx +0 -13
  32. package/src/hooks/useRouteNodeStore.tsx +0 -12
  33. package/src/hooks/useRouteStore.tsx +0 -12
  34. package/src/hooks/useRouteUtils.tsx +0 -50
  35. package/src/hooks/useRouter.tsx +0 -6
  36. package/src/hooks/useRouterTransition.tsx +0 -14
  37. package/src/index.tsx +0 -66
  38. package/src/ssr.tsx +0 -39
  39. package/src/types.ts +0 -28
  40. package/src/utils/createHttpStatusSink.ts +0 -31
  41. package/src/utils/createMountedSignal.ts +0 -26
@@ -1,123 +0,0 @@
1
- import { onCleanup } from "solid-js";
2
-
3
- import { useRouter } from "./useRouter";
4
-
5
- import type { State } from "@real-router/core";
6
-
7
- export interface RouteExitContext {
8
- /** The route being left. */
9
- route: State;
10
- /** The route being navigated to. */
11
- nextRoute: State;
12
- /**
13
- * AbortSignal that fires when this navigation is superseded by a later
14
- * one (rapid clicks). Already filtered: when the handler runs,
15
- * `signal.aborted` is guaranteed to be `false`. Use
16
- * `signal.addEventListener("abort", cleanup, { once: true })` for
17
- * cleanup that must run on cancellation.
18
- */
19
- signal: AbortSignal;
20
- }
21
-
22
- export interface UseRouteExitOptions {
23
- /**
24
- * Skip the handler when `route.name === nextRoute.name`
25
- * (sort/filter/query-only navigations on the same route). Default:
26
- * `true`.
27
- */
28
- skipSameRoute?: boolean;
29
- }
30
-
31
- export type RouteExitHandler = (
32
- context: RouteExitContext,
33
- ) => void | Promise<void>;
34
-
35
- /**
36
- * Subscribe to the router's leave-window with the universal guards baked
37
- * in. Wraps `router.subscribeLeave` so consumers don't repeat the same
38
- * boilerplate every time:
39
- *
40
- * - **Reentrant abort pre-check**: if `signal.aborted` is already `true`
41
- * when the handler would run (rapid navigation superseded a slower
42
- * one), the handler is skipped entirely. `signal.addEventListener(
43
- * "abort", ...)` does not fire retroactively, so without this guard
44
- * downstream cleanup would never trigger.
45
- * - **Same-route skip**: by default, `route.name === nextRoute.name`
46
- * short-circuits the handler — query-only navigations (sort, filter,
47
- * pagination) skip the work. Opt out with `skipSameRoute: false`.
48
- *
49
- * Returns nothing — the subscription's lifecycle is bound to the
50
- * component via `onCleanup`.
51
- *
52
- * If the handler returns a Promise, the router blocks on it. If the
53
- * Promise resolves, navigation proceeds. If it rejects, the router emits
54
- * `TRANSITION_CANCELLED`.
55
- *
56
- * **Handler reactivity (Solid)**: Solid components run **once** at mount;
57
- * `handler` is captured in closure at the call site. If you need
58
- * different behavior across renders, derive it from a signal inside the
59
- * handler body — do not rely on swapping the handler reference.
60
- *
61
- * @example Animation
62
- * ```tsx
63
- * let ref: HTMLDivElement | undefined;
64
- *
65
- * useRouteExit(async ({ signal }) => {
66
- * const el = ref;
67
- * if (!el) return;
68
- * el.classList.add("fade-out");
69
- * const cleanup = () => el.classList.remove("fade-out");
70
- * signal.addEventListener("abort", cleanup, { once: true });
71
- * try {
72
- * el.getBoundingClientRect(); // style flush
73
- * await Promise.allSettled(el.getAnimations().map((a) => a.finished));
74
- * } finally {
75
- * cleanup();
76
- * }
77
- * });
78
- * ```
79
- *
80
- * @example Auto-save form draft
81
- * ```tsx
82
- * useRouteExit(async ({ signal }) => {
83
- * if (formState.dirty) await api.saveDraft(formState, { signal });
84
- * });
85
- * ```
86
- *
87
- * @example Reading rich transition metadata via `nextRoute.transition`
88
- * ```tsx
89
- * useRouteExit(({ route, nextRoute }) => {
90
- * if (nextRoute.transition.segments.deactivated.includes("products")) {
91
- * productCache.clear();
92
- * }
93
- * if (nextRoute.transition.redirected) {
94
- * return;
95
- * }
96
- * });
97
- * ```
98
- */
99
- export function useRouteExit(
100
- handler: RouteExitHandler,
101
- options?: UseRouteExitOptions,
102
- ): void {
103
- const router = useRouter();
104
- const skipSameRoute = options?.skipSameRoute ?? true;
105
-
106
- const off = router.subscribeLeave(({ route, nextRoute, signal }) => {
107
- if (skipSameRoute && route.name === nextRoute.name) {
108
- return;
109
- }
110
-
111
- // Reentrant abort: signal is already aborted when listener fires
112
- // (e.g. a newer navigate superseded this one before subscribeLeave
113
- // even ran). addEventListener("abort", ...) does not fire
114
- // retroactively, so we skip the handler entirely.
115
- if (signal.aborted) {
116
- return;
117
- }
118
-
119
- return handler({ route, nextRoute, signal });
120
- });
121
-
122
- onCleanup(off);
123
- }
@@ -1,13 +0,0 @@
1
- import { createRouteNodeSource } from "@real-router/sources";
2
-
3
- import { createSignalFromSource } from "../createSignalFromSource";
4
- import { useRouter } from "./useRouter";
5
-
6
- import type { RouteState } from "../types";
7
- import type { Accessor } from "solid-js";
8
-
9
- export function useRouteNode(nodeName: string): Accessor<RouteState> {
10
- const router = useRouter();
11
-
12
- return createSignalFromSource(createRouteNodeSource(router, nodeName));
13
- }
@@ -1,12 +0,0 @@
1
- import { createRouteNodeSource } from "@real-router/sources";
2
-
3
- import { createStoreFromSource } from "../createStoreFromSource";
4
- import { useRouter } from "./useRouter";
5
-
6
- import type { RouteState } from "../types";
7
-
8
- export function useRouteNodeStore(nodeName: string): RouteState {
9
- const router = useRouter();
10
-
11
- return createStoreFromSource(createRouteNodeSource(router, nodeName));
12
- }
@@ -1,12 +0,0 @@
1
- import { createRouteSource } from "@real-router/sources";
2
-
3
- import { createStoreFromSource } from "../createStoreFromSource";
4
- import { useRouter } from "./useRouter";
5
-
6
- import type { RouteState } from "../types";
7
-
8
- export function useRouteStore(): RouteState {
9
- const router = useRouter();
10
-
11
- return createStoreFromSource(createRouteSource(router));
12
- }
@@ -1,50 +0,0 @@
1
- import { getPluginApi } from "@real-router/core/api";
2
- import { getRouteUtils } from "@real-router/route-utils";
3
-
4
- import { useRouter } from "./useRouter";
5
-
6
- import type { Router } from "@real-router/core";
7
- import type { RouteUtils } from "@real-router/route-utils";
8
-
9
- // §8.1 audit fix (MED) — cache the `RouteUtils` per (router, tree) so N
10
- // components calling `useRouteUtils()` against the same router share ONE
11
- // chain through `getPluginApi(router).getTree()` + `getRouteUtils(tree)`.
12
- //
13
- // Why two-level (router + tree) and not just router:
14
- // `getRouteUtils` is WeakMap-cached by tree root, BUT a RouteUtils
15
- // instance is built FROM the tree at construction time — its internal
16
- // `getChain`/`getSiblings` caches are pre-computed Object.freeze'd arrays
17
- // (see `@real-router/route-utils` CLAUDE.md). If the router replaces its
18
- // tree (e.g. `routesApi.replace([...])`), the old RouteUtils is stale.
19
- // Caching only by router would serve the stale instance.
20
- //
21
- // Storing `{ tree, utils }` per router lets us detect tree replacement and
22
- // recompute. In the steady state (no tree mutation), this is a cheap
23
- // reference compare; under tree replacement, the cache self-heals on the
24
- // next call.
25
- //
26
- // WeakMap keys on the router — entries are released automatically when the
27
- // router is garbage-collected.
28
- interface CachedEntry {
29
- tree: unknown;
30
- utils: RouteUtils;
31
- }
32
-
33
- const routeUtilsCache = new WeakMap<Router, CachedEntry>();
34
-
35
- export const useRouteUtils = (): RouteUtils => {
36
- const router = useRouter();
37
- const tree = getPluginApi(router).getTree();
38
-
39
- const cached = routeUtilsCache.get(router);
40
-
41
- if (cached?.tree === tree) {
42
- return cached.utils;
43
- }
44
-
45
- const utils = getRouteUtils(tree);
46
-
47
- routeUtilsCache.set(router, { tree, utils });
48
-
49
- return utils;
50
- };
@@ -1,6 +0,0 @@
1
- import { useRequiredRouterContext } from "../context";
2
-
3
- import type { Router } from "@real-router/core";
4
-
5
- export const useRouter = (): Router =>
6
- useRequiredRouterContext("useRouter").router;
@@ -1,14 +0,0 @@
1
- import { getTransitionSource } from "@real-router/sources";
2
-
3
- import { createSignalFromSource } from "../createSignalFromSource";
4
- import { useRouter } from "./useRouter";
5
-
6
- import type { RouterTransitionSnapshot } from "@real-router/sources";
7
- import type { Accessor } from "solid-js";
8
-
9
- export function useRouterTransition(): Accessor<RouterTransitionSnapshot> {
10
- const router = useRouter();
11
- const source = getTransitionSource(router);
12
-
13
- return createSignalFromSource(source);
14
- }
package/src/index.tsx DELETED
@@ -1,66 +0,0 @@
1
- export { RouteView } from "./components/RouteView";
2
-
3
- export { Link } from "./components/Link";
4
-
5
- export { RouterErrorBoundary } from "./components/RouterErrorBoundary";
6
-
7
- export { link } from "./directives/link";
8
-
9
- export { useRouter } from "./hooks/useRouter";
10
-
11
- export { useNavigator } from "./hooks/useNavigator";
12
-
13
- export { useRouteUtils } from "./hooks/useRouteUtils";
14
-
15
- export { useRoute } from "./hooks/useRoute";
16
-
17
- export { useRouteNode } from "./hooks/useRouteNode";
18
-
19
- export { useRouteStore } from "./hooks/useRouteStore";
20
-
21
- export { useRouteNodeStore } from "./hooks/useRouteNodeStore";
22
-
23
- export { useRouterTransition } from "./hooks/useRouterTransition";
24
-
25
- export { useRouteExit } from "./hooks/useRouteExit";
26
-
27
- export { useRouteEnter } from "./hooks/useRouteEnter";
28
-
29
- export { RouterProvider } from "./RouterProvider";
30
-
31
- export { RouterContext, RouteContext } from "./context";
32
-
33
- export type { RouterContextValue } from "./context";
34
-
35
- export { createSignalFromSource } from "./createSignalFromSource";
36
-
37
- export { createStoreFromSource } from "./createStoreFromSource";
38
-
39
- export type { LinkProps, RouteState } from "./types";
40
-
41
- export type { RouterErrorBoundaryProps } from "./components/RouterErrorBoundary";
42
-
43
- export type { LinkDirectiveOptions } from "./directives/link";
44
-
45
- export type {
46
- RouteViewProps,
47
- RouteViewMatchProps,
48
- RouteViewSelfProps,
49
- RouteViewNotFoundProps,
50
- } from "./components/RouteView";
51
-
52
- export type {
53
- RouteExitContext,
54
- RouteExitHandler,
55
- UseRouteExitOptions,
56
- } from "./hooks/useRouteExit";
57
-
58
- export type {
59
- RouteEnterContext,
60
- RouteEnterHandler,
61
- UseRouteEnterOptions,
62
- } from "./hooks/useRouteEnter";
63
-
64
- export type { Navigator } from "@real-router/core";
65
-
66
- export type { RouterTransitionSnapshot } from "@real-router/sources";
package/src/ssr.tsx DELETED
@@ -1,39 +0,0 @@
1
- // SSR-feature entry — Solid 1.7+
2
- //
3
- // Server-side and SSR-aware components/hooks. Mirror of `@real-router/react/ssr`
4
- // — same exports, Solid-native idioms (Accessor returns, createResource-backed
5
- // Await, native Suspense for Streamed).
6
-
7
- // Components
8
- export { ClientOnly } from "./components/ClientOnly";
9
-
10
- export { ServerOnly } from "./components/ServerOnly";
11
-
12
- export { Await } from "./components/Await";
13
-
14
- export { Streamed } from "./components/Streamed";
15
-
16
- export { HttpStatusCode } from "./components/HttpStatusCode";
17
-
18
- export { HttpStatusProvider } from "./components/HttpStatusProvider";
19
-
20
- // Hooks
21
- export { useDeferred } from "./hooks/useDeferred";
22
-
23
- // Utilities
24
- export { createHttpStatusSink } from "./utils/createHttpStatusSink";
25
-
26
- // Types
27
- export type { ClientOnlyProps } from "./components/ClientOnly";
28
-
29
- export type { ServerOnlyProps } from "./components/ServerOnly";
30
-
31
- export type { AwaitProps } from "./components/Await";
32
-
33
- export type { StreamedProps } from "./components/Streamed";
34
-
35
- export type { HttpStatusCodeProps } from "./components/HttpStatusCode";
36
-
37
- export type { HttpStatusProviderProps } from "./components/HttpStatusProvider";
38
-
39
- export type { HttpStatusSink } from "./utils/createHttpStatusSink";
package/src/types.ts DELETED
@@ -1,28 +0,0 @@
1
- import type { NavigationOptions, Params, State } from "@real-router/core";
2
- import type { JSX } from "solid-js";
3
-
4
- export interface RouteState<P extends Params = Params> {
5
- route: State<P> | undefined;
6
- previousRoute?: State | undefined;
7
- }
8
-
9
- export interface LinkProps<P extends Params = Params> extends Omit<
10
- JSX.HTMLAttributes<HTMLAnchorElement>,
11
- "onClick"
12
- > {
13
- routeName: string;
14
- routeParams?: P;
15
- routeOptions?: NavigationOptions;
16
- activeClassName?: string;
17
- activeStrict?: boolean;
18
- ignoreQueryParams?: boolean;
19
- /**
20
- * URL fragment (decoded form, no leading "#") (#532).
21
- * - omitted/`undefined` → preserve current fragment on same-route navigation
22
- * - `""` → clear fragment
23
- * - non-empty → set fragment
24
- */
25
- hash?: string;
26
- target?: string;
27
- onClick?: (evt: MouseEvent) => void;
28
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Render-scoped HTTP status sink. Created per request on the server, passed to
3
- * `<HttpStatusProvider sink={...}>`, and read after `renderToString` /
4
- * `renderToStream` to apply the value to the HTTP response.
5
- *
6
- * Last write wins: if the rendered tree mounts more than one
7
- * `<HttpStatusCode />`, the value reflects the last component that ran during
8
- * the render pass.
9
- *
10
- * No-op on the client — `<HttpStatusCode />` reads the optional context and
11
- * skips the write when no provider is mounted, so the same component tree can
12
- * be hydrated without changing behaviour.
13
- *
14
- * Constraints:
15
- * - **Per-request only.** Don't share a sink across requests; the rendered
16
- * tree mutates `code` in place. Module-level singletons leak status
17
- * between concurrent requests.
18
- * - **Don't `Object.freeze` the sink.** The component writes to `.code`;
19
- * freezing makes the assignment throw under ESM strict mode.
20
- * - **Hydration symmetry:** mount `<HttpStatusProvider>` on both server and
21
- * client (with a throwaway client sink). Solid emits `data-hk` markers
22
- * per component boundary; an extra provider on one side desyncs the
23
- * counter and breaks the hydration walker.
24
- */
25
- export interface HttpStatusSink {
26
- code: number | undefined;
27
- }
28
-
29
- export function createHttpStatusSink(): HttpStatusSink {
30
- return { code: undefined };
31
- }
@@ -1,26 +0,0 @@
1
- import { createSignal, onMount } from "solid-js";
2
-
3
- import type { Accessor } from "solid-js";
4
-
5
- /**
6
- * Returns a boolean accessor that is `false` during initial render (SSR
7
- * and the first client paint) and flips to `true` once the component
8
- * has mounted in the browser.
9
- *
10
- * Solid guarantees that `onMount` does NOT fire during `renderToString` /
11
- * `renderToStream`, so the accessor stays `false` server-side — this is
12
- * the building block for SSR boundary components (`<ClientOnly>` /
13
- * `<ServerOnly>`).
14
- *
15
- * Consolidates the identical `createSignal(false) + onMount(setMounted)`
16
- * pattern across the two boundary components (§8a Q15).
17
- */
18
- export function createMountedSignal(): Accessor<boolean> {
19
- const [mounted, setMounted] = createSignal(false);
20
-
21
- onMount(() => {
22
- setMounted(true);
23
- });
24
-
25
- return mounted;
26
- }