reactive-route 0.0.1-alpha.29 → 0.0.1-alpha.30
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/package.json +44 -117
- package/LICENSE +0 -21
- package/README.md +0 -11
- package/dist/cjs/adapters/kr-observable-preact/package.json +0 -1
- package/dist/cjs/adapters/kr-observable-react/package.json +0 -1
- package/dist/cjs/adapters/kr-observable-solid/package.json +0 -1
- package/dist/cjs/adapters/mobx-preact/package.json +0 -1
- package/dist/cjs/adapters/mobx-react/package.json +0 -1
- package/dist/cjs/adapters/mobx-solid/package.json +0 -1
- package/dist/cjs/adapters/solid/package.json +0 -1
- package/dist/cjs/adapters/vue/package.json +0 -1
- package/dist/cjs/package.json +0 -1
- package/dist/cjs/preact/package.json +0 -1
- package/dist/cjs/react/package.json +0 -1
- package/dist/cjs/solid/package.json +0 -1
- package/dist/cjs/vue/package.json +0 -1
- package/dist/esm/adapters/kr-observable-preact/package.json +0 -1
- package/dist/esm/adapters/kr-observable-react/package.json +0 -1
- package/dist/esm/adapters/kr-observable-solid/package.json +0 -1
- package/dist/esm/adapters/mobx-preact/package.json +0 -1
- package/dist/esm/adapters/mobx-react/package.json +0 -1
- package/dist/esm/adapters/mobx-solid/package.json +0 -1
- package/dist/esm/adapters/solid/package.json +0 -1
- package/dist/esm/adapters/vue/package.json +0 -1
- package/dist/esm/package.json +0 -1
- package/dist/esm/preact/package.json +0 -1
- package/dist/esm/react/package.json +0 -1
- package/dist/esm/solid/package.json +0 -1
- package/dist/esm/vue/package.json +0 -1
- package/dist/tsconfig.types.react.tsbuildinfo +0 -1
- package/dist/tsconfig.types.solid.tsbuildinfo +0 -1
- package/e2e/app.test.ts +0 -130
- package/e2e/teardown.ts +0 -12
- package/playwright.config.ts +0 -54
- package/vitepress/.vitepress/cache/deps/_metadata.json +0 -52
- package/vitepress/.vitepress/cache/deps/chunk-FL23S3EK.js +0 -12705
- package/vitepress/.vitepress/cache/deps/chunk-FL23S3EK.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/chunk-VGAXUAUJ.js +0 -9952
- package/vitepress/.vitepress/cache/deps/chunk-VGAXUAUJ.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/package.json +0 -3
- package/vitepress/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -3844
- package/vitepress/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -588
- package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +0 -1153
- package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +0 -1665
- package/vitepress/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/vitepress___minisearch.js +0 -1812
- package/vitepress/.vitepress/cache/deps/vitepress___minisearch.js.map +0 -7
- package/vitepress/.vitepress/cache/deps/vue.js +0 -342
- package/vitepress/.vitepress/cache/deps/vue.js.map +0 -7
- package/vitepress/.vitepress/config.mts +0 -72
- package/vitepress/.vitepress/theme/custom.css +0 -9
- package/vitepress/.vitepress/theme/index.ts +0 -5
- package/vitepress/examples/preact.md +0 -22
- package/vitepress/examples/react.md +0 -22
- package/vitepress/examples/solid.md +0 -21
- package/vitepress/file.svg +0 -79
- package/vitepress/guide/advanced.md +0 -131
- package/vitepress/guide/getting-started.md +0 -139
- package/vitepress/guide/index.md +0 -44
- package/vitepress/guide/preact.md +0 -33
- package/vitepress/guide/react.md +0 -33
- package/vitepress/guide/router-component.md +0 -67
- package/vitepress/guide/router-configuration.md +0 -185
- package/vitepress/guide/routes-configuration.md +0 -191
- package/vitepress/guide/solid.md +0 -68
- package/vitepress/guide/ssr.md +0 -70
- package/vitepress/index.md +0 -29
- package/vitest.vue.config.mjs +0 -23
- /package/{dist/cjs/adapters/kr-observable-preact/index.js → adapters/kr-observable-preact.cjs} +0 -0
- /package/{dist/adapters → adapters}/kr-observable-preact.d.ts +0 -0
- /package/{dist/adapters → adapters}/kr-observable-preact.d.ts.map +0 -0
- /package/{dist/esm/adapters/kr-observable-preact/index.js → adapters/kr-observable-preact.mjs} +0 -0
- /package/{dist/cjs/adapters/kr-observable-react/index.js → adapters/kr-observable-react.cjs} +0 -0
- /package/{dist/adapters → adapters}/kr-observable-react.d.ts +0 -0
- /package/{dist/adapters → adapters}/kr-observable-react.d.ts.map +0 -0
- /package/{dist/esm/adapters/kr-observable-react/index.js → adapters/kr-observable-react.mjs} +0 -0
- /package/{dist/cjs/adapters/kr-observable-solid/index.js → adapters/kr-observable-solid.cjs} +0 -0
- /package/{dist/adapters → adapters}/kr-observable-solid.d.ts +0 -0
- /package/{dist/adapters → adapters}/kr-observable-solid.d.ts.map +0 -0
- /package/{dist/esm/adapters/kr-observable-solid/index.js → adapters/kr-observable-solid.mjs} +0 -0
- /package/{dist/cjs/adapters/mobx-preact/index.js → adapters/mobx-preact.cjs} +0 -0
- /package/{dist/adapters → adapters}/mobx-preact.d.ts +0 -0
- /package/{dist/adapters → adapters}/mobx-preact.d.ts.map +0 -0
- /package/{dist/esm/adapters/mobx-preact/index.js → adapters/mobx-preact.mjs} +0 -0
- /package/{dist/cjs/adapters/mobx-react/index.js → adapters/mobx-react.cjs} +0 -0
- /package/{dist/adapters → adapters}/mobx-react.d.ts +0 -0
- /package/{dist/adapters → adapters}/mobx-react.d.ts.map +0 -0
- /package/{dist/esm/adapters/mobx-react/index.js → adapters/mobx-react.mjs} +0 -0
- /package/{dist/cjs/adapters/mobx-solid/index.js → adapters/mobx-solid.cjs} +0 -0
- /package/{dist/adapters → adapters}/mobx-solid.d.ts +0 -0
- /package/{dist/adapters → adapters}/mobx-solid.d.ts.map +0 -0
- /package/{dist/esm/adapters/mobx-solid/index.js → adapters/mobx-solid.mjs} +0 -0
- /package/{dist/cjs/adapters/solid/index.js → adapters/solid.cjs} +0 -0
- /package/{dist/adapters → adapters}/solid.d.ts +0 -0
- /package/{dist/adapters → adapters}/solid.d.ts.map +0 -0
- /package/{dist/esm/adapters/solid/index.js → adapters/solid.mjs} +0 -0
- /package/{dist/cjs/adapters/vue/index.js → adapters/vue.cjs} +0 -0
- /package/{dist/adapters → adapters}/vue.d.ts +0 -0
- /package/{dist/adapters → adapters}/vue.d.ts.map +0 -0
- /package/{dist/esm/adapters/vue/index.js → adapters/vue.mjs} +0 -0
- /package/{dist/core → core}/createRouter.d.ts +0 -0
- /package/{dist/core → core}/createRouter.d.ts.map +0 -0
- /package/{dist/core → core}/createRoutes.d.ts +0 -0
- /package/{dist/core → core}/createRoutes.d.ts.map +0 -0
- /package/{dist/core → core}/index.d.ts +0 -0
- /package/{dist/core → core}/index.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeAdapters.d.ts +0 -0
- /package/{dist/core → core}/types/TypeAdapters.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeCurrentRoute.d.ts +0 -0
- /package/{dist/core → core}/types/TypeCurrentRoute.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeLifecycleConfig.d.ts +0 -0
- /package/{dist/core → core}/types/TypeLifecycleConfig.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypePropsRouter.d.ts +0 -0
- /package/{dist/core → core}/types/TypePropsRouter.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeRedirectParams.d.ts +0 -0
- /package/{dist/core → core}/types/TypeRedirectParams.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeRoute.d.ts +0 -0
- /package/{dist/core → core}/types/TypeRoute.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeRouteRaw.d.ts +0 -0
- /package/{dist/core → core}/types/TypeRouteRaw.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeRouter.d.ts +0 -0
- /package/{dist/core → core}/types/TypeRouter.d.ts.map +0 -0
- /package/{dist/core → core}/types/TypeValidator.d.ts +0 -0
- /package/{dist/core → core}/types/TypeValidator.d.ts.map +0 -0
- /package/{dist/core → core}/utils/PreventError.d.ts +0 -0
- /package/{dist/core → core}/utils/PreventError.d.ts.map +0 -0
- /package/{dist/core → core}/utils/RedirectError.d.ts +0 -0
- /package/{dist/core → core}/utils/RedirectError.d.ts.map +0 -0
- /package/{dist/core → core}/utils/addNames.d.ts +0 -0
- /package/{dist/core → core}/utils/addNames.d.ts.map +0 -0
- /package/{dist/core → core}/utils/constants.d.ts +0 -0
- /package/{dist/core → core}/utils/constants.d.ts.map +0 -0
- /package/{dist/core → core}/utils/dynamic.d.ts +0 -0
- /package/{dist/core → core}/utils/dynamic.d.ts.map +0 -0
- /package/{dist/core → core}/utils/findRouteByPathname.d.ts +0 -0
- /package/{dist/core → core}/utils/findRouteByPathname.d.ts.map +0 -0
- /package/{dist/core → core}/utils/getDynamicValues.d.ts +0 -0
- /package/{dist/core → core}/utils/getDynamicValues.d.ts.map +0 -0
- /package/{dist/core → core}/utils/getInitialRoute.d.ts +0 -0
- /package/{dist/core → core}/utils/getInitialRoute.d.ts.map +0 -0
- /package/{dist/core → core}/utils/getQueryValues.d.ts +0 -0
- /package/{dist/core → core}/utils/getQueryValues.d.ts.map +0 -0
- /package/{dist/core → core}/utils/getTypedEntries.d.ts +0 -0
- /package/{dist/core → core}/utils/getTypedEntries.d.ts.map +0 -0
- /package/{dist/core → core}/utils/history.d.ts +0 -0
- /package/{dist/core → core}/utils/history.d.ts.map +0 -0
- /package/{dist/core → core}/utils/loadComponentToConfig.d.ts +0 -0
- /package/{dist/core → core}/utils/loadComponentToConfig.d.ts.map +0 -0
- /package/{dist/core → core}/utils/queryString.d.ts +0 -0
- /package/{dist/core → core}/utils/queryString.d.ts.map +0 -0
- /package/{dist/core → core}/utils/replaceDynamicValues.d.ts +0 -0
- /package/{dist/core → core}/utils/replaceDynamicValues.d.ts.map +0 -0
- /package/{dist/cjs/index.js → index.cjs} +0 -0
- /package/{dist/esm/index.js → index.mjs} +0 -0
- /package/{dist/preact → preact}/Router.d.ts +0 -0
- /package/{dist/preact → preact}/Router.d.ts.map +0 -0
- /package/{dist/cjs/preact/index.js → preact/index.cjs} +0 -0
- /package/{dist/preact → preact}/index.d.ts +0 -0
- /package/{dist/preact → preact}/index.d.ts.map +0 -0
- /package/{dist/esm/preact/index.js → preact/index.mjs} +0 -0
- /package/{dist/react → react}/Router.d.ts +0 -0
- /package/{dist/react → react}/Router.d.ts.map +0 -0
- /package/{dist/cjs/react/index.js → react/index.cjs} +0 -0
- /package/{dist/react → react}/index.d.ts +0 -0
- /package/{dist/react → react}/index.d.ts.map +0 -0
- /package/{dist/esm/react/index.js → react/index.mjs} +0 -0
- /package/{dist/solid → solid}/Router.d.ts +0 -0
- /package/{dist/solid → solid}/Router.d.ts.map +0 -0
- /package/{dist/cjs/solid/index.js → solid/index.cjs} +0 -0
- /package/{dist/solid → solid}/index.d.ts +0 -0
- /package/{dist/solid → solid}/index.d.ts.map +0 -0
- /package/{dist/esm/solid/index.js → solid/index.mjs} +0 -0
- /package/{dist/cjs/vue/index.js → vue/index.cjs} +0 -0
- /package/{dist/vue → vue}/index.d.ts +0 -0
- /package/{dist/vue → vue}/index.d.ts.map +0 -0
- /package/{dist/esm/vue/index.js → vue/index.mjs} +0 -0
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# Router Configuration
|
|
2
|
-
|
|
3
|
-
The router is the central piece that manages the state of the router and provides methods for navigation. It's created using the `createRouter` function.
|
|
4
|
-
|
|
5
|
-
## Creating a Router Store
|
|
6
|
-
|
|
7
|
-
```typescript [router.ts]
|
|
8
|
-
import { createRouter } from 'reactive-route';
|
|
9
|
-
import { adapters } from 'reactive-route/adapters/{reactive-system}';
|
|
10
|
-
|
|
11
|
-
const routes = createRoutes({
|
|
12
|
-
// ...your config
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// If you prefer Context and SSR
|
|
16
|
-
export function getRouter() {
|
|
17
|
-
return createRouter({ routes, adapters });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// If you prefer singletons
|
|
21
|
-
export const router = createRouter({ routes, adapters })
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The `createRouter` function accepts an object with the following properties:
|
|
25
|
-
|
|
26
|
-
| Property | Type | Description |
|
|
27
|
-
|-------------------|-----------------------------------|------------------------------------------------------------|
|
|
28
|
-
| `routes` | `ReturnType<typeof createRoutes>` | The routes configuration |
|
|
29
|
-
| `adapters` | `TypeAdapters` | Adapters for the state management system |
|
|
30
|
-
| `lifecycleParams` | `Array<any>` | Built-in DI for `beforeEnter` and `beforeLeave` (optional) |
|
|
31
|
-
|
|
32
|
-
You may pass your own adapters if they satisfy the model
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
type TypeAdapters = {
|
|
36
|
-
batch: (cb: () => void) => void;
|
|
37
|
-
autorun: (cb: () => void) => any;
|
|
38
|
-
replaceObject: <TObj extends Record<string, any>>(obj: TObj, newObj: TObj) => void;
|
|
39
|
-
makeObservable: <TObj extends Record<string, any>>(obj: TObj) => TObj;
|
|
40
|
-
observer?: (comp: any) => any;
|
|
41
|
-
};
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Router API
|
|
45
|
-
|
|
46
|
-
The router store provides several methods for navigation and state management:
|
|
47
|
-
|
|
48
|
-
| Property | Type | Description |
|
|
49
|
-
|---------------------|-------------------------------------------------|------------------------------|
|
|
50
|
-
| `currentRoute` | `TypeCurrentRoute<typeof routes['routeKey']>` | The current route data |
|
|
51
|
-
| `routesHistory` | `Array<string>` | The history of visited paths |
|
|
52
|
-
| `isRedirecting` | `boolean` | The indicator of redirecting |
|
|
53
|
-
| `redirect` | `(config: TypeRedirectToParams): Promise<void>` | The navigation function |
|
|
54
|
-
| `restoreFromURL` | `(params: { pathname: string }): Promise<void>` | To restore from url |
|
|
55
|
-
| `restoreFromServer` | `(obj: TypeRouter): Promise<void>` | To restore from object |
|
|
56
|
-
| `routes` | `ReturnType<typeof createRoutes>` | Routes configuration |
|
|
57
|
-
| `lifecycleParams` | `Array<any>` | Custom lifecycle parameters |
|
|
58
|
-
|
|
59
|
-
### redirect
|
|
60
|
-
|
|
61
|
-
Navigates to a specified route:
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
await router.redirect({
|
|
65
|
-
route: 'about',
|
|
66
|
-
// with dynamic parameters
|
|
67
|
-
params: { id: '123' },
|
|
68
|
-
// with query parameters
|
|
69
|
-
query: { q: 's' },
|
|
70
|
-
// if you want to replace history state instead of pushing
|
|
71
|
-
replace: true,
|
|
72
|
-
});
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
This function is fully TypeScript-typed, and TypeScript hints will be shown for autocomplete.
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
const routes = createRoutes({
|
|
79
|
-
static: {
|
|
80
|
-
path: '/static',
|
|
81
|
-
loader: () => import('./pages/static'),
|
|
82
|
-
},
|
|
83
|
-
dynamic: {
|
|
84
|
-
path: '/page/:foo',
|
|
85
|
-
params: {
|
|
86
|
-
foo: (value: string) => value.length > 0,
|
|
87
|
-
},
|
|
88
|
-
query: {
|
|
89
|
-
q: (value: string) => value.length > 0,
|
|
90
|
-
},
|
|
91
|
-
loader: () => import('./pages/dynamic'),
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
// other routes
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Good
|
|
98
|
-
redirect({ route: 'static' })
|
|
99
|
-
redirect({ route: 'dynamic', params: { foo: 'bar' } })
|
|
100
|
-
redirect({ route: 'dynamic', params: { foo: 'bar' }, query: { q: 's' } })
|
|
101
|
-
|
|
102
|
-
// TS errors
|
|
103
|
-
redirect({ });
|
|
104
|
-
redirect({ route: 'nonExisting' });
|
|
105
|
-
redirect({ route: 'static', params: {} });
|
|
106
|
-
redirect({ route: 'dynamic' });
|
|
107
|
-
redirect({ route: 'dynamic', params: {} });
|
|
108
|
-
redirect({ route: 'dynamic', params: { a: 'b' } });
|
|
109
|
-
redirect({ route: 'dynamic', params: { foo: 'bar' }, query: { some: 'value' } });
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### restoreFromURL
|
|
113
|
-
|
|
114
|
-
Initializes the basic route from the current URL:
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
// Client-side
|
|
118
|
-
await router.restoreFromURL({
|
|
119
|
-
pathname: location.pathname + location.search,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Server-side
|
|
123
|
-
await router.restoreFromURL({
|
|
124
|
-
// use your framework's way to get the full path + search
|
|
125
|
-
pathname: req.originalUrl,
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### restoreFromServer
|
|
130
|
-
|
|
131
|
-
Initializes the basic route from an object, for example SSR-prepared data:
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
await router.restoreFromServer({ routesHistory, currentRoute });
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### currentRoute
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
import { TypeCurrentRoute } from 'reactive-route';
|
|
141
|
-
|
|
142
|
-
const currentRoute = router.currentRoute
|
|
143
|
-
as TypeCurrentRoute<typeof router.routes.dynamic>;
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
The current route object has the following properties:
|
|
147
|
-
|
|
148
|
-
| Property | Type | Description |
|
|
149
|
-
|------------|-------------------------------------------------------|-------------------------------------------------------------------|
|
|
150
|
-
| `name` | `string (keyof typeof routes)` | The name of the route |
|
|
151
|
-
| `path` | `string (typeof routes[keyof typeof routes]['path'])` | The path of the route |
|
|
152
|
-
| `params` | `Record<string, string>` | The parameters of the route |
|
|
153
|
-
| `query` | `Record<string, string>` | The query parameters of the route |
|
|
154
|
-
| `props` | `Record<string, any>` | The props for the component |
|
|
155
|
-
| `pageId` | `string` | The name of the page, if exported from the page loader (optional) |
|
|
156
|
-
|
|
157
|
-
Note that TS-typing is static and `currentRoute` is not necessarily this one. When redirecting is finished,
|
|
158
|
-
it will become a new route instance, so if you use `autorun` to track current params, check `currentRoute.name` first.
|
|
159
|
-
|
|
160
|
-
## isRedirecting
|
|
161
|
-
|
|
162
|
-
If you need to show loaders on redirects, you may use this parameter. For global loader:
|
|
163
|
-
|
|
164
|
-
```tsx
|
|
165
|
-
const GlobalHeader = () => {
|
|
166
|
-
const { router } = useContext(StoreContext);
|
|
167
|
-
|
|
168
|
-
return router.isRedirecting ? <Loader /> : null;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Or for a local one:
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
const GlobalHeader = () => {
|
|
176
|
-
const { router } = useContext(StoreContext);
|
|
177
|
-
|
|
178
|
-
return <Button isLoading={router.isRedirecting} />;
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## routesHistory
|
|
183
|
-
|
|
184
|
-
This array includes all the visited paths and may be used for logging or to check from which route
|
|
185
|
-
the user came to the current page.
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# Routes Configuration
|
|
2
|
-
|
|
3
|
-
The router configuration is the heart of Reactive Route. It defines all the routes in your application, their paths, parameters, and behavior.
|
|
4
|
-
|
|
5
|
-
Use the `createRoutes` function to create a router configuration:
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { createRoutes } from 'reactive-route';
|
|
9
|
-
|
|
10
|
-
const routes = createRoutes({
|
|
11
|
-
// Your route definitions go here.
|
|
12
|
-
|
|
13
|
-
// These routes are required
|
|
14
|
-
notFound: {
|
|
15
|
-
path: '/not-found',
|
|
16
|
-
loader: () => import('./pages/error'),
|
|
17
|
-
},
|
|
18
|
-
internalError: {
|
|
19
|
-
path: '/internal-error',
|
|
20
|
-
loader: () => import('./pages/error'),
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Route Definition
|
|
26
|
-
|
|
27
|
-
Each route is defined as a key-value pair in the configuration object. The key is the route name, and the value is an object with the route configuration.
|
|
28
|
-
|
|
29
|
-
| Property | Type | Description |
|
|
30
|
-
|---------------|--------------------------------------------------|-------------------------------------------------------------------------------------------------------|
|
|
31
|
-
| `path` | `string` | The URL path for the route. Can include dynamic segments prefixed with `:` |
|
|
32
|
-
| `loader` | `() => Promise<{ default, pageId, ...rest }>` | A function that returns a Promise resolving to the component (it should be in the **default** export) |
|
|
33
|
-
| `props` | `Record<string, any>` | Static props to pass to the component (optional) |
|
|
34
|
-
| `params` | `Record<string, (value: string) => boolean>` | Validation functions for path parameters (required if route type is Dynamic) |
|
|
35
|
-
| `query` | `Record<string, (value: string) => boolean>` | Validation functions for query parameters (optional) |
|
|
36
|
-
| `pageId` | `string` | An optimization for nested routes to avoid page's rerender (optional) |
|
|
37
|
-
| `beforeEnter` | `(config: TypeLifecycleConfig) => Promise<void>` | Hook called before entering the route (optional) |
|
|
38
|
-
| `beforeLeave` | `(config: TypeLifecycleConfig) => Promise<void>` | Hook called before leaving the route (optional) |
|
|
39
|
-
|
|
40
|
-
## Route Types
|
|
41
|
-
|
|
42
|
-
### Static Routes
|
|
43
|
-
|
|
44
|
-
Static routes have fixed paths without parameters:
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
home: {
|
|
48
|
-
path: '/',
|
|
49
|
-
loader: () => import('./pages/Home'),
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Dynamic Routes
|
|
54
|
-
|
|
55
|
-
Dynamic routes have parameters in their paths, indicated by a colon prefix:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
user: {
|
|
59
|
-
path: '/user/:id',
|
|
60
|
-
params: {
|
|
61
|
-
id: (value) => /^\d+$/.test(value), // Validation function
|
|
62
|
-
},
|
|
63
|
-
loader: () => import('./pages/User'),
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
A validation function is required, and if it's not satisfied, the user will be redirected to the "notFound" route.
|
|
68
|
-
If the page is rendered, you can be sure that all the params are validated and present in `router.currentRoute`.
|
|
69
|
-
|
|
70
|
-
### Routes with Query Parameters
|
|
71
|
-
|
|
72
|
-
Both Static Routes and Dynamic Routes may have query parameters:
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
search: {
|
|
76
|
-
path: '/search',
|
|
77
|
-
query: {
|
|
78
|
-
text: (value) => value.length > 0,
|
|
79
|
-
},
|
|
80
|
-
loader: () => import('./pages/Search'),
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
A validation function is required, and if it's not satisfied, the parameter will be inaccessible from the
|
|
85
|
-
store. This means that all query parameters are optional and may be `undefined` in `router.currentRoute`.
|
|
86
|
-
|
|
87
|
-
## Navigation Guards
|
|
88
|
-
|
|
89
|
-
Navigation guards allow you to control the navigation flow in your application. Both `beforeEnter` and `beforeLeave` are async functions.
|
|
90
|
-
|
|
91
|
-
The `beforeEnter` hook is called before entering a route. It can be used to redirect to another route,
|
|
92
|
-
perform authentication checks, and load data.
|
|
93
|
-
|
|
94
|
-
The `beforeLeave` hook is called before leaving a route. It can be used to prevent navigation or
|
|
95
|
-
show a confirmation dialog.
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
dashboard: {
|
|
99
|
-
path: '/dashboard',
|
|
100
|
-
loader: () => import('./pages/protected'),
|
|
101
|
-
async beforeEnter(config) {
|
|
102
|
-
await api.loadUser();
|
|
103
|
-
|
|
104
|
-
if (!isAuthenticated()) {
|
|
105
|
-
return config.redirect({ route: 'login', query: { return: 'dashboard' } });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
await api.loadDashboard();
|
|
109
|
-
},
|
|
110
|
-
async beforeLeave(config) {
|
|
111
|
-
const hasUnsavedChanges = await api.checkSavedForm();
|
|
112
|
-
|
|
113
|
-
if (hasUnsavedChanges) {
|
|
114
|
-
const confirmed = window.confirm(
|
|
115
|
-
`You have unsaved changes. Are you sure you want to leave?`
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
if (!confirmed) return config.preventRedirect();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (config.nextRoute.name === 'user') {
|
|
122
|
-
return config.preventRedirect();
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Always remember to use `return` with `config.redirect` and `config.preventRedirect` to ensure proper flow control.
|
|
129
|
-
|
|
130
|
-
Uncaught errors in `beforeEnter` or `beforeLeave` will lead to the rendering of the "internalError" route,
|
|
131
|
-
so it's important to handle errors properly using `try-catch` blocks or `Promise.catch()` methods.
|
|
132
|
-
|
|
133
|
-
Note that `beforeEnter` is called on dynamic parameter changes, but not called on query changes.
|
|
134
|
-
This behavior may become configurable in future versions.
|
|
135
|
-
|
|
136
|
-
### Accessing Route Information
|
|
137
|
-
|
|
138
|
-
The `config` is an object with parameters as follows:
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
type TypeLifecycleConfig = {
|
|
142
|
-
nextUrl: string;
|
|
143
|
-
nextRoute: any;
|
|
144
|
-
nextPathname: string;
|
|
145
|
-
nextQuery?: any;
|
|
146
|
-
nextSearch?: string;
|
|
147
|
-
|
|
148
|
-
currentUrl?: string;
|
|
149
|
-
currentQuery?: any;
|
|
150
|
-
currentRoute?: any;
|
|
151
|
-
currentSearch?: string;
|
|
152
|
-
currentPathname?: string;
|
|
153
|
-
|
|
154
|
-
redirect: (params: any) => void;
|
|
155
|
-
preventRedirect: () => void;
|
|
156
|
-
};
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Be careful with `config.redirect` function. It accepts the same route data as `router.redirect`,
|
|
160
|
-
but is not typed. So, if you refactor your routes, TS errors will not be shown here which may lead to
|
|
161
|
-
incorrect redirects.
|
|
162
|
-
|
|
163
|
-
### Accessing Custom Parameters in Lifecycle Hooks
|
|
164
|
-
|
|
165
|
-
Both `beforeEnter` and `beforeLeave` support passing custom parameters. These parameters are passed through
|
|
166
|
-
`createRouter({ lifecycleParams })` as will be described in the next section of the documentation.
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
const routes = createRoutes({
|
|
170
|
-
dashboard: {
|
|
171
|
-
path: '/dashboard',
|
|
172
|
-
loader: () => import('./pages/protected'),
|
|
173
|
-
async beforeEnter(config, userStore: UserStore, uiStore: UIStore) {
|
|
174
|
-
if (!userStore.isAuthenticated()) {
|
|
175
|
-
return config.redirect({ route: 'login' });
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
async beforeLeave(config, userStore, uiStore) {
|
|
179
|
-
console.log(userStore, uiStore);
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
// Other routes
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
createRouter({ routes, lifecycleParams: [new UserStore(), new UIStore()] })
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
This approach may not be necessary for CSR-only projects with singletons, as you can simply import `userStore`
|
|
190
|
-
and `uiStore` directly. However, for SSR projects, it's a powerful helper because you can't use singletons
|
|
191
|
-
in that context, and each store needs to be created for every request.
|
package/vitepress/guide/solid.md
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Solid.js Integration
|
|
2
|
-
|
|
3
|
-
## Solid.js native reactivity
|
|
4
|
-
|
|
5
|
-
The relevant imports are as follows
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { Router } from 'reactive-route/solid';
|
|
9
|
-
import { adapters } from 'reactive-route/adapters/solid';
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
No extra packages or configuration needed.
|
|
13
|
-
|
|
14
|
-
## Mobx
|
|
15
|
-
|
|
16
|
-
The relevant imports are as follows
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
import { Router } from 'reactive-route/solid';
|
|
20
|
-
import { adapters } from 'reactive-route/adapters/mobx-solid';
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
You should ensure that package `mobx` is installed.
|
|
24
|
-
|
|
25
|
-
Actually Solid.js has no native integration with MobX. So if you use MobX with Solid.js you probably
|
|
26
|
-
use something like this:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { Reaction } from 'mobx';
|
|
30
|
-
import { enableExternalSource } from 'solid-js';
|
|
31
|
-
|
|
32
|
-
let id = 0;
|
|
33
|
-
|
|
34
|
-
enableExternalSource((fn, trigger) => {
|
|
35
|
-
const reaction = new Reaction(`mobx@${++id}`, trigger);
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
track: (x) => {
|
|
39
|
-
let next;
|
|
40
|
-
reaction.track(() => (next = fn(x)));
|
|
41
|
-
return next;
|
|
42
|
-
},
|
|
43
|
-
dispose: () => reaction.dispose(),
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
... or has better alternatives. Anyway, something like this should be included in your entry file.
|
|
49
|
-
|
|
50
|
-
## Observable
|
|
51
|
-
|
|
52
|
-
The relevant imports are as follows
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
import { Router } from 'reactive-route/solid';
|
|
56
|
-
import { adapters } from 'reactive-route/adapters/kr-observable-solid';
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
You should ensure that package `kr-observable` is installed.
|
|
60
|
-
|
|
61
|
-
Be sure to enable integration in your entry file
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
import { enableObservable } from 'kr-observable/solidjs';
|
|
65
|
-
|
|
66
|
-
enableObservable();
|
|
67
|
-
```
|
|
68
|
-
|
package/vitepress/guide/ssr.md
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# Server-Side Rendering
|
|
2
|
-
|
|
3
|
-
For server-side rendering, you need to initialize the router store on both the server and the client.
|
|
4
|
-
Use `renderToString` and `hydrate` from you framework, as well as `escapeAllStrings` and `unescapeAllStrings` -
|
|
5
|
-
for example, from `lodash`. These utilities are not included in `reactive-route`.
|
|
6
|
-
|
|
7
|
-
### Server
|
|
8
|
-
|
|
9
|
-
```tsx [server.tsx]
|
|
10
|
-
import { getRouter } from './router';
|
|
11
|
-
import { StoreContext } from './StoreContext';
|
|
12
|
-
import { RedirectError } from 'reactive-route';
|
|
13
|
-
|
|
14
|
-
express()
|
|
15
|
-
.get('*', async (req, res) => {
|
|
16
|
-
const template = fs.readFileSync(templatePath, 'utf-8');
|
|
17
|
-
|
|
18
|
-
const router = getRouter();
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
await router.restoreFromURL({ pathname: req.originalUrl });
|
|
22
|
-
} catch (error: any) {
|
|
23
|
-
// The redirects on server-side are made manually, because
|
|
24
|
-
// we can't manipulate the browser's url and history
|
|
25
|
-
if (error instanceof RedirectError) {
|
|
26
|
-
// error.message is a full new path here
|
|
27
|
-
return res.redirect(error.message);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
console.error(error);
|
|
31
|
-
|
|
32
|
-
return res.status(500).send('Unexpected error');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const htmlMarkup = renderToString(
|
|
36
|
-
<StoreContext.Provider value={{ router }}>
|
|
37
|
-
<App />
|
|
38
|
-
</StoreContext.Provider>
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
// A very simple method of serialization, but sufficient for react-route
|
|
42
|
-
const storeJS = JSON.parse(JSON.stringify({ router }));
|
|
43
|
-
const initialData = JSON.stringify(escapeAllStrings(storeJS));
|
|
44
|
-
|
|
45
|
-
res.send(
|
|
46
|
-
template
|
|
47
|
-
.replace(`<!-- HTML -->`, htmlMarkup)
|
|
48
|
-
.replace('<!-- INITIAL_DATA -->', initialData)
|
|
49
|
-
);
|
|
50
|
-
})
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Client
|
|
54
|
-
|
|
55
|
-
```tsx [client.tsx]
|
|
56
|
-
import { getRouter } from './router';
|
|
57
|
-
import { StoreContext } from './StoreContext';
|
|
58
|
-
|
|
59
|
-
const router = getRouter();
|
|
60
|
-
const initialData = unescapeAllStrings(window.INITIAL_DATA);
|
|
61
|
-
|
|
62
|
-
await router.restoreFromServer(initialData.router);
|
|
63
|
-
|
|
64
|
-
hydrate(
|
|
65
|
-
document.getElementById('app'),
|
|
66
|
-
<StoreContext.Provider value={{ router }}>
|
|
67
|
-
<App />
|
|
68
|
-
</StoreContext.Provider>
|
|
69
|
-
);
|
|
70
|
-
```
|
package/vitepress/index.md
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: home
|
|
3
|
-
|
|
4
|
-
hero:
|
|
5
|
-
name: "Reactive Route"
|
|
6
|
-
text: "Framework-agnostic reactive routing"
|
|
7
|
-
tagline: A lightweight, flexible, and reactive router for React, Preact and Solid.js
|
|
8
|
-
actions:
|
|
9
|
-
- theme: brand
|
|
10
|
-
text: Get Started
|
|
11
|
-
link: /guide/
|
|
12
|
-
- theme: alt
|
|
13
|
-
text: View on GitHub
|
|
14
|
-
link: https://github.com/dkazakov8/reactive-route
|
|
15
|
-
|
|
16
|
-
features:
|
|
17
|
-
- title: Framework Agnostic
|
|
18
|
-
details: Core routing logic is framework-agnostic, with adapters for React, Preact and Solid.js
|
|
19
|
-
- title: State Management Integration
|
|
20
|
-
details: Seamlessly integrates with MobX, Observable, and Solid.js reactivity systems
|
|
21
|
-
- title: Type Safety
|
|
22
|
-
details: Built with TypeScript for type safety and better developer experience
|
|
23
|
-
- title: Config-based
|
|
24
|
-
details: Define your routes in a simple, declarative configuration object
|
|
25
|
-
- title: Navigation Guards
|
|
26
|
-
details: Powerful async beforeEnter and beforeLeave route lifecycle with DI
|
|
27
|
-
- title: SSR Support
|
|
28
|
-
details: Full support for server-side rendering in any supported framework
|
|
29
|
-
---
|
package/vitest.vue.config.mjs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
test: {
|
|
5
|
-
projects: ['packages/vue/vitest.config.mjs' /*, 'packages/vue/vitest.ssr.config.mjs'*/],
|
|
6
|
-
coverage: {
|
|
7
|
-
clean: false,
|
|
8
|
-
enabled: true,
|
|
9
|
-
provider: 'istanbul',
|
|
10
|
-
reporter: ['text', ['cobertura', { file: 'core.xml' }]],
|
|
11
|
-
reportsDirectory: './.nyc_output',
|
|
12
|
-
include: ['packages/*'],
|
|
13
|
-
exclude: ['packages/*/test/*', 'packages/shared'],
|
|
14
|
-
},
|
|
15
|
-
onConsoleLog(log) {
|
|
16
|
-
if (log.includes('a is not defined') /*|| log.includes('warn')*/) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return true;
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
});
|
/package/{dist/cjs/adapters/kr-observable-preact/index.js → adapters/kr-observable-preact.cjs}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{dist/esm/adapters/kr-observable-preact/index.js → adapters/kr-observable-preact.mjs}
RENAMED
|
File without changes
|
/package/{dist/cjs/adapters/kr-observable-react/index.js → adapters/kr-observable-react.cjs}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{dist/esm/adapters/kr-observable-react/index.js → adapters/kr-observable-react.mjs}
RENAMED
|
File without changes
|
/package/{dist/cjs/adapters/kr-observable-solid/index.js → adapters/kr-observable-solid.cjs}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{dist/esm/adapters/kr-observable-solid/index.js → adapters/kr-observable-solid.mjs}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|