react-iten 0.0.2 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -2
- package/dist/components/Link.cjs +21 -0
- package/dist/components/Link.d.cts +13 -0
- package/dist/components/Link.d.ts +13 -0
- package/dist/components/Link.mjs +21 -0
- package/dist/components/Navigate.cjs +15 -0
- package/dist/components/Navigate.d.cts +10 -0
- package/dist/components/Navigate.d.ts +10 -0
- package/dist/components/Navigate.mjs +15 -0
- package/dist/components/Route.cjs +22 -0
- package/dist/components/Route.d.cts +17 -0
- package/dist/components/Route.d.ts +17 -0
- package/dist/components/Route.mjs +22 -0
- package/dist/components/Switch.cjs +21 -0
- package/dist/components/Switch.d.cts +9 -0
- package/dist/components/Switch.d.ts +9 -0
- package/dist/components/Switch.mjs +21 -0
- package/dist/create-router.cjs +18 -0
- package/dist/create-router.d.cts +18 -0
- package/dist/create-router.d.ts +18 -0
- package/dist/create-router.mjs +18 -0
- package/dist/headless.cjs +83 -0
- package/dist/headless.d.cts +21 -0
- package/dist/headless.d.ts +21 -0
- package/dist/headless.mjs +40 -0
- package/dist/hooks.cjs +52 -0
- package/dist/hooks.d.cts +21 -0
- package/dist/hooks.d.ts +21 -0
- package/dist/hooks.mjs +52 -0
- package/dist/index.cjs +48 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.mjs +4 -0
- package/dist/types.d.cts +19 -0
- package/dist/types.d.ts +19 -0
- package/dist/url.cjs +20 -0
- package/dist/url.d.cts +14 -0
- package/dist/url.d.ts +14 -0
- package/dist/url.mjs +19 -0
- package/dist/utils.cjs +44 -0
- package/dist/utils.d.cts +3 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.mjs +2 -0
- package/dist/zod.cjs +77 -0
- package/dist/zod.d.cts +48 -0
- package/dist/zod.d.ts +48 -0
- package/dist/zod.mjs +73 -0
- package/package.json +99 -5
- package/src/components/Link.tsx +36 -0
- package/src/components/Navigate.tsx +26 -0
- package/src/components/Route.tsx +53 -0
- package/src/components/Switch.tsx +30 -0
- package/src/create-router.ts +33 -0
- package/src/headless.ts +91 -0
- package/src/hooks.ts +74 -0
- package/src/index.ts +35 -0
- package/src/types.ts +47 -0
- package/src/url.ts +49 -0
- package/src/utils.ts +23 -0
- package/src/zod.ts +150 -0
- package/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-iten",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "React adapter for iten — ultralight in-memory router for embedded JS apps
|
|
3
|
+
"version": "0.4.2",
|
|
4
|
+
"description": "React adapter for iten — ultralight in-memory router for embedded JS apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
7
7
|
"router",
|
|
@@ -18,13 +18,107 @@
|
|
|
18
18
|
"url": "https://github.com/andrew-bierman/iten/issues"
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://github.com/andrew-bierman/iten#readme",
|
|
21
|
-
"
|
|
21
|
+
"type": "module",
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"bun": "./src/index.ts",
|
|
26
|
+
"import": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"default": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"require": {
|
|
31
|
+
"types": "./dist/index.d.cts",
|
|
32
|
+
"default": "./dist/index.cjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"./headless": {
|
|
36
|
+
"bun": "./src/headless.ts",
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/headless.d.ts",
|
|
39
|
+
"default": "./dist/headless.mjs"
|
|
40
|
+
},
|
|
41
|
+
"require": {
|
|
42
|
+
"types": "./dist/headless.d.cts",
|
|
43
|
+
"default": "./dist/headless.cjs"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"./zod": {
|
|
47
|
+
"bun": "./src/zod.ts",
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/zod.d.ts",
|
|
50
|
+
"default": "./dist/zod.mjs"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./dist/zod.d.cts",
|
|
54
|
+
"default": "./dist/zod.cjs"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./utils": {
|
|
58
|
+
"bun": "./src/utils.ts",
|
|
59
|
+
"import": {
|
|
60
|
+
"types": "./dist/utils.d.ts",
|
|
61
|
+
"default": "./dist/utils.mjs"
|
|
62
|
+
},
|
|
63
|
+
"require": {
|
|
64
|
+
"types": "./dist/utils.d.cts",
|
|
65
|
+
"default": "./dist/utils.cjs"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"./url": {
|
|
69
|
+
"bun": "./src/url.ts",
|
|
70
|
+
"import": {
|
|
71
|
+
"types": "./dist/url.d.ts",
|
|
72
|
+
"default": "./dist/url.mjs"
|
|
73
|
+
},
|
|
74
|
+
"require": {
|
|
75
|
+
"types": "./dist/url.d.cts",
|
|
76
|
+
"default": "./dist/url.cjs"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"main": "./dist/index.cjs",
|
|
81
|
+
"module": "./dist/index.mjs",
|
|
82
|
+
"types": "./dist/index.d.ts",
|
|
22
83
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"
|
|
84
|
+
"dist",
|
|
85
|
+
"src"
|
|
25
86
|
],
|
|
87
|
+
"scripts": {
|
|
88
|
+
"build": "tsdown",
|
|
89
|
+
"typecheck": "tsc --noEmit",
|
|
90
|
+
"typecheck:types": "bun run build && tsc -p tsconfig.type-tests.json",
|
|
91
|
+
"test": "bun test ./test"
|
|
92
|
+
},
|
|
93
|
+
"peerDependencies": {
|
|
94
|
+
"@tanstack/react-query": "^5.0.0",
|
|
95
|
+
"react": "^18.3.0 || ^19.0.0",
|
|
96
|
+
"zod": "^4.0.0"
|
|
97
|
+
},
|
|
98
|
+
"peerDependenciesMeta": {
|
|
99
|
+
"@tanstack/react-query": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"zod": {
|
|
103
|
+
"optional": true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"dependencies": {
|
|
107
|
+
"iten-core": "^0.4.2"
|
|
108
|
+
},
|
|
26
109
|
"publishConfig": {
|
|
27
110
|
"access": "public",
|
|
28
111
|
"registry": "https://registry.npmjs.org/"
|
|
112
|
+
},
|
|
113
|
+
"devDependencies": {
|
|
114
|
+
"@tanstack/react-query": "^5.101.2",
|
|
115
|
+
"@testing-library/react": "^16.0.0",
|
|
116
|
+
"@types/react": "^19.0.0",
|
|
117
|
+
"happy-dom": "^20.9.0",
|
|
118
|
+
"react": "^19.0.0",
|
|
119
|
+
"react-dom": "^19.0.0",
|
|
120
|
+
"tsdown": "0.21.9",
|
|
121
|
+
"typescript": "^5.7.0",
|
|
122
|
+
"zod": "^4.4.3"
|
|
29
123
|
}
|
|
30
124
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RouteMapDef, RouteUnion } from 'iten-core'
|
|
2
|
+
import { type MouseEvent, type ReactNode, useCallback } from 'react'
|
|
3
|
+
import type { HookBundle } from '../hooks.ts'
|
|
4
|
+
|
|
5
|
+
export type LinkProps<M extends RouteMapDef> = {
|
|
6
|
+
to: RouteUnion<M>
|
|
7
|
+
children: (state: { isLoading: boolean }) => ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type LinkComponent<M extends RouteMapDef> = (props: LinkProps<M>) => ReactNode
|
|
11
|
+
|
|
12
|
+
export function makeLink<M extends RouteMapDef>(hooks: HookBundle<M>): LinkComponent<M> {
|
|
13
|
+
const { useNavigate, useRouteLoading } = hooks
|
|
14
|
+
|
|
15
|
+
function Link({ to, children }: LinkProps<M>): ReactNode {
|
|
16
|
+
const navigate = useNavigate()
|
|
17
|
+
const isLoading = useRouteLoading({ name: to.name as keyof M })
|
|
18
|
+
|
|
19
|
+
const handleClick = useCallback(
|
|
20
|
+
(event: MouseEvent) => {
|
|
21
|
+
event.preventDefault()
|
|
22
|
+
void navigate({ target: to })
|
|
23
|
+
},
|
|
24
|
+
[navigate, to],
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
// biome-ignore lint/a11y/useValidAnchor: embedded app context uses in-memory navigation
|
|
29
|
+
<a href="#" onClick={handleClick}>
|
|
30
|
+
{children({ isLoading })}
|
|
31
|
+
</a>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return Link
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RouteMapDef, RouteUnion } from 'iten-core'
|
|
2
|
+
import { type ReactNode, useEffect } from 'react'
|
|
3
|
+
import type { HookBundle } from '../hooks.ts'
|
|
4
|
+
|
|
5
|
+
export type NavigateProps<M extends RouteMapDef> = {
|
|
6
|
+
to: RouteUnion<M>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type NavigateComponent<M extends RouteMapDef> = (props: NavigateProps<M>) => ReactNode
|
|
10
|
+
|
|
11
|
+
export function makeNavigate<M extends RouteMapDef>(hooks: HookBundle<M>): NavigateComponent<M> {
|
|
12
|
+
const { useNavigate } = hooks
|
|
13
|
+
|
|
14
|
+
function Navigate({ to }: NavigateProps<M>): ReactNode {
|
|
15
|
+
const navigate = useNavigate()
|
|
16
|
+
|
|
17
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: redirect should fire once on mount
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
void navigate({ target: to })
|
|
20
|
+
}, [])
|
|
21
|
+
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return Navigate
|
|
26
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { RouteMapDef } from 'iten-core'
|
|
2
|
+
import type { ComponentType, ReactNode } from 'react'
|
|
3
|
+
import type { HookBundle } from '../hooks.ts'
|
|
4
|
+
|
|
5
|
+
export type RouteProps<M extends RouteMapDef, K extends keyof M> = {
|
|
6
|
+
name: K
|
|
7
|
+
children?: ((params: M[K]) => ReactNode) | undefined
|
|
8
|
+
component?: ComponentType<M[K]> | undefined
|
|
9
|
+
pendingComponent?: ComponentType | undefined
|
|
10
|
+
errorComponent?: ComponentType<{ error: unknown; retry: () => Promise<void> }> | undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type RouteComponent<M extends RouteMapDef> = <K extends keyof M>(
|
|
14
|
+
props: RouteProps<M, K>,
|
|
15
|
+
) => ReactNode
|
|
16
|
+
|
|
17
|
+
export function makeRoute<M extends RouteMapDef>(hooks: HookBundle<M>): RouteComponent<M> {
|
|
18
|
+
const { useRoute, useIsNavigating, useRouterError } = hooks
|
|
19
|
+
|
|
20
|
+
function Route<K extends keyof M>({
|
|
21
|
+
name,
|
|
22
|
+
children,
|
|
23
|
+
component: Component,
|
|
24
|
+
pendingComponent: PendingComponent,
|
|
25
|
+
errorComponent: ErrorComponent,
|
|
26
|
+
}: RouteProps<M, K>): ReactNode {
|
|
27
|
+
const { isActive, params } = useRoute({ name })
|
|
28
|
+
const isNavigating = useIsNavigating()
|
|
29
|
+
const error = useRouterError()
|
|
30
|
+
|
|
31
|
+
if (!isActive) return null
|
|
32
|
+
|
|
33
|
+
if (error && ErrorComponent) {
|
|
34
|
+
return <ErrorComponent error={error.error} retry={error.retry} />
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isNavigating && PendingComponent) {
|
|
38
|
+
return <PendingComponent />
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (children) {
|
|
42
|
+
return children(params)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (Component) {
|
|
46
|
+
return <Component {...params} />
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return Route
|
|
53
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RouteMapDef } from 'iten-core'
|
|
2
|
+
import { Children, isValidElement, type ReactNode } from 'react'
|
|
3
|
+
import type { HookBundle } from '../hooks.ts'
|
|
4
|
+
|
|
5
|
+
export type SwitchComponent = (props: { children: ReactNode }) => ReactNode
|
|
6
|
+
|
|
7
|
+
export function makeSwitch<M extends RouteMapDef>(hooks: HookBundle<M>): SwitchComponent {
|
|
8
|
+
const { useCurrentRoute } = hooks
|
|
9
|
+
|
|
10
|
+
function Switch({ children }: { children: ReactNode }): ReactNode {
|
|
11
|
+
const route = useCurrentRoute()
|
|
12
|
+
|
|
13
|
+
for (const child of Children.toArray(children)) {
|
|
14
|
+
if (!isValidElement(child)) continue
|
|
15
|
+
|
|
16
|
+
const props = child.props as Record<string, unknown>
|
|
17
|
+
|
|
18
|
+
if ('name' in props) {
|
|
19
|
+
if (props.name === route?.name) return child
|
|
20
|
+
continue
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return child
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return Switch
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RouteMapDef } from 'iten-core'
|
|
2
|
+
import type { LinkComponent } from './components/Link.tsx'
|
|
3
|
+
import { makeLink } from './components/Link.tsx'
|
|
4
|
+
import type { NavigateComponent } from './components/Navigate.tsx'
|
|
5
|
+
import { makeNavigate } from './components/Navigate.tsx'
|
|
6
|
+
import type { RouteComponent } from './components/Route.tsx'
|
|
7
|
+
import { makeRoute } from './components/Route.tsx'
|
|
8
|
+
import type { SwitchComponent } from './components/Switch.tsx'
|
|
9
|
+
import { makeSwitch } from './components/Switch.tsx'
|
|
10
|
+
import type { HeadlessReactRouter } from './headless.ts'
|
|
11
|
+
import { createHeadlessRouter } from './headless.ts'
|
|
12
|
+
import type { ReactRouterConfig } from './types.ts'
|
|
13
|
+
|
|
14
|
+
export type ReactRouter<M extends RouteMapDef, _Ctx = unknown> = HeadlessReactRouter<M> & {
|
|
15
|
+
Route: RouteComponent<M>
|
|
16
|
+
Switch: SwitchComponent
|
|
17
|
+
Link: LinkComponent<M>
|
|
18
|
+
Navigate: NavigateComponent<M>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createRouter<M extends RouteMapDef, Ctx = unknown>(
|
|
22
|
+
config: ReactRouterConfig<M, Ctx>,
|
|
23
|
+
): ReactRouter<M, Ctx> {
|
|
24
|
+
const hooks = createHeadlessRouter<M, Ctx>(config)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
...hooks,
|
|
28
|
+
Route: makeRoute<M>(hooks),
|
|
29
|
+
Switch: makeSwitch<M>(hooks),
|
|
30
|
+
Link: makeLink<M>(hooks),
|
|
31
|
+
Navigate: makeNavigate<M>(hooks),
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/headless.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { ItenCore, NavigateInput, RouteMapDef, RouterState } from 'iten-core'
|
|
2
|
+
import { createItenCore } from 'iten-core'
|
|
3
|
+
import type { HookBundle } from './hooks.ts'
|
|
4
|
+
import { makeHooks } from './hooks.ts'
|
|
5
|
+
import type { ReactRouterConfig } from './types.ts'
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
createRoute,
|
|
9
|
+
defineRouteConfig,
|
|
10
|
+
defineRoutes,
|
|
11
|
+
isRoute,
|
|
12
|
+
isRouteName,
|
|
13
|
+
matchRoute,
|
|
14
|
+
route,
|
|
15
|
+
} from 'iten-core'
|
|
16
|
+
export type {
|
|
17
|
+
InferRoutes,
|
|
18
|
+
NoParams,
|
|
19
|
+
QueryClientLike,
|
|
20
|
+
RouteConfigMap,
|
|
21
|
+
RouteMap,
|
|
22
|
+
RouteMapDef,
|
|
23
|
+
RouteMatcher,
|
|
24
|
+
RouteName,
|
|
25
|
+
RouteOf,
|
|
26
|
+
RouteParams,
|
|
27
|
+
RouterError,
|
|
28
|
+
RouterState,
|
|
29
|
+
RouteUnion,
|
|
30
|
+
UseRouteResult,
|
|
31
|
+
} from './types.ts'
|
|
32
|
+
|
|
33
|
+
export type ReactRouterStore<M extends RouteMapDef> = {
|
|
34
|
+
getState: () => RouterState<M>
|
|
35
|
+
subscribe: (input: { listener: () => void }) => () => void
|
|
36
|
+
navigate: (input: NavigateInput<M>) => Promise<void>
|
|
37
|
+
goBack: () => void
|
|
38
|
+
dispose: () => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type HeadlessReactRouter<M extends RouteMapDef> = HookBundle<M> & {
|
|
42
|
+
store: ReactRouterStore<M>
|
|
43
|
+
core: ItenCore<M>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function createHeadlessRouter<M extends RouteMapDef, Ctx = unknown>(
|
|
47
|
+
config: ReactRouterConfig<M, Ctx>,
|
|
48
|
+
): HeadlessReactRouter<M> {
|
|
49
|
+
const getCtx = (): Ctx => {
|
|
50
|
+
if (typeof config.context === 'function') {
|
|
51
|
+
return (config.context as () => Ctx)()
|
|
52
|
+
}
|
|
53
|
+
return (config.context ?? {}) as Ctx
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const core = createItenCore<M, Ctx>({
|
|
57
|
+
initial: config.initial,
|
|
58
|
+
routeConfig: config.routeConfig,
|
|
59
|
+
maxHistoryLength: config.maxHistoryLength,
|
|
60
|
+
queryClient: config.queryClient,
|
|
61
|
+
getCtx,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
let snapshot = core.getState()
|
|
65
|
+
|
|
66
|
+
const store: ReactRouterStore<M> = {
|
|
67
|
+
getState: () => snapshot,
|
|
68
|
+
subscribe: ({ listener }) =>
|
|
69
|
+
core.subscribe({
|
|
70
|
+
listener: (nextSnapshot) => {
|
|
71
|
+
snapshot = nextSnapshot
|
|
72
|
+
listener()
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
navigate: async (input) => {
|
|
76
|
+
await core.navigate(input)
|
|
77
|
+
snapshot = core.getState()
|
|
78
|
+
},
|
|
79
|
+
goBack: () => {
|
|
80
|
+
core.goBack()
|
|
81
|
+
snapshot = core.getState()
|
|
82
|
+
},
|
|
83
|
+
dispose: () => core.dispose(),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
store,
|
|
88
|
+
core,
|
|
89
|
+
...makeHooks<M>(store),
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/hooks.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { NavigateInput, RouteMapDef, RouterError, RouterState, RouteUnion } from 'iten-core'
|
|
2
|
+
import { useSyncExternalStore } from 'react'
|
|
3
|
+
import type { ReactRouterStore } from './headless.ts'
|
|
4
|
+
import type { UseRouteResult } from './types.ts'
|
|
5
|
+
|
|
6
|
+
export type HookBundle<M extends RouteMapDef> = {
|
|
7
|
+
useRouterState: () => RouterState<M>
|
|
8
|
+
useCurrentRoute: () => RouteUnion<M> | null
|
|
9
|
+
useRoute: <K extends keyof M>(input: { name: K }) => UseRouteResult<M, K>
|
|
10
|
+
useNavigate: () => (input: NavigateInput<M>) => Promise<void>
|
|
11
|
+
useGoBack: () => () => void
|
|
12
|
+
useIsNavigating: () => boolean
|
|
13
|
+
useCanGoBack: () => boolean
|
|
14
|
+
useRouteLoading: (input: { name: keyof M }) => boolean
|
|
15
|
+
useRouterError: () => RouterError | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function makeHooks<M extends RouteMapDef>(store: ReactRouterStore<M>): HookBundle<M> {
|
|
19
|
+
function useRouterState(): RouterState<M> {
|
|
20
|
+
return useSyncExternalStore(
|
|
21
|
+
(listener) => store.subscribe({ listener }),
|
|
22
|
+
store.getState,
|
|
23
|
+
store.getState,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function useCurrentRoute(): RouteUnion<M> | null {
|
|
28
|
+
return useRouterState().route
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function useRoute<K extends keyof M>({ name }: { name: K }): UseRouteResult<M, K> {
|
|
32
|
+
const route = useRouterState().route
|
|
33
|
+
if (route?.name === name) {
|
|
34
|
+
return { isActive: true, params: route as unknown as M[K] }
|
|
35
|
+
}
|
|
36
|
+
return { isActive: false, params: null }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function useNavigate(): (input: NavigateInput<M>) => Promise<void> {
|
|
40
|
+
return store.navigate
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function useGoBack(): () => void {
|
|
44
|
+
return store.goBack
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function useIsNavigating(): boolean {
|
|
48
|
+
return useRouterState().isNavigating
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function useCanGoBack(): boolean {
|
|
52
|
+
return useRouterState().canGoBack
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function useRouteLoading({ name }: { name: keyof M }): boolean {
|
|
56
|
+
return useRouterState().pendingRoute?.name === name
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function useRouterError(): RouterError | null {
|
|
60
|
+
return useRouterState().error
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
useRouterState,
|
|
65
|
+
useCurrentRoute,
|
|
66
|
+
useRoute,
|
|
67
|
+
useNavigate,
|
|
68
|
+
useGoBack,
|
|
69
|
+
useIsNavigating,
|
|
70
|
+
useCanGoBack,
|
|
71
|
+
useRouteLoading,
|
|
72
|
+
useRouterError,
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createRoute,
|
|
3
|
+
defineRouteConfig,
|
|
4
|
+
defineRoutes,
|
|
5
|
+
isRoute,
|
|
6
|
+
isRouteName,
|
|
7
|
+
matchRoute,
|
|
8
|
+
route,
|
|
9
|
+
} from 'iten-core'
|
|
10
|
+
export type { LinkProps } from './components/Link.tsx'
|
|
11
|
+
export type { NavigateProps } from './components/Navigate.tsx'
|
|
12
|
+
export type { RouteProps } from './components/Route.tsx'
|
|
13
|
+
export type { ReactRouter } from './create-router.ts'
|
|
14
|
+
export { createRouter } from './create-router.ts'
|
|
15
|
+
export type { HeadlessReactRouter, ReactRouterStore } from './headless.ts'
|
|
16
|
+
export { createHeadlessRouter } from './headless.ts'
|
|
17
|
+
export type {
|
|
18
|
+
InferRoutes,
|
|
19
|
+
NoParams,
|
|
20
|
+
QueryClientLike,
|
|
21
|
+
ReactRouterConfig,
|
|
22
|
+
RouteConfigMap,
|
|
23
|
+
RouteDefinition,
|
|
24
|
+
RouteDefinitions,
|
|
25
|
+
RouteMap,
|
|
26
|
+
RouteMapDef,
|
|
27
|
+
RouteMatcher,
|
|
28
|
+
RouteName,
|
|
29
|
+
RouteOf,
|
|
30
|
+
RouteParams,
|
|
31
|
+
RouterError,
|
|
32
|
+
RouterState,
|
|
33
|
+
RouteUnion,
|
|
34
|
+
UseRouteResult,
|
|
35
|
+
} from './types.ts'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InferRoutes,
|
|
3
|
+
NoParams,
|
|
4
|
+
QueryClientLike,
|
|
5
|
+
RouteConfigMap,
|
|
6
|
+
RouteDefinition,
|
|
7
|
+
RouteDefinitions,
|
|
8
|
+
RouteMap,
|
|
9
|
+
RouteMapDef,
|
|
10
|
+
RouteMatcher,
|
|
11
|
+
RouteName,
|
|
12
|
+
RouteOf,
|
|
13
|
+
RouteParams,
|
|
14
|
+
RouterError,
|
|
15
|
+
RouterState,
|
|
16
|
+
RouteUnion,
|
|
17
|
+
} from 'iten-core'
|
|
18
|
+
|
|
19
|
+
export type {
|
|
20
|
+
InferRoutes,
|
|
21
|
+
NoParams,
|
|
22
|
+
QueryClientLike,
|
|
23
|
+
RouteConfigMap,
|
|
24
|
+
RouteDefinition,
|
|
25
|
+
RouteDefinitions,
|
|
26
|
+
RouteMap,
|
|
27
|
+
RouteMapDef,
|
|
28
|
+
RouteMatcher,
|
|
29
|
+
RouteName,
|
|
30
|
+
RouteOf,
|
|
31
|
+
RouteParams,
|
|
32
|
+
RouterError,
|
|
33
|
+
RouterState,
|
|
34
|
+
RouteUnion,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type ReactRouterConfig<M extends RouteMapDef, Ctx = unknown> = {
|
|
38
|
+
initial: RouteUnion<M> | null
|
|
39
|
+
routeConfig?: RouteConfigMap<M, Ctx> | undefined
|
|
40
|
+
maxHistoryLength?: number | undefined
|
|
41
|
+
context?: Ctx | (() => Ctx) | undefined
|
|
42
|
+
queryClient?: QueryClientLike | null | undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type UseRouteResult<M extends RouteMapDef, K extends keyof M> =
|
|
46
|
+
| { isActive: true; params: M[K] }
|
|
47
|
+
| { isActive: false; params: null }
|
package/src/url.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ItenCore, NavigateInput, RouteMapDef, RouterState } from 'iten-core'
|
|
2
|
+
import {
|
|
3
|
+
type CreateUrlSyncInput as CoreCreateUrlSyncInput,
|
|
4
|
+
createUrlSync as createCoreUrlSync,
|
|
5
|
+
type UrlSync,
|
|
6
|
+
} from 'iten-core/url'
|
|
7
|
+
import type { HeadlessReactRouter } from './headless.ts'
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
FormatUrlInput,
|
|
11
|
+
ParseUrlInput,
|
|
12
|
+
UrlHydrateInput,
|
|
13
|
+
UrlParseErrorInput,
|
|
14
|
+
UrlStartInput,
|
|
15
|
+
UrlSubscribeInput,
|
|
16
|
+
UrlSync,
|
|
17
|
+
UrlWriteInput,
|
|
18
|
+
UrlWriteMode,
|
|
19
|
+
} from 'iten-core/url'
|
|
20
|
+
|
|
21
|
+
export type CreateUrlSyncInput<M extends RouteMapDef> = Omit<
|
|
22
|
+
CoreCreateUrlSyncInput<M>,
|
|
23
|
+
'router'
|
|
24
|
+
> & {
|
|
25
|
+
router: HeadlessReactRouter<M>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createUrlSync<M extends RouteMapDef>({
|
|
29
|
+
router,
|
|
30
|
+
...input
|
|
31
|
+
}: CreateUrlSyncInput<M>): UrlSync<M> {
|
|
32
|
+
const coreLike: ItenCore<M> = {
|
|
33
|
+
getState: () => router.store.getState() as RouterState<M>,
|
|
34
|
+
navigate: (navigateInput: NavigateInput<M>) => router.store.navigate(navigateInput),
|
|
35
|
+
goBack: () => router.store.goBack(),
|
|
36
|
+
subscribe: ({ listener }) =>
|
|
37
|
+
router.store.subscribe({
|
|
38
|
+
listener: () => {
|
|
39
|
+
listener(router.store.getState() as RouterState<M>)
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
dispose: () => {},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return createCoreUrlSync<M>({
|
|
46
|
+
...input,
|
|
47
|
+
router: coreLike,
|
|
48
|
+
})
|
|
49
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
InferRoutes,
|
|
3
|
+
NoParams,
|
|
4
|
+
RouteConfigMap,
|
|
5
|
+
RouteMap,
|
|
6
|
+
RouteMapDef,
|
|
7
|
+
RouteUnion,
|
|
8
|
+
} from 'iten-core'
|
|
9
|
+
export type {
|
|
10
|
+
RouteMatcher,
|
|
11
|
+
RouteName,
|
|
12
|
+
RouteOf,
|
|
13
|
+
RouteParams,
|
|
14
|
+
} from 'iten-core/utils'
|
|
15
|
+
export {
|
|
16
|
+
createRoute,
|
|
17
|
+
defineRouteConfig,
|
|
18
|
+
defineRoutes,
|
|
19
|
+
isRoute,
|
|
20
|
+
isRouteName,
|
|
21
|
+
matchRoute,
|
|
22
|
+
route,
|
|
23
|
+
} from 'iten-core/utils'
|