@real-router/svelte 0.2.6 → 0.2.8

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.
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getNavigator } from "@real-router/core";
3
3
  import { createRouteSource } from "@real-router/sources";
4
- import { createRouteAnnouncer } from "dom-utils";
4
+ import { createRouteAnnouncer } from "./dom-utils";
5
5
  import { setContext } from "svelte";
6
6
 
7
7
  import { createReactiveSource } from "./createReactiveSource.svelte";
@@ -1,6 +1,6 @@
1
1
  import { getContext } from "svelte";
2
2
  import { ROUTER_KEY } from "../context";
3
- import { shouldNavigate, applyLinkA11y } from "dom-utils";
3
+ import { shouldNavigate, applyLinkA11y } from "../dom-utils";
4
4
  /**
5
5
  * Factory function that captures router context during component initialization.
6
6
  * Must be called during component init (not inside event handlers or effects).
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { useIsActiveRoute } from "../composables/useIsActiveRoute.svelte";
3
3
  import { useRouter } from "../composables/useRouter.svelte";
4
- import { shouldNavigate, buildHref, buildActiveClassName } from "dom-utils";
4
+ import { shouldNavigate, buildHref, buildActiveClassName } from "../dom-utils";
5
5
 
6
6
  import type { NavigationOptions, Params } from "@real-router/core";
7
7
  import type { Snippet } from "svelte";
@@ -0,0 +1,3 @@
1
+ export { createRouteAnnouncer } from "./route-announcer";
2
+ export { shouldNavigate, buildHref, buildActiveClassName, applyLinkA11y, } from "./link-utils";
3
+ export type { RouteAnnouncerOptions } from "./route-announcer";
@@ -0,0 +1,2 @@
1
+ export { createRouteAnnouncer } from "./route-announcer";
2
+ export { shouldNavigate, buildHref, buildActiveClassName, applyLinkA11y, } from "./link-utils";
@@ -0,0 +1,5 @@
1
+ import type { Router, Params } from "@real-router/core";
2
+ export declare function shouldNavigate(evt: MouseEvent): boolean;
3
+ export declare function buildHref(router: Router, routeName: string, routeParams: Params): string | undefined;
4
+ export declare function buildActiveClassName(isActive: boolean, activeClassName: string | undefined, baseClassName: string | undefined): string | undefined;
5
+ export declare function applyLinkA11y(element: HTMLElement): void;
@@ -0,0 +1,41 @@
1
+ export function shouldNavigate(evt) {
2
+ return (evt.button === 0 &&
3
+ !evt.metaKey &&
4
+ !evt.altKey &&
5
+ !evt.ctrlKey &&
6
+ !evt.shiftKey);
7
+ }
8
+ // Lives in dom-utils (not core/utils) because buildUrl is injected by browser-plugin via extendRouter()
9
+ export function buildHref(router, routeName, routeParams) {
10
+ try {
11
+ const buildUrl = router.buildUrl;
12
+ if (buildUrl) {
13
+ return buildUrl(routeName, routeParams);
14
+ }
15
+ return router.buildPath(routeName, routeParams);
16
+ }
17
+ catch {
18
+ console.error(`[real-router] Route "${routeName}" is not defined. The element will render without an href attribute.`);
19
+ return undefined;
20
+ }
21
+ }
22
+ export function buildActiveClassName(isActive, activeClassName, baseClassName) {
23
+ if (isActive && activeClassName) {
24
+ return baseClassName
25
+ ? `${baseClassName} ${activeClassName}`.trim()
26
+ : activeClassName;
27
+ }
28
+ return baseClassName ?? undefined;
29
+ }
30
+ export function applyLinkA11y(element) {
31
+ if (element instanceof HTMLAnchorElement ||
32
+ element instanceof HTMLButtonElement) {
33
+ return;
34
+ }
35
+ if (!element.getAttribute("role")) {
36
+ element.setAttribute("role", "link");
37
+ }
38
+ if (!element.getAttribute("tabindex")) {
39
+ element.setAttribute("tabindex", "0");
40
+ }
41
+ }
@@ -0,0 +1,8 @@
1
+ import type { Router, State } from "@real-router/core";
2
+ export interface RouteAnnouncerOptions {
3
+ prefix?: string;
4
+ getAnnouncementText?: (route: State) => string;
5
+ }
6
+ export declare function createRouteAnnouncer(router: Router, options?: RouteAnnouncerOptions): {
7
+ destroy: () => void;
8
+ };
@@ -0,0 +1,89 @@
1
+ const CLEAR_DELAY = 7000;
2
+ const SAFARI_READY_DELAY = 100;
3
+ const ANNOUNCER_ATTR = "data-real-router-announcer";
4
+ const INTERNAL_ROUTE_PREFIX = "@@";
5
+ const VISUALLY_HIDDEN = "position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0";
6
+ export function createRouteAnnouncer(router, options) {
7
+ const prefix = options?.prefix ?? "Navigated to ";
8
+ const getCustomText = options?.getAnnouncementText;
9
+ let isInitialNavigation = true;
10
+ let isReady = false;
11
+ let isDestroyed = false;
12
+ let lastAnnouncedText = "";
13
+ let clearTimeoutId;
14
+ const announcer = getOrCreateAnnouncer();
15
+ const safariTimeoutId = setTimeout(() => {
16
+ isReady = true;
17
+ }, SAFARI_READY_DELAY);
18
+ const unsubscribe = router.subscribe(({ route }) => {
19
+ if (isInitialNavigation) {
20
+ isInitialNavigation = false;
21
+ return;
22
+ }
23
+ requestAnimationFrame(() => {
24
+ requestAnimationFrame(() => {
25
+ if (isDestroyed) {
26
+ return;
27
+ }
28
+ const text = resolveText(route, prefix, getCustomText);
29
+ if (text && text !== lastAnnouncedText && isReady) {
30
+ lastAnnouncedText = text;
31
+ clearTimeout(clearTimeoutId);
32
+ announcer.textContent = text;
33
+ clearTimeoutId = setTimeout(() => {
34
+ announcer.textContent = "";
35
+ lastAnnouncedText = "";
36
+ }, CLEAR_DELAY);
37
+ manageFocus();
38
+ }
39
+ });
40
+ });
41
+ });
42
+ return {
43
+ destroy() {
44
+ isDestroyed = true;
45
+ unsubscribe();
46
+ clearTimeout(clearTimeoutId);
47
+ clearTimeout(safariTimeoutId);
48
+ removeAnnouncer();
49
+ },
50
+ };
51
+ }
52
+ function getOrCreateAnnouncer() {
53
+ const existing = document.querySelector(`[${ANNOUNCER_ATTR}]`);
54
+ if (existing) {
55
+ return existing;
56
+ }
57
+ const element = document.createElement("div");
58
+ element.setAttribute("style", VISUALLY_HIDDEN);
59
+ element.setAttribute("aria-live", "assertive");
60
+ element.setAttribute("aria-atomic", "true");
61
+ element.setAttribute(ANNOUNCER_ATTR, "");
62
+ document.body.prepend(element);
63
+ return element;
64
+ }
65
+ function removeAnnouncer() {
66
+ document.querySelector(`[${ANNOUNCER_ATTR}]`)?.remove();
67
+ }
68
+ function resolveText(route, prefix, getCustomText) {
69
+ if (getCustomText) {
70
+ return getCustomText(route);
71
+ }
72
+ const h1 = document.querySelector("h1");
73
+ const h1Text = h1?.textContent.trim() ?? "";
74
+ const routeName = route.name.startsWith(INTERNAL_ROUTE_PREFIX)
75
+ ? ""
76
+ : route.name;
77
+ const rawText = h1Text || document.title || routeName || globalThis.location.pathname;
78
+ return `${prefix}${rawText}`;
79
+ }
80
+ function manageFocus() {
81
+ const h1 = document.querySelector("h1");
82
+ if (!h1) {
83
+ return;
84
+ }
85
+ if (!h1.hasAttribute("tabindex")) {
86
+ h1.setAttribute("tabindex", "-1");
87
+ }
88
+ h1.focus({ preventScroll: true });
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/svelte",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "description": "Svelte 5 integration for Real-Router",
6
6
  "svelte": "./dist/index.js",
@@ -13,8 +13,7 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
- "dist",
17
- "src"
16
+ "dist"
18
17
  ],
19
18
  "homepage": "https://github.com/greydragon888/real-router",
20
19
  "repository": {
@@ -44,10 +43,9 @@
44
43
  "license": "MIT",
45
44
  "sideEffects": false,
46
45
  "dependencies": {
47
- "@real-router/core": "^0.45.0",
48
- "@real-router/route-utils": "^0.1.11",
49
- "@real-router/sources": "^0.4.1",
50
- "dom-utils": "^0.2.7"
46
+ "@real-router/core": "^0.45.1",
47
+ "@real-router/route-utils": "^0.1.12",
48
+ "@real-router/sources": "^0.4.2"
51
49
  },
52
50
  "devDependencies": {
53
51
  "@sveltejs/package": "2.5.7",
@@ -59,7 +57,8 @@
59
57
  "svelte": "5.54.0",
60
58
  "svelte-check": "4.4.5",
61
59
  "svelte-eslint-parser": "1.6.0",
62
- "@real-router/browser-plugin": "^0.11.4"
60
+ "@real-router/browser-plugin": "^0.11.5",
61
+ "dom-utils": "^0.2.7"
63
62
  },
64
63
  "peerDependencies": {
65
64
  "svelte": ">=5.7.0"
@@ -1,51 +0,0 @@
1
- <script lang="ts">
2
- import { getNavigator } from "@real-router/core";
3
- import { createRouteSource } from "@real-router/sources";
4
- import { createRouteAnnouncer } from "dom-utils";
5
- import { setContext } from "svelte";
6
-
7
- import { createReactiveSource } from "./createReactiveSource.svelte";
8
- import { NAVIGATOR_KEY, ROUTE_KEY, ROUTER_KEY } from "./context";
9
-
10
- import type { Router } from "@real-router/core";
11
- import type { Snippet } from "svelte";
12
-
13
- let {
14
- router,
15
- children,
16
- announceNavigation,
17
- }: { router: Router; children: Snippet; announceNavigation?: boolean } =
18
- $props();
19
-
20
- $effect(() => {
21
- if (!announceNavigation) return;
22
- const announcer = createRouteAnnouncer(router);
23
- return () => announcer.destroy();
24
- });
25
-
26
- const navigator = getNavigator(router);
27
- const source = createRouteSource(router);
28
- const reactive = createReactiveSource(source);
29
-
30
- setContext(ROUTER_KEY, router);
31
- setContext(NAVIGATOR_KEY, navigator);
32
- setContext(ROUTE_KEY, {
33
- navigator,
34
- get route() {
35
- return {
36
- get current() {
37
- return reactive.current.route;
38
- },
39
- };
40
- },
41
- get previousRoute() {
42
- return {
43
- get current() {
44
- return reactive.current.previousRoute;
45
- },
46
- };
47
- },
48
- });
49
- </script>
50
-
51
- {@render children()}
@@ -1,90 +0,0 @@
1
- import { getContext } from "svelte";
2
- import type { ActionReturn } from "svelte/action";
3
- import type { Router, Params, NavigationOptions } from "@real-router/core";
4
- import { ROUTER_KEY } from "../context";
5
- import { shouldNavigate, applyLinkA11y } from "dom-utils";
6
-
7
- export interface LinkActionParams {
8
- name: string;
9
- params?: Params;
10
- options?: NavigationOptions;
11
- }
12
-
13
- /**
14
- * Factory function that captures router context during component initialization.
15
- * Must be called during component init (not inside event handlers or effects).
16
- *
17
- * @returns Action function for use with `use:` directive
18
- * @throws Error if called outside RouterProvider
19
- *
20
- * @example
21
- * ```svelte
22
- * <script>
23
- * import { createLinkAction } from '@real-router/svelte';
24
- * const link = createLinkAction();
25
- * </script>
26
- *
27
- * <button use:link={{ name: 'home' }}>Home</button>
28
- * <a use:link={{ name: 'users', params: { id: '123' } }}>User Profile</a>
29
- * ```
30
- */
31
- export function createLinkAction(): (
32
- node: HTMLElement,
33
- params: LinkActionParams,
34
- ) => ActionReturn<LinkActionParams> {
35
- const router = getContext<Router | undefined>(ROUTER_KEY);
36
-
37
- if (!router) {
38
- throw new Error("createLinkAction must be called inside a RouterProvider");
39
- }
40
-
41
- return function link(
42
- node: HTMLElement,
43
- params: LinkActionParams,
44
- ): ActionReturn<LinkActionParams> {
45
- let currentParams = params;
46
-
47
- applyLinkA11y(node);
48
-
49
- function handleClick(evt: MouseEvent) {
50
- if (!shouldNavigate(evt)) return;
51
- evt.preventDefault();
52
- // router is guaranteed to exist due to check in factory
53
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
54
- router!
55
- .navigate(
56
- currentParams.name,
57
- currentParams.params ?? {},
58
- currentParams.options ?? {},
59
- )
60
- .catch(() => {});
61
- }
62
-
63
- function handleKeyDown(evt: KeyboardEvent) {
64
- if (evt.key === "Enter" && !(node instanceof HTMLButtonElement)) {
65
- // router is guaranteed to exist due to check in factory
66
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
67
- router!
68
- .navigate(
69
- currentParams.name,
70
- currentParams.params ?? {},
71
- currentParams.options ?? {},
72
- )
73
- .catch(() => {});
74
- }
75
- }
76
-
77
- node.addEventListener("click", handleClick);
78
- node.addEventListener("keydown", handleKeyDown);
79
-
80
- return {
81
- update(newParams: LinkActionParams) {
82
- currentParams = newParams;
83
- },
84
- destroy() {
85
- node.removeEventListener("click", handleClick);
86
- node.removeEventListener("keydown", handleKeyDown);
87
- },
88
- };
89
- };
90
- }
@@ -1,47 +0,0 @@
1
- <script lang="ts">
2
- import type { Component } from "svelte";
3
-
4
- let {
5
- loader,
6
- fallback,
7
- }: {
8
- loader: () => Promise<{ default: Component }>;
9
- fallback?: Component | undefined;
10
- } = $props();
11
-
12
- let LoadedComponent = $state<Component | null>(null);
13
- let error = $state<Error | null>(null);
14
- let loading = $state(true);
15
-
16
- $effect(() => {
17
- loading = true;
18
- error = null;
19
- LoadedComponent = null;
20
- let active = true;
21
-
22
- loader()
23
- .then((module) => {
24
- if (!active) return;
25
- LoadedComponent = module.default;
26
- loading = false;
27
- })
28
- .catch((err) => {
29
- if (!active) return;
30
- error = err;
31
- loading = false;
32
- });
33
-
34
- return () => {
35
- active = false;
36
- };
37
- });
38
- </script>
39
-
40
- {#if loading && fallback}
41
- {@const Fallback = fallback}
42
- <Fallback />
43
- {:else if error}
44
- <p>Error loading component: {error.message}</p>
45
- {:else if LoadedComponent}
46
- <LoadedComponent />
47
- {/if}
@@ -1,69 +0,0 @@
1
- <script lang="ts">
2
- import { useIsActiveRoute } from "../composables/useIsActiveRoute.svelte";
3
- import { useRouter } from "../composables/useRouter.svelte";
4
- import { shouldNavigate, buildHref, buildActiveClassName } from "dom-utils";
5
-
6
- import type { NavigationOptions, Params } from "@real-router/core";
7
- import type { Snippet } from "svelte";
8
-
9
- let {
10
- routeName,
11
- routeParams = {} as Params,
12
- routeOptions = {} as NavigationOptions,
13
- class: className = undefined,
14
- activeClassName = "active",
15
- activeStrict = false,
16
- ignoreQueryParams = true,
17
- target = undefined,
18
- children = undefined,
19
- onclick: userOnClick = undefined,
20
- ...restProps
21
- }: {
22
- routeName: string;
23
- routeParams?: Params;
24
- routeOptions?: NavigationOptions;
25
- class?: string;
26
- activeClassName?: string;
27
- activeStrict?: boolean;
28
- ignoreQueryParams?: boolean;
29
- target?: string;
30
- children?: Snippet;
31
- onclick?: (evt: MouseEvent) => void;
32
- [key: string]: unknown;
33
- } = $props();
34
-
35
- const router = useRouter();
36
- const activeState = useIsActiveRoute(
37
- routeName,
38
- routeParams,
39
- activeStrict,
40
- ignoreQueryParams,
41
- );
42
-
43
- const href = $derived(buildHref(router, routeName, routeParams));
44
-
45
- const finalClassName = $derived(
46
- buildActiveClassName(activeState.current, activeClassName, className),
47
- );
48
-
49
- function handleClick(evt: MouseEvent) {
50
- if (userOnClick) {
51
- userOnClick(evt);
52
-
53
- if (evt.defaultPrevented) {
54
- return;
55
- }
56
- }
57
-
58
- if (!shouldNavigate(evt) || target === "_blank") {
59
- return;
60
- }
61
-
62
- evt.preventDefault();
63
- router.navigate(routeName, routeParams, routeOptions).catch(() => {});
64
- }
65
- </script>
66
-
67
- <a {href} class={finalClassName} {target} onclick={handleClick} {...restProps}>
68
- {@render children?.()}
69
- </a>
@@ -1,46 +0,0 @@
1
- <script lang="ts">
2
- import { UNKNOWN_ROUTE } from "@real-router/core";
3
- import { startsWithSegment } from "@real-router/route-utils";
4
-
5
- import { useRouteNode } from "../composables/useRouteNode.svelte";
6
-
7
- import type { Snippet } from "svelte";
8
-
9
- let {
10
- nodeName,
11
- notFound,
12
- ...segmentSnippets
13
- }: {
14
- nodeName: string;
15
- notFound?: Snippet;
16
- [key: string]: Snippet | string | undefined;
17
- } = $props();
18
-
19
- const routeContext = useRouteNode(nodeName);
20
-
21
- function getActiveSegment(
22
- routeName: string,
23
- node: string,
24
- snippets: Record<string, unknown>,
25
- ): string {
26
- for (const segment of Object.keys(snippets)) {
27
- const fullSegmentName = node ? `${node}.${segment}` : segment;
28
-
29
- if (startsWithSegment(routeName, fullSegmentName)) {
30
- return segment;
31
- }
32
- }
33
-
34
- return "";
35
- }
36
- </script>
37
-
38
- {#if routeContext.route.current}
39
- {@const route = routeContext.route.current}
40
- {@const segment = getActiveSegment(route.name, nodeName, segmentSnippets)}
41
- {#if segment && segmentSnippets[segment]}
42
- {@render (segmentSnippets[segment] as Snippet)()}
43
- {:else if route.name === UNKNOWN_ROUTE && notFound}
44
- {@render notFound()}
45
- {/if}
46
- {/if}
@@ -1,47 +0,0 @@
1
- <script lang="ts">
2
- import { untrack } from "svelte";
3
-
4
- import { useRouterError } from "../composables/useRouterError.svelte";
5
-
6
- import type { RouterError, State } from "@real-router/core";
7
- import type { Snippet } from "svelte";
8
-
9
- interface Props {
10
- children: Snippet;
11
- fallback: Snippet<[RouterError, () => void]>;
12
- onError?: (
13
- error: RouterError,
14
- toRoute: State | null,
15
- fromRoute: State | null,
16
- ) => void;
17
- }
18
-
19
- let { children, fallback, onError }: Props = $props();
20
-
21
- const snapshot = useRouterError();
22
- let dismissedVersion = $state(-1);
23
-
24
- const visibleError = $derived(
25
- snapshot.current.version > dismissedVersion
26
- ? snapshot.current.error
27
- : null,
28
- );
29
-
30
- function resetError(): void {
31
- dismissedVersion = snapshot.current.version;
32
- }
33
-
34
- $effect(() => {
35
- if (snapshot.current.error) {
36
- const { error, toRoute, fromRoute } = snapshot.current;
37
- untrack(() => {
38
- onError?.(error, toRoute, fromRoute);
39
- });
40
- }
41
- });
42
- </script>
43
-
44
- {@render children?.()}
45
- {#if visibleError}
46
- {@render fallback(visibleError, resetError)}
47
- {/if}
@@ -1,22 +0,0 @@
1
- import { createActiveRouteSource } from "@real-router/sources";
2
-
3
- import { createReactiveSource } from "../createReactiveSource.svelte";
4
- import { useRouter } from "./useRouter.svelte";
5
-
6
- import type { Params } from "@real-router/core";
7
-
8
- export function useIsActiveRoute(
9
- routeName: string,
10
- params?: Params,
11
- strict = false,
12
- ignoreQueryParams = true,
13
- ): { readonly current: boolean } {
14
- const router = useRouter();
15
-
16
- const source = createActiveRouteSource(router, routeName, params, {
17
- strict,
18
- ignoreQueryParams,
19
- });
20
-
21
- return createReactiveSource(source);
22
- }
@@ -1,15 +0,0 @@
1
- import { getContext } from "svelte";
2
-
3
- import { NAVIGATOR_KEY } from "../context";
4
-
5
- import type { Navigator } from "@real-router/core";
6
-
7
- export const useNavigator = (): Navigator => {
8
- const navigator = getContext<Navigator | undefined>(NAVIGATOR_KEY);
9
-
10
- if (!navigator) {
11
- throw new Error("useNavigator must be used within a RouterProvider");
12
- }
13
-
14
- return navigator;
15
- };
@@ -1,15 +0,0 @@
1
- import { getContext } from "svelte";
2
-
3
- import { ROUTE_KEY } from "../context";
4
-
5
- import type { RouteContext } from "../types";
6
-
7
- export const useRoute = (): RouteContext => {
8
- const routeContext = getContext<RouteContext | undefined>(ROUTE_KEY);
9
-
10
- if (!routeContext) {
11
- throw new Error("useRoute must be used within a RouterProvider");
12
- }
13
-
14
- return routeContext;
15
- };
@@ -1,33 +0,0 @@
1
- import { getNavigator } from "@real-router/core";
2
- import { createRouteNodeSource } from "@real-router/sources";
3
-
4
- import { createReactiveSource } from "../createReactiveSource.svelte";
5
- import { useRouter } from "./useRouter.svelte";
6
-
7
- import type { RouteContext } from "../types";
8
-
9
- export function useRouteNode(nodeName: string): RouteContext {
10
- const router = useRouter();
11
- const navigator = getNavigator(router);
12
-
13
- const source = createRouteNodeSource(router, nodeName);
14
- const reactive = createReactiveSource(source);
15
-
16
- return {
17
- navigator,
18
- get route() {
19
- return {
20
- get current() {
21
- return reactive.current.route;
22
- },
23
- };
24
- },
25
- get previousRoute() {
26
- return {
27
- get current() {
28
- return reactive.current.previousRoute;
29
- },
30
- };
31
- },
32
- };
33
- }
@@ -1,12 +0,0 @@
1
- import { getPluginApi } from "@real-router/core/api";
2
- import { getRouteUtils } from "@real-router/route-utils";
3
-
4
- import { useRouter } from "./useRouter.svelte";
5
-
6
- import type { RouteUtils } from "@real-router/route-utils";
7
-
8
- export const useRouteUtils = (): RouteUtils => {
9
- const router = useRouter();
10
-
11
- return getRouteUtils(getPluginApi(router).getTree());
12
- };
@@ -1,15 +0,0 @@
1
- import { getContext } from "svelte";
2
-
3
- import { ROUTER_KEY } from "../context";
4
-
5
- import type { Router } from "@real-router/core";
6
-
7
- export const useRouter = (): Router => {
8
- const router = getContext<Router | undefined>(ROUTER_KEY);
9
-
10
- if (!router) {
11
- throw new Error("useRouter must be used within a RouterProvider");
12
- }
13
-
14
- return router;
15
- };
@@ -1,21 +0,0 @@
1
- import { createErrorSource } from "@real-router/sources";
2
-
3
- import { createReactiveSource } from "../createReactiveSource.svelte";
4
- import { useRouter } from "./useRouter.svelte";
5
-
6
- import type { Router } from "@real-router/core";
7
- import type { RouterErrorSnapshot, RouterSource } from "@real-router/sources";
8
-
9
- const cache = new WeakMap<Router, RouterSource<RouterErrorSnapshot>>();
10
-
11
- export function useRouterError(): { readonly current: RouterErrorSnapshot } {
12
- const router = useRouter();
13
-
14
- let source = cache.get(router);
15
- if (!source) {
16
- source = createErrorSource(router);
17
- cache.set(router, source);
18
- }
19
-
20
- return createReactiveSource(source);
21
- }
@@ -1,16 +0,0 @@
1
- import { createTransitionSource } from "@real-router/sources";
2
-
3
- import { createReactiveSource } from "../createReactiveSource.svelte";
4
- import { useRouter } from "./useRouter.svelte";
5
-
6
- import type { RouterTransitionSnapshot } from "@real-router/sources";
7
-
8
- export function useRouterTransition(): {
9
- readonly current: RouterTransitionSnapshot;
10
- } {
11
- const router = useRouter();
12
-
13
- const source = createTransitionSource(router);
14
-
15
- return createReactiveSource(source);
16
- }
package/src/context.ts DELETED
@@ -1,5 +0,0 @@
1
- export const ROUTER_KEY = "real-router:router";
2
-
3
- export const NAVIGATOR_KEY = "real-router:navigator";
4
-
5
- export const ROUTE_KEY = "real-router:route";
@@ -1,21 +0,0 @@
1
- import { createSubscriber } from "svelte/reactivity";
2
-
3
- import type { RouterSource } from "@real-router/sources";
4
-
5
- export function createReactiveSource<T>(source: RouterSource<T>): {
6
- readonly current: T;
7
- } {
8
- const subscribe = createSubscriber((update) => {
9
- return source.subscribe(() => {
10
- update();
11
- });
12
- });
13
-
14
- return {
15
- get current(): T {
16
- subscribe();
17
-
18
- return source.getSnapshot();
19
- },
20
- };
21
- }
package/src/index.ts DELETED
@@ -1,44 +0,0 @@
1
- // Components
2
- export { default as RouteView } from "./components/RouteView.svelte";
3
-
4
- export { default as Link } from "./components/Link.svelte";
5
-
6
- export { default as Lazy } from "./components/Lazy.svelte";
7
-
8
- export { default as RouterErrorBoundary } from "./components/RouterErrorBoundary.svelte";
9
-
10
- // Reactive Primitives
11
- export { createReactiveSource } from "./createReactiveSource.svelte";
12
-
13
- // Composables
14
- export { useRouter } from "./composables/useRouter.svelte";
15
-
16
- export { useNavigator } from "./composables/useNavigator.svelte";
17
-
18
- export { useRouteUtils } from "./composables/useRouteUtils.svelte";
19
-
20
- export { useRoute } from "./composables/useRoute.svelte";
21
-
22
- export { useRouteNode } from "./composables/useRouteNode.svelte";
23
-
24
- export { useRouterTransition } from "./composables/useRouterTransition.svelte";
25
-
26
- // Actions
27
- export { createLinkAction } from "./actions/link.svelte";
28
-
29
- export type { LinkActionParams } from "./actions/link.svelte";
30
-
31
- // Context
32
- export { default as RouterProvider } from "./RouterProvider.svelte";
33
-
34
- export { ROUTER_KEY, NAVIGATOR_KEY, ROUTE_KEY } from "./context";
35
-
36
- // Types
37
- export type { LinkProps, RouteContext } from "./types";
38
-
39
- export type { Navigator } from "@real-router/core";
40
-
41
- export type {
42
- RouterTransitionSnapshot,
43
- RouterErrorSnapshot,
44
- } from "@real-router/sources";
package/src/types.ts DELETED
@@ -1,23 +0,0 @@
1
- import type {
2
- NavigationOptions,
3
- Navigator,
4
- Params,
5
- State,
6
- } from "@real-router/core";
7
-
8
- export interface RouteContext {
9
- readonly navigator: Navigator;
10
- readonly route: { readonly current: State | undefined };
11
- readonly previousRoute: { readonly current: State | undefined };
12
- }
13
-
14
- export interface LinkProps<P extends Params = Params> {
15
- readonly routeName: string;
16
- readonly routeParams?: P;
17
- readonly routeOptions?: NavigationOptions;
18
- readonly class?: string;
19
- readonly activeClassName?: string;
20
- readonly activeStrict?: boolean;
21
- readonly ignoreQueryParams?: boolean;
22
- readonly target?: string;
23
- }