@nano_kit/react-router 1.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 - present, TrigenSoftware
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @nano_kit/react-router
|
|
2
|
+
|
|
3
|
+
[![ESM-only package][package]][package-url]
|
|
4
|
+
[![NPM version][npm]][npm-url]
|
|
5
|
+
[![Dependencies status][deps]][deps-url]
|
|
6
|
+
[![Install size][size]][size-url]
|
|
7
|
+
[![Build status][build]][build-url]
|
|
8
|
+
[![Coverage status][coverage]][coverage-url]
|
|
9
|
+
|
|
10
|
+
[package]: https://img.shields.io/badge/package-ESM--only-ffe536.svg
|
|
11
|
+
[package-url]: https://nodejs.org/api/esm.html
|
|
12
|
+
|
|
13
|
+
[npm]: https://img.shields.io/npm/v/@nano_kit/react-router.svg
|
|
14
|
+
[npm-url]: https://npmjs.com/package/@nano_kit/react-router
|
|
15
|
+
|
|
16
|
+
[deps]: https://img.shields.io/librariesio/release/npm/@nano_kit/react-router
|
|
17
|
+
[deps-url]: https://libraries.io/npm/@nano_kit/react-router/tree
|
|
18
|
+
|
|
19
|
+
[size]: https://deno.bundlejs.com/badge?q=@nano_kit/react-router
|
|
20
|
+
[size-url]: https://bundlejs.com/?q=@nano_kit/react-router
|
|
21
|
+
|
|
22
|
+
[build]: https://img.shields.io/github/actions/workflow/status/TrigenSoftware/nano_kit/tests.yml?branch=main
|
|
23
|
+
[build-url]: https://github.com/TrigenSoftware/nano_kit/actions
|
|
24
|
+
|
|
25
|
+
[coverage]: https://img.shields.io/codecov/c/github/TrigenSoftware/nano_kit.svg
|
|
26
|
+
[coverage-url]: https://app.codecov.io/gh/TrigenSoftware/nano_kit
|
|
27
|
+
|
|
28
|
+
The `@nano_kit/react-router` package provides React integration for [@nano_kit/router](../router). It allows you to use the router's powerful features like code splitting, dependency injection, and state management directly within your React application.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm add @nano_kit/store @nano_kit/router @nano_kit/react @nano_kit/react-router
|
|
34
|
+
# or
|
|
35
|
+
npm install @nano_kit/store @nano_kit/router @nano_kit/react @nano_kit/react-router
|
|
36
|
+
# or
|
|
37
|
+
yarn add @nano_kit/store @nano_kit/router @nano_kit/react @nano_kit/react-router
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
Basically, `@nano_kit/react-router` re-exports everything from `@nano_kit/router`, so you can use all base router functions:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { browserNavigation, app, layout, page, loadable, Outlet } from '@nano_kit/react-router'
|
|
46
|
+
import { MainLayout } from './MainLayout'
|
|
47
|
+
|
|
48
|
+
/* Define routes config */
|
|
49
|
+
const routes = {
|
|
50
|
+
home: '/',
|
|
51
|
+
user: '/users/:id'
|
|
52
|
+
} as const
|
|
53
|
+
|
|
54
|
+
/* Create navigation */
|
|
55
|
+
const [$location, navigation] = browserNavigation(routes)
|
|
56
|
+
|
|
57
|
+
/* Define loader fallback */
|
|
58
|
+
const Loader = () => <div>Loading...</div>
|
|
59
|
+
|
|
60
|
+
/* Create App component */
|
|
61
|
+
const App = app($location, [
|
|
62
|
+
layout(MainLayout, [
|
|
63
|
+
page('home', loadable(() => import('./Home'), Loader)),
|
|
64
|
+
page('user', loadable(() => import('./User'), Loader))
|
|
65
|
+
])
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
/* Render App */
|
|
69
|
+
createRoot(document.getElementById('root')!).render(<App />)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
|
|
74
|
+
For comprehensive guides, API reference, and integration patterns, visit the [documentation website](https://nano_kit.js.org/integrations/react-router).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type ReactNode, type FocusEvent, type MouseEvent, type AnchorHTMLAttributes } from 'react';
|
|
2
|
+
import { type InjectionFactory, type ReadableSignal } from '@nano_kit/store';
|
|
3
|
+
import { type LayoutMatchRef, type Navigation, type PageMatchRef, type Paths, type RouteLocationRecord, type Routes, type StoresPreload, type UnknownMatchRef } from '@nano_kit/router';
|
|
4
|
+
export * from '@nano_kit/router';
|
|
5
|
+
export type PageComponent = () => ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Renders the nested page component within a layout.
|
|
8
|
+
*/
|
|
9
|
+
export declare function Outlet(): import("react").JSX.Element | null;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a computed signal that matches the current route against page and layout definitions.
|
|
12
|
+
* Supports nested layouts with composition function for combining layouts with nested content.
|
|
13
|
+
* @param $location - Route match signal containing route and parameters
|
|
14
|
+
* @param pages - Array of page and layout match references
|
|
15
|
+
* @returns Tuple of computed signal containing the matched page or composed layout and function to preload stores
|
|
16
|
+
*/
|
|
17
|
+
export declare function router<R extends Routes, K extends keyof R & string>($location: RouteLocationRecord<R>, pages: (PageMatchRef<NoInfer<K>, PageComponent> | PageMatchRef<null, PageComponent> | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>)[]): [ReadableSignal<PageComponent | null>, StoresPreload];
|
|
18
|
+
/**
|
|
19
|
+
* Creates a current route matching page and layout injection factory.
|
|
20
|
+
* @param Location$ - Injection factory for the route location record.
|
|
21
|
+
* @param pages - Array of page and layout match references.
|
|
22
|
+
* @returns Tuple of page injection factory and stores preload injection factory.
|
|
23
|
+
*/
|
|
24
|
+
export declare function router$<R extends Routes, K extends keyof R & string>(Location$: InjectionFactory<RouteLocationRecord<R>>, pages: (PageMatchRef<NoInfer<K>, PageComponent> | PageMatchRef<null, PageComponent> | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>)[]): [
|
|
25
|
+
InjectionFactory<ReadableSignal<PageComponent | null>>,
|
|
26
|
+
InjectionFactory<StoresPreload>
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Creates a React application component that renders the matched page based on the current route.
|
|
30
|
+
* @param $location - Current location signal.
|
|
31
|
+
* @param pages - Array of page and layout match references.
|
|
32
|
+
* @returns React application component.
|
|
33
|
+
*/
|
|
34
|
+
export declare function app<R extends Routes, K extends keyof R & string>($location: RouteLocationRecord<R>, pages: (PageMatchRef<NoInfer<K>, PageComponent> | PageMatchRef<null, PageComponent> | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>)[]): () => import("react").JSX.Element | null;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a React application component that renders the matched page based on the current route.
|
|
37
|
+
* Notice: App should be used within a dependency injection context.
|
|
38
|
+
* @param Location$ - Injection factory for the route location record.
|
|
39
|
+
* @param pages - Array of page and layout match references.
|
|
40
|
+
* @returns React application component and stores preload injection factory.
|
|
41
|
+
*/
|
|
42
|
+
export declare function app$<R extends Routes, K extends keyof R & string>(Location$: InjectionFactory<RouteLocationRecord<R>>, pages: (PageMatchRef<NoInfer<K>, PageComponent> | PageMatchRef<null, PageComponent> | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>)[]): readonly [() => import("react").JSX.Element | null, InjectionFactory<StoresPreload>];
|
|
43
|
+
/**
|
|
44
|
+
* Creates a preload hook for preloading pages on user interaction.
|
|
45
|
+
* @param pages - Array of page and layout match references.
|
|
46
|
+
* @param preloadByDefault - Whether to preload pages by default.
|
|
47
|
+
* @returns Hook function to use for preloading pages.
|
|
48
|
+
*/
|
|
49
|
+
export declare function preloadable(pages: UnknownMatchRef[], preloadByDefault?: boolean): ({ onFocus, onMouseEnter }: {
|
|
50
|
+
onFocus?(event: FocusEvent): void;
|
|
51
|
+
onMouseEnter?(event: MouseEvent): void;
|
|
52
|
+
}, to: string | undefined, preload?: boolean) => {
|
|
53
|
+
onFocus: (event: FocusEvent) => void;
|
|
54
|
+
onMouseEnter: (event: MouseEvent) => void;
|
|
55
|
+
};
|
|
56
|
+
export type LinkProps<R extends Routes, K extends keyof R & string> = AnchorHTMLAttributes<HTMLAnchorElement> & ((Paths<R>[K] extends infer P ? P extends (params?: infer Params) => string ? {
|
|
57
|
+
/** Target route name */
|
|
58
|
+
to: K;
|
|
59
|
+
/** Parameters for the route */
|
|
60
|
+
params?: Params;
|
|
61
|
+
/**
|
|
62
|
+
* Whether to preload the page on hover or focus.
|
|
63
|
+
* Notice: Link should be created with preloadable hook.
|
|
64
|
+
*/
|
|
65
|
+
preload?: boolean;
|
|
66
|
+
href?: never;
|
|
67
|
+
} : P extends (params: infer Params) => string ? {
|
|
68
|
+
/** Target route name */
|
|
69
|
+
to: K;
|
|
70
|
+
/** Parameters for the route */
|
|
71
|
+
params: Params;
|
|
72
|
+
/**
|
|
73
|
+
* Whether to preload the page on hover or focus.
|
|
74
|
+
* Notice: Link should be created with preloadable hook.
|
|
75
|
+
*/
|
|
76
|
+
preload?: boolean;
|
|
77
|
+
href?: never;
|
|
78
|
+
} : {
|
|
79
|
+
/** Target route name */
|
|
80
|
+
to: K;
|
|
81
|
+
params?: never;
|
|
82
|
+
/**
|
|
83
|
+
* Whether to preload the page on hover or focus.
|
|
84
|
+
* Notice: Link should be created with preloadable hook.
|
|
85
|
+
*/
|
|
86
|
+
preload?: boolean;
|
|
87
|
+
href?: never;
|
|
88
|
+
} : never) | {
|
|
89
|
+
to?: never;
|
|
90
|
+
params?: never;
|
|
91
|
+
preload?: never;
|
|
92
|
+
href?: string;
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* Creates a Link component for navigation.
|
|
96
|
+
* @param navigation - Router navigation object
|
|
97
|
+
* @param paths - Path builders for routes
|
|
98
|
+
* @param usePreload - Preload hook for preloading pages
|
|
99
|
+
* @returns Link component for navigation.
|
|
100
|
+
*/
|
|
101
|
+
export declare function link<R extends Routes>(navigation: Navigation, paths: Paths<R>, usePreload?: ReturnType<typeof preloadable>): <K extends keyof R & string>(props: LinkProps<R, K>) => import("react").JSX.Element;
|
|
102
|
+
/**
|
|
103
|
+
* Creates a Link component for navigation.
|
|
104
|
+
* Notice: Link should be used within a dependency injection context.
|
|
105
|
+
* @param Navigation$ - Injection factory for the navigation object.
|
|
106
|
+
* @param paths - Path builders for routes
|
|
107
|
+
* @param usePreload - Preload hook for preloading pages
|
|
108
|
+
* @returns Link component for navigation.
|
|
109
|
+
*/
|
|
110
|
+
export declare function link$<R extends Routes>(Navigation$: InjectionFactory<Navigation>, paths: Paths<R>, usePreload?: ReturnType<typeof preloadable>): <K extends keyof R & string>(props: LinkProps<R, K>) => import("react").JSX.Element;
|
|
111
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useContext, useCallback, useMemo } from 'react';
|
|
3
|
+
import { signal } from '@nano_kit/store';
|
|
4
|
+
import { useSignal, useInject } from '@nano_kit/react';
|
|
5
|
+
import { router as router$2, router$ as router$$1, loadPage, onLinkClick } from '@nano_kit/router';
|
|
6
|
+
export * from '@nano_kit/router';
|
|
7
|
+
|
|
8
|
+
const OutletContext = /* @__PURE__ */ createContext(
|
|
9
|
+
signal(null)
|
|
10
|
+
);
|
|
11
|
+
// @__NO_SIDE_EFFECTS__
|
|
12
|
+
function Outlet() {
|
|
13
|
+
const $nested = useContext(OutletContext);
|
|
14
|
+
const Nested = useSignal($nested);
|
|
15
|
+
return Nested ? /* @__PURE__ */ jsx(Nested, {}) : null;
|
|
16
|
+
}
|
|
17
|
+
function compose($nested, Layout) {
|
|
18
|
+
const { Provider } = OutletContext;
|
|
19
|
+
return () => /* @__PURE__ */ jsx(Provider, { value: $nested, children: /* @__PURE__ */ jsx(Layout, {}) });
|
|
20
|
+
}
|
|
21
|
+
// @__NO_SIDE_EFFECTS__
|
|
22
|
+
function router($location, pages) {
|
|
23
|
+
return router$2($location, pages, compose);
|
|
24
|
+
}
|
|
25
|
+
function router$(Location$, pages) {
|
|
26
|
+
return router$$1(Location$, pages, compose);
|
|
27
|
+
}
|
|
28
|
+
function app($location, pages) {
|
|
29
|
+
const [$page] = /* @__PURE__ */ router($location, pages);
|
|
30
|
+
return function App() {
|
|
31
|
+
const Page = useSignal($page);
|
|
32
|
+
return Page && /* @__PURE__ */ jsx(Page, {});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function app$(Location$, pages) {
|
|
36
|
+
const [Page$, StoresToPreload$] = router$(Location$, pages);
|
|
37
|
+
return [
|
|
38
|
+
function App() {
|
|
39
|
+
const $page = useInject(Page$);
|
|
40
|
+
const Page = useSignal($page);
|
|
41
|
+
return Page && /* @__PURE__ */ jsx(Page, {});
|
|
42
|
+
},
|
|
43
|
+
StoresToPreload$
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function preloadable(pages, preloadByDefault = false) {
|
|
47
|
+
const preloaded = /* @__PURE__ */ new Set();
|
|
48
|
+
return function usePreload({
|
|
49
|
+
onFocus,
|
|
50
|
+
onMouseEnter
|
|
51
|
+
}, to, preload = preloadByDefault) {
|
|
52
|
+
const preloadCallback = useCallback(() => {
|
|
53
|
+
if (to && preload && !preloaded.has(to)) {
|
|
54
|
+
preloaded.add(to);
|
|
55
|
+
void loadPage(pages, to);
|
|
56
|
+
}
|
|
57
|
+
}, [to, preload]);
|
|
58
|
+
const onFocusCallback = useCallback((event) => {
|
|
59
|
+
preloadCallback();
|
|
60
|
+
onFocus?.(event);
|
|
61
|
+
}, [onFocus, preloadCallback]);
|
|
62
|
+
const onMouseEnterCallback = useCallback((event) => {
|
|
63
|
+
preloadCallback();
|
|
64
|
+
onMouseEnter?.(event);
|
|
65
|
+
}, [onMouseEnter, preloadCallback]);
|
|
66
|
+
return {
|
|
67
|
+
onFocus: onFocusCallback,
|
|
68
|
+
onMouseEnter: onMouseEnterCallback
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function createLink(useOnClick, paths, usePreload) {
|
|
73
|
+
return function Link(props) {
|
|
74
|
+
const {
|
|
75
|
+
to,
|
|
76
|
+
preload,
|
|
77
|
+
href: hrefProp,
|
|
78
|
+
onClick: onClickProp,
|
|
79
|
+
params,
|
|
80
|
+
...restProps
|
|
81
|
+
} = props;
|
|
82
|
+
const onClick = useOnClick();
|
|
83
|
+
const path = to && paths[to];
|
|
84
|
+
const href = hrefProp ?? (path && (typeof path === "function" ? path(params) : path));
|
|
85
|
+
const onClickCallback = useCallback((event) => {
|
|
86
|
+
onClick(event);
|
|
87
|
+
onClickProp?.(event);
|
|
88
|
+
}, [onClick, onClickProp]);
|
|
89
|
+
return /* @__PURE__ */ jsx(
|
|
90
|
+
"a",
|
|
91
|
+
{
|
|
92
|
+
href,
|
|
93
|
+
onClick: onClickCallback,
|
|
94
|
+
...restProps,
|
|
95
|
+
...usePreload?.(restProps, to, preload)
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function link(navigation, paths, usePreload) {
|
|
101
|
+
const onClick = onLinkClick.bind(navigation);
|
|
102
|
+
return createLink(() => onClick, paths, usePreload);
|
|
103
|
+
}
|
|
104
|
+
function link$(Navigation$, paths, usePreload) {
|
|
105
|
+
return createLink(() => {
|
|
106
|
+
const navigation = useInject(Navigation$);
|
|
107
|
+
return useMemo(() => onLinkClick.bind(navigation), [navigation]);
|
|
108
|
+
}, paths, usePreload);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { Outlet, app, app$, link, link$, preloadable, router, router$ };
|
|
112
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import {\n type ReactNode,\n type FocusEvent,\n type MouseEvent,\n type AnchorHTMLAttributes,\n useMemo,\n createContext,\n useContext,\n useCallback\n} from 'react'\nimport {\n type InjectionFactory,\n type ReadableSignal,\n signal\n} from '@nano_kit/store'\nimport {\n useSignal,\n useInject\n} from '@nano_kit/react'\nimport {\n type LayoutMatchRef,\n type Navigation,\n type PageMatchRef,\n type Paths,\n type RouteLocationRecord,\n type Routes,\n type StoresPreload,\n type UnknownMatchRef,\n loadPage,\n onLinkClick,\n router as vanillaRouter,\n router$ as vanillaRouter$\n} from '@nano_kit/router'\n\nexport * from '@nano_kit/router'\n\nexport type PageComponent = () => ReactNode\n\nconst OutletContext = /* @__PURE__ */ createContext<ReadableSignal<PageComponent | null>>(\n signal(null)\n)\n\n/**\n * Renders the nested page component within a layout.\n */\n/* @__NO_SIDE_EFFECTS__ */\nexport function Outlet() {\n const $nested = useContext(OutletContext)\n const Nested = useSignal($nested)\n\n return Nested ? <Nested/> : null\n}\n\nfunction compose(\n $nested: ReadableSignal<PageComponent | null>,\n Layout: PageComponent\n) {\n const { Provider } = OutletContext\n\n return () => (\n <Provider value={$nested}>\n <Layout/>\n </Provider>\n )\n}\n\n/**\n * Creates a computed signal that matches the current route against page and layout definitions.\n * Supports nested layouts with composition function for combining layouts with nested content.\n * @param $location - Route match signal containing route and parameters\n * @param pages - Array of page and layout match references\n * @returns Tuple of computed signal containing the matched page or composed layout and function to preload stores\n */\n/* @__NO_SIDE_EFFECTS__ */\nexport function router<R extends Routes, K extends keyof R & string>(\n $location: RouteLocationRecord<R>,\n pages: (\n | PageMatchRef<NoInfer<K>, PageComponent>\n | PageMatchRef<null, PageComponent>\n | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>\n )[]\n): [ReadableSignal<PageComponent | null>, StoresPreload] {\n return vanillaRouter($location, pages, compose)\n}\n\n/**\n * Creates a current route matching page and layout injection factory.\n * @param Location$ - Injection factory for the route location record.\n * @param pages - Array of page and layout match references.\n * @returns Tuple of page injection factory and stores preload injection factory.\n */\nexport function router$<R extends Routes, K extends keyof R & string>(\n Location$: InjectionFactory<RouteLocationRecord<R>>,\n pages: (\n | PageMatchRef<NoInfer<K>, PageComponent>\n | PageMatchRef<null, PageComponent>\n | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>\n )[]\n): [\n InjectionFactory<ReadableSignal<PageComponent | null>>,\n InjectionFactory<StoresPreload>\n] {\n return vanillaRouter$(Location$, pages, compose)\n}\n\n/**\n * Creates a React application component that renders the matched page based on the current route.\n * @param $location - Current location signal.\n * @param pages - Array of page and layout match references.\n * @returns React application component.\n */\nexport function app<R extends Routes, K extends keyof R & string>(\n $location: RouteLocationRecord<R>,\n pages: (\n | PageMatchRef<NoInfer<K>, PageComponent>\n | PageMatchRef<null, PageComponent>\n | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>\n )[]\n) {\n const [$page] = router($location, pages)\n\n /**\n * React application component.\n */\n return function App() {\n const Page = useSignal($page)\n\n return Page && <Page/>\n }\n}\n\n/**\n * Creates a React application component that renders the matched page based on the current route.\n * Notice: App should be used within a dependency injection context.\n * @param Location$ - Injection factory for the route location record.\n * @param pages - Array of page and layout match references.\n * @returns React application component and stores preload injection factory.\n */\nexport function app$<R extends Routes, K extends keyof R & string>(\n Location$: InjectionFactory<RouteLocationRecord<R>>,\n pages: (\n | PageMatchRef<NoInfer<K>, PageComponent>\n | PageMatchRef<null, PageComponent>\n | LayoutMatchRef<NoInfer<K>, PageComponent, PageComponent>\n )[]\n) {\n const [Page$, StoresToPreload$] = router$(Location$, pages)\n\n /**\n * React application component.\n */\n return [\n function App() {\n const $page = useInject(Page$)\n const Page = useSignal($page)\n\n return Page && <Page/>\n },\n StoresToPreload$\n ] as const\n}\n\n/**\n * Creates a preload hook for preloading pages on user interaction.\n * @param pages - Array of page and layout match references.\n * @param preloadByDefault - Whether to preload pages by default.\n * @returns Hook function to use for preloading pages.\n */\nexport function preloadable(\n pages: UnknownMatchRef[],\n preloadByDefault = false\n) {\n const preloaded = new Set<string>()\n\n /**\n * Hook to preload pages on user interaction.\n * @param props - Event handlers for focus and mouse enter.\n * @param to - Target route to preload.\n * @param preload - Flag indicating whether to preload.\n * @returns Event handlers for preloading.\n */\n return function usePreload(\n {\n onFocus,\n onMouseEnter\n }: {\n onFocus?(event: FocusEvent): void\n onMouseEnter?(event: MouseEvent): void\n },\n to: string | undefined,\n preload = preloadByDefault\n ) {\n const preloadCallback = useCallback(() => {\n if (to && preload && !preloaded.has(to)) {\n preloaded.add(to)\n void loadPage(pages, to)\n }\n }, [to, preload])\n const onFocusCallback = useCallback((event: FocusEvent) => {\n preloadCallback()\n onFocus?.(event)\n }, [onFocus, preloadCallback])\n const onMouseEnterCallback = useCallback((event: MouseEvent) => {\n preloadCallback()\n onMouseEnter?.(event)\n }, [onMouseEnter, preloadCallback])\n\n return {\n onFocus: onFocusCallback,\n onMouseEnter: onMouseEnterCallback\n }\n }\n}\n\nexport type LinkProps<R extends Routes, K extends keyof R & string> = AnchorHTMLAttributes<HTMLAnchorElement> & ((\n Paths<R>[K] extends infer P\n ? P extends (params?: infer Params) => string\n ? {\n /** Target route name */\n to: K\n /** Parameters for the route */\n params?: Params\n /**\n * Whether to preload the page on hover or focus.\n * Notice: Link should be created with preloadable hook.\n */\n preload?: boolean\n href?: never\n }\n : P extends (params: infer Params) => string\n ? {\n /** Target route name */\n to: K\n /** Parameters for the route */\n params: Params\n /**\n * Whether to preload the page on hover or focus.\n * Notice: Link should be created with preloadable hook.\n */\n preload?: boolean\n href?: never\n }\n : {\n /** Target route name */\n to: K\n params?: never\n /**\n * Whether to preload the page on hover or focus.\n * Notice: Link should be created with preloadable hook.\n */\n preload?: boolean\n href?: never\n }\n : never\n) | {\n to?: never\n params?: never\n preload?: never\n href?: string\n})\n\nfunction createLink<R extends Routes>(\n useOnClick: () => (event: MouseEvent<HTMLAnchorElement>) => void,\n paths: Paths<R>,\n usePreload?: ReturnType<typeof preloadable>\n) {\n /**\n * Link component for navigation.\n * @param props - Link properties including target route, parameters, and event handlers.\n * @returns Anchor element for navigation.\n */\n return function Link<K extends keyof R & string>(props: LinkProps<R, K>) {\n const {\n to,\n preload,\n href: hrefProp,\n onClick: onClickProp,\n params,\n ...restProps\n } = props\n const onClick = useOnClick()\n const path = to && paths[to]\n const href = hrefProp ?? (path && (\n typeof path === 'function'\n ? path(params)\n : path\n ))\n const onClickCallback = useCallback((event: MouseEvent<HTMLAnchorElement>) => {\n onClick(event)\n onClickProp?.(event)\n }, [onClick, onClickProp])\n\n return (\n <a\n href={href}\n onClick={onClickCallback}\n {...restProps}\n {...usePreload?.(restProps, to, preload)}\n />\n )\n }\n}\n\n/**\n * Creates a Link component for navigation.\n * @param navigation - Router navigation object\n * @param paths - Path builders for routes\n * @param usePreload - Preload hook for preloading pages\n * @returns Link component for navigation.\n */\nexport function link<R extends Routes>(\n navigation: Navigation,\n paths: Paths<R>,\n usePreload?: ReturnType<typeof preloadable>\n) {\n const onClick = onLinkClick.bind(navigation)\n\n return createLink(() => onClick, paths, usePreload)\n}\n\n/**\n * Creates a Link component for navigation.\n * Notice: Link should be used within a dependency injection context.\n * @param Navigation$ - Injection factory for the navigation object.\n * @param paths - Path builders for routes\n * @param usePreload - Preload hook for preloading pages\n * @returns Link component for navigation.\n */\nexport function link$<R extends Routes>(\n Navigation$: InjectionFactory<Navigation>,\n paths: Paths<R>,\n usePreload?: ReturnType<typeof preloadable>\n) {\n return createLink(() => {\n const navigation = useInject(Navigation$)\n\n return useMemo(() => onLinkClick.bind(navigation), [navigation])\n }, paths, usePreload)\n}\n"],"names":["vanillaRouter","vanillaRouter$"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nano_kit/react-router",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0-alpha.1",
|
|
5
|
+
"description": "React integration for @nano_kit/router with code splitting, dependency injection, and state management.",
|
|
6
|
+
"author": "dangreen",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://nano_kit.js.org/integrations/react-router",
|
|
9
|
+
"funding": "https://ko-fi.com/dangreen",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/TrigenSoftware/nano_kit.git",
|
|
13
|
+
"directory": "packages/react-router"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/TrigenSoftware/nano_kit/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"react",
|
|
20
|
+
"router",
|
|
21
|
+
"routing",
|
|
22
|
+
"navigation",
|
|
23
|
+
"store",
|
|
24
|
+
"state",
|
|
25
|
+
"signal",
|
|
26
|
+
"reactive",
|
|
27
|
+
"nano_kit"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=16"
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"exports": {
|
|
34
|
+
"./package.json": "./package.json",
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
45
|
+
"@nano_kit/router": "^1.0.0-alpha.4",
|
|
46
|
+
"@nano_kit/store": "^1.0.0-alpha.0",
|
|
47
|
+
"@nano_kit/react": "^1.0.0-alpha.3"
|
|
48
|
+
}
|
|
49
|
+
}
|