@native-router/core 1.0.0
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 +79 -0
- package/dist/index.mjs +393 -0
- package/dist/types/errors.d.ts +5 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/router.d.ts +154 -0
- package/dist/types/types.d.ts +74 -0
- package/dist/types/util.d.ts +12 -0
- package/package.json +119 -0
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@native-router/core)
|
|
2
|
+
[](https://github.com/wmzy/@native-router/core/actions)
|
|
3
|
+
[](https://codecov.io/gh/wmzy/@native-router/core)
|
|
4
|
+
[](https://packagephobia.now.sh/result?p=@native-router/core)
|
|
5
|
+
|
|
6
|
+
# Native Router React
|
|
7
|
+
|
|
8
|
+
> A route close to the native experience for react.
|
|
9
|
+
|
|
10
|
+
English | [简体中文](./README-zh_CN.md)
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- Asynchronous navigation
|
|
15
|
+
- Cancelable
|
|
16
|
+
- Page data concurrent fetch
|
|
17
|
+
- Link prefetch and preview
|
|
18
|
+
- Most unused features can be tree-shaking
|
|
19
|
+
- SSR support
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i @native-router/core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import {View, HistoryRouter as Router} from '@native-router/core';
|
|
31
|
+
import Loading from '@/components/Loading';
|
|
32
|
+
import RouterError from '@/components/RouterError';
|
|
33
|
+
import * as userService from '@/services/user';
|
|
34
|
+
|
|
35
|
+
export default function App() {
|
|
36
|
+
return (
|
|
37
|
+
<Router
|
|
38
|
+
routes={{
|
|
39
|
+
component: () => import('./Layout'),
|
|
40
|
+
children: [
|
|
41
|
+
{
|
|
42
|
+
path: '/',
|
|
43
|
+
component: () => import('./Home')
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
path: '/users',
|
|
47
|
+
component: () => import('./UserList'),
|
|
48
|
+
data: userService.fetchList
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
path: '/users/:id',
|
|
52
|
+
component: () => import('./UserProfile'),
|
|
53
|
+
data: ({id}) => userService.fetchById(+id)
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: '/help',
|
|
57
|
+
component: () => import('./Help')
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: '/about',
|
|
61
|
+
component: () => import('./About')
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}}
|
|
65
|
+
baseUrl="/demos"
|
|
66
|
+
errorHandler={(e) => <RouterError error={e} />}
|
|
67
|
+
>
|
|
68
|
+
<View />
|
|
69
|
+
<Loading />
|
|
70
|
+
</Router>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
See [demos](/demos/) for a complete example.
|
|
76
|
+
|
|
77
|
+
## Documentation
|
|
78
|
+
|
|
79
|
+
[API](https://wmzy.github.io/@native-router/core/modules.html)
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { parsePath, createPath } from 'history';
|
|
2
|
+
import { match as match$1 } from 'path-to-regexp';
|
|
3
|
+
|
|
4
|
+
let i = 1;
|
|
5
|
+
function uniqId() {
|
|
6
|
+
return i++;
|
|
7
|
+
}
|
|
8
|
+
function noop() {}
|
|
9
|
+
const reject = /* @__PURE__ */Promise.reject.bind(Promise);
|
|
10
|
+
function cancelPromise() {
|
|
11
|
+
return new Promise(noop);
|
|
12
|
+
}
|
|
13
|
+
function createCurrentGuard() {
|
|
14
|
+
let current;
|
|
15
|
+
return [function currentGuard(promise) {
|
|
16
|
+
const cur = uniqId();
|
|
17
|
+
current = cur;
|
|
18
|
+
return promise.then(result => current === cur ? result : cancelPromise()).catch(err => current === cur ? Promise.reject(err) : cancelPromise());
|
|
19
|
+
}, function cancel() {
|
|
20
|
+
current = undefined;
|
|
21
|
+
}];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* eslint-disable max-classes-per-file */
|
|
25
|
+
|
|
26
|
+
class NativeRouterError extends Error {}
|
|
27
|
+
class NotFoundError extends NativeRouterError {
|
|
28
|
+
constructor(pathname) {
|
|
29
|
+
super(`Can't find the path: ${pathname}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a router instance.
|
|
35
|
+
* @group Methods
|
|
36
|
+
* @category Router
|
|
37
|
+
* @param routes routes config
|
|
38
|
+
* @param history {@link https://www.npmjs.com/package/history history} instance
|
|
39
|
+
* @param resolveView a callback to resolve view. see {@link defaultResolveView}
|
|
40
|
+
* @param options options
|
|
41
|
+
* @returns a router instance
|
|
42
|
+
*/
|
|
43
|
+
function create(routes, history, resolveView, options) {
|
|
44
|
+
const [currentGuard, cancelAll] = createCurrentGuard();
|
|
45
|
+
const {
|
|
46
|
+
index,
|
|
47
|
+
locationStack
|
|
48
|
+
} = getHistoryState({
|
|
49
|
+
history: history
|
|
50
|
+
});
|
|
51
|
+
const viewStack = new Array(locationStack.length).fill(null);
|
|
52
|
+
if (options?.currentView) {
|
|
53
|
+
viewStack[index] = options.currentView;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
routes: Array.isArray(routes) ? routes : [routes],
|
|
57
|
+
resolveView,
|
|
58
|
+
history: history,
|
|
59
|
+
locationStack,
|
|
60
|
+
viewStack,
|
|
61
|
+
currentGuard,
|
|
62
|
+
cancelAll,
|
|
63
|
+
errorHandler: reject,
|
|
64
|
+
...options,
|
|
65
|
+
baseUrl: options?.baseUrl || ''
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function setOptions(router, options) {
|
|
69
|
+
return Object.assign(router, options);
|
|
70
|
+
}
|
|
71
|
+
function getLocation({
|
|
72
|
+
history
|
|
73
|
+
}) {
|
|
74
|
+
const state = history.location.state || {};
|
|
75
|
+
return {
|
|
76
|
+
...history.location,
|
|
77
|
+
state: state.state
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function getHistoryState(router) {
|
|
81
|
+
const {
|
|
82
|
+
location
|
|
83
|
+
} = router.history;
|
|
84
|
+
const state = location.state || {};
|
|
85
|
+
return {
|
|
86
|
+
index: state.index || 0,
|
|
87
|
+
locationStack: state.locationStack || [getLocation(router)]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function getCurrentView(router) {
|
|
91
|
+
return router.viewStack[getHistoryState(router).index];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Match a path.
|
|
96
|
+
* @group Methods
|
|
97
|
+
* @category Router
|
|
98
|
+
* @param router router instance
|
|
99
|
+
* @param pathname the pathname
|
|
100
|
+
* @returns the matched result
|
|
101
|
+
*/
|
|
102
|
+
function match(router, pathname) {
|
|
103
|
+
function matchRoutes(routes, baseUrl,
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
105
|
+
pathname) {
|
|
106
|
+
for (let i = 0; i < routes.length; i++) {
|
|
107
|
+
const route = routes[i];
|
|
108
|
+
const end = !route.children;
|
|
109
|
+
const matched = route.path ? match$1(route.path, {
|
|
110
|
+
strict: true,
|
|
111
|
+
sensitive: true,
|
|
112
|
+
decode: typeof decodeURIComponent === 'function' ? decodeURIComponent : undefined,
|
|
113
|
+
end
|
|
114
|
+
})(pathname) : {
|
|
115
|
+
path: '',
|
|
116
|
+
index: 0,
|
|
117
|
+
params: {}
|
|
118
|
+
};
|
|
119
|
+
if (matched) {
|
|
120
|
+
const result = {
|
|
121
|
+
route,
|
|
122
|
+
...matched
|
|
123
|
+
};
|
|
124
|
+
if (end) return [result];
|
|
125
|
+
const children = matchRoutes(route.children, `${baseUrl}${route.path || ''}`, pathname.slice(matched.path.length));
|
|
126
|
+
if (children) return [result, ...children];
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return matchRoutes(router.routes, router.baseUrl, pathname.slice(router.baseUrl.length));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Path to Location.
|
|
137
|
+
* @group Methods
|
|
138
|
+
* @category Router
|
|
139
|
+
* @param router router instance
|
|
140
|
+
* @param to path string
|
|
141
|
+
* @param state the state of location
|
|
142
|
+
* @returns location
|
|
143
|
+
*/
|
|
144
|
+
function toLocation(router, to, state) {
|
|
145
|
+
const {
|
|
146
|
+
baseUrl
|
|
147
|
+
} = router;
|
|
148
|
+
return {
|
|
149
|
+
pathname: '',
|
|
150
|
+
search: '',
|
|
151
|
+
hash: '',
|
|
152
|
+
...parsePath(baseUrl + to),
|
|
153
|
+
state
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Resolve a location.
|
|
159
|
+
* @group Methods
|
|
160
|
+
* @category Router
|
|
161
|
+
* @param router router instance
|
|
162
|
+
* @param location history instance
|
|
163
|
+
* @returns resolve task(a promise)
|
|
164
|
+
*/
|
|
165
|
+
function resolve(router, location) {
|
|
166
|
+
const matched = match(router, location.pathname);
|
|
167
|
+
const {
|
|
168
|
+
resolveView,
|
|
169
|
+
errorHandler
|
|
170
|
+
} = router;
|
|
171
|
+
return (matched ? resolveView(matched, {
|
|
172
|
+
router,
|
|
173
|
+
location
|
|
174
|
+
}) : Promise.reject(new NotFoundError(location.pathname))).catch(errorHandler);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Resolve a path.
|
|
179
|
+
* @group Methods
|
|
180
|
+
* @category Router
|
|
181
|
+
* @param router router instance
|
|
182
|
+
* @param to the path
|
|
183
|
+
* @param state state of the path location
|
|
184
|
+
* @returns resolve task(a promise)
|
|
185
|
+
*/
|
|
186
|
+
function resolveTo(router, to, state) {
|
|
187
|
+
const location = toLocation(router, to, state);
|
|
188
|
+
return resolve(router, location);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Commit the resolve task and push history.
|
|
193
|
+
* @group Methods
|
|
194
|
+
* @category Router
|
|
195
|
+
* @param router router instance
|
|
196
|
+
* @param resolvePromise resolve task(a promise)
|
|
197
|
+
* @param location the location to resolved
|
|
198
|
+
*/
|
|
199
|
+
function commit(router, resolvePromise, location) {
|
|
200
|
+
const {
|
|
201
|
+
history
|
|
202
|
+
} = router;
|
|
203
|
+
const nextIndex = getHistoryState(router).index + 1;
|
|
204
|
+
return commitBase(router, resolvePromise, location, resolvedView => {
|
|
205
|
+
router.locationStack = [...router.locationStack.slice(0, nextIndex), location];
|
|
206
|
+
router.viewStack = [...router.viewStack.slice(0, nextIndex), resolvedView];
|
|
207
|
+
history.push(location, {
|
|
208
|
+
index: nextIndex,
|
|
209
|
+
locationStack: router.locationStack,
|
|
210
|
+
state: location.state
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Commit the resolve task and replace history.
|
|
217
|
+
* @group Methods
|
|
218
|
+
* @category Router
|
|
219
|
+
* @param router router instance
|
|
220
|
+
* @param resolvePromise resolve task(a promise)
|
|
221
|
+
* @param location the location to resolved
|
|
222
|
+
*/
|
|
223
|
+
function commitReplace(router, resolvePromise, location) {
|
|
224
|
+
const {
|
|
225
|
+
history
|
|
226
|
+
} = router;
|
|
227
|
+
const {
|
|
228
|
+
index
|
|
229
|
+
} = getHistoryState(router);
|
|
230
|
+
return commitBase(router, resolvePromise, location, resolvedView => {
|
|
231
|
+
router.locationStack[index] = location;
|
|
232
|
+
router.viewStack[index] = resolvedView;
|
|
233
|
+
history.replace(location, {
|
|
234
|
+
index,
|
|
235
|
+
locationStack: router.locationStack,
|
|
236
|
+
state: location.state
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function commitBase(router, resolvePromise, location, onResolved) {
|
|
241
|
+
const {
|
|
242
|
+
currentGuard,
|
|
243
|
+
onLoadingChange = noop
|
|
244
|
+
} = router;
|
|
245
|
+
if (router.resolving) {
|
|
246
|
+
// Cancel current resolve
|
|
247
|
+
onLoadingChange();
|
|
248
|
+
}
|
|
249
|
+
router.resolving = location;
|
|
250
|
+
onLoadingChange('pending');
|
|
251
|
+
return currentGuard(resolvePromise).then(onResolved)
|
|
252
|
+
// eslint-disable-next-line no-void
|
|
253
|
+
.then(() => void onLoadingChange('resolved')).catch(e => {
|
|
254
|
+
onLoadingChange('rejected');
|
|
255
|
+
throw e;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Navigate to a new path.
|
|
261
|
+
* @group Methods
|
|
262
|
+
* @category Router
|
|
263
|
+
* @param router router instance
|
|
264
|
+
* @param to path string
|
|
265
|
+
* @param state location state
|
|
266
|
+
*/
|
|
267
|
+
function navigate(router, to, state) {
|
|
268
|
+
const location = toLocation(router, to, state);
|
|
269
|
+
const viewPromise = resolve(router, location);
|
|
270
|
+
return commit(router, viewPromise, location);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Refresh the page.
|
|
275
|
+
* @group Methods
|
|
276
|
+
* @category Router
|
|
277
|
+
* @param router router instance
|
|
278
|
+
*/
|
|
279
|
+
function refresh(router) {
|
|
280
|
+
const location = getLocation(router);
|
|
281
|
+
const viewPromise = resolve(router, location);
|
|
282
|
+
return commitReplace(router, viewPromise, location);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Navigate in history stack.
|
|
287
|
+
* @group Methods
|
|
288
|
+
* @category Router
|
|
289
|
+
* @param router router instance
|
|
290
|
+
* @param delta history stack index
|
|
291
|
+
*/
|
|
292
|
+
function go(router, delta) {
|
|
293
|
+
router.history.go(delta);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Forward in history stack.
|
|
298
|
+
* @group Methods
|
|
299
|
+
* @category Router
|
|
300
|
+
* @param router router instance
|
|
301
|
+
*/
|
|
302
|
+
function forward(router) {
|
|
303
|
+
router.history.forward();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Back in history stack.
|
|
308
|
+
* @group Methods
|
|
309
|
+
* @category Router
|
|
310
|
+
* @param router router instance
|
|
311
|
+
*/
|
|
312
|
+
function back(router) {
|
|
313
|
+
router.history.back();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Create href of a route path. For {@link Link Link Component} hover url preview.
|
|
318
|
+
* @group Methods
|
|
319
|
+
* @category Router
|
|
320
|
+
* @param router router instance
|
|
321
|
+
* @param to route path
|
|
322
|
+
* @returns href
|
|
323
|
+
*/
|
|
324
|
+
function createHref({
|
|
325
|
+
baseUrl,
|
|
326
|
+
history
|
|
327
|
+
}, to) {
|
|
328
|
+
return baseUrl + history.createHref(to);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Cancel the current navigate.
|
|
333
|
+
* @group Methods
|
|
334
|
+
* @category Router
|
|
335
|
+
* @param router router instance
|
|
336
|
+
*/
|
|
337
|
+
function cancel({
|
|
338
|
+
cancelAll,
|
|
339
|
+
onLoadingChange = noop
|
|
340
|
+
}) {
|
|
341
|
+
cancelAll();
|
|
342
|
+
onLoadingChange();
|
|
343
|
+
}
|
|
344
|
+
function initHistoryStack(router) {
|
|
345
|
+
const {
|
|
346
|
+
history
|
|
347
|
+
} = router;
|
|
348
|
+
const {
|
|
349
|
+
locationStack
|
|
350
|
+
} = getHistoryState(router);
|
|
351
|
+
return Promise.all(locationStack.map(l => resolve(router, l))).then(views => {
|
|
352
|
+
router.viewStack = views;
|
|
353
|
+
history.replace(createPath(history.location), history.location.state);
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Listen the history change.
|
|
359
|
+
* @group Methods
|
|
360
|
+
* @category Router
|
|
361
|
+
* @param router router instance
|
|
362
|
+
* @param onViewChange a callback function will be call when view changed
|
|
363
|
+
* @returns unlisten - A function that may be used to stop listening
|
|
364
|
+
*/
|
|
365
|
+
function listen(router, onViewChange) {
|
|
366
|
+
const {
|
|
367
|
+
history
|
|
368
|
+
} = router;
|
|
369
|
+
const rmListener = history.listen(({
|
|
370
|
+
action,
|
|
371
|
+
location
|
|
372
|
+
}) => {
|
|
373
|
+
cancel(router);
|
|
374
|
+
const state = location.state;
|
|
375
|
+
const index = state?.index || 0;
|
|
376
|
+
const view = router.viewStack[index];
|
|
377
|
+
onViewChange(view);
|
|
378
|
+
if (!view) refresh(router);
|
|
379
|
+
if (action === 'POP') {
|
|
380
|
+
history.replace(createPath(history.location), {
|
|
381
|
+
...state,
|
|
382
|
+
locationStack: router.locationStack
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
history.replace(createPath(history.location), history.location.state);
|
|
387
|
+
return () => {
|
|
388
|
+
cancel(router);
|
|
389
|
+
rmListener();
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export { NativeRouterError, NotFoundError, back, cancel, commit, commitReplace, create, createHref, forward, getCurrentView, getLocation, go, initHistoryStack, listen, match, navigate, refresh, resolve, resolveTo, setOptions, toLocation };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { History } from 'history';
|
|
2
|
+
import type { Location, Matched, Options, BaseRoute, RouterInstance, ResolveView } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Create a router instance.
|
|
5
|
+
* @group Methods
|
|
6
|
+
* @category Router
|
|
7
|
+
* @param routes routes config
|
|
8
|
+
* @param history {@link https://www.npmjs.com/package/history history} instance
|
|
9
|
+
* @param resolveView a callback to resolve view. see {@link defaultResolveView}
|
|
10
|
+
* @param options options
|
|
11
|
+
* @returns a router instance
|
|
12
|
+
*/
|
|
13
|
+
export declare function create<R extends BaseRoute = BaseRoute, V = any>(routes: R | R[], history: History, resolveView: ResolveView<R, V>, options?: Options<V>): RouterInstance<R, V>;
|
|
14
|
+
export declare function setOptions<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, options: Omit<Options<V>, 'currentView'>): {
|
|
15
|
+
routes: R[];
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
history: History & {
|
|
18
|
+
location: import("./types").WrappedLocation;
|
|
19
|
+
};
|
|
20
|
+
viewStack: V[];
|
|
21
|
+
locationStack: Location<any>[];
|
|
22
|
+
resolveView: ResolveView<R, V>;
|
|
23
|
+
currentGuard<T>(promise: Promise<T>): Promise<T>;
|
|
24
|
+
cancelAll(): void;
|
|
25
|
+
resolving?: Location<any> | undefined;
|
|
26
|
+
} & Required<Pick<Options<V>, "baseUrl">> & Omit<Options<V>, "baseUrl"> & Omit<Options<V>, "currentView">;
|
|
27
|
+
export declare function getLocation({ history }: Pick<RouterInstance<any>, 'history'>): {
|
|
28
|
+
state: any;
|
|
29
|
+
key: string;
|
|
30
|
+
pathname: string;
|
|
31
|
+
search: string;
|
|
32
|
+
hash: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function getCurrentView<R extends BaseRoute = BaseRoute>(router: RouterInstance<R>): any;
|
|
35
|
+
/**
|
|
36
|
+
* Match a path.
|
|
37
|
+
* @group Methods
|
|
38
|
+
* @category Router
|
|
39
|
+
* @param router router instance
|
|
40
|
+
* @param pathname the pathname
|
|
41
|
+
* @returns the matched result
|
|
42
|
+
*/
|
|
43
|
+
export declare function match<R extends BaseRoute = BaseRoute>(router: RouterInstance<R>, pathname: string): Matched<R>[] | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Path to Location.
|
|
46
|
+
* @group Methods
|
|
47
|
+
* @category Router
|
|
48
|
+
* @param router router instance
|
|
49
|
+
* @param to path string
|
|
50
|
+
* @param state the state of location
|
|
51
|
+
* @returns location
|
|
52
|
+
*/
|
|
53
|
+
export declare function toLocation<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, to: string, state?: any): Location;
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a location.
|
|
56
|
+
* @group Methods
|
|
57
|
+
* @category Router
|
|
58
|
+
* @param router router instance
|
|
59
|
+
* @param location history instance
|
|
60
|
+
* @returns resolve task(a promise)
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolve<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, location: Location): Promise<V>;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a path.
|
|
65
|
+
* @group Methods
|
|
66
|
+
* @category Router
|
|
67
|
+
* @param router router instance
|
|
68
|
+
* @param to the path
|
|
69
|
+
* @param state state of the path location
|
|
70
|
+
* @returns resolve task(a promise)
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveTo<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, to: string, state?: any): Promise<V>;
|
|
73
|
+
/**
|
|
74
|
+
* Commit the resolve task and push history.
|
|
75
|
+
* @group Methods
|
|
76
|
+
* @category Router
|
|
77
|
+
* @param router router instance
|
|
78
|
+
* @param resolvePromise resolve task(a promise)
|
|
79
|
+
* @param location the location to resolved
|
|
80
|
+
*/
|
|
81
|
+
export declare function commit<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, resolvePromise: Promise<V>, location: Location): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Commit the resolve task and replace history.
|
|
84
|
+
* @group Methods
|
|
85
|
+
* @category Router
|
|
86
|
+
* @param router router instance
|
|
87
|
+
* @param resolvePromise resolve task(a promise)
|
|
88
|
+
* @param location the location to resolved
|
|
89
|
+
*/
|
|
90
|
+
export declare function commitReplace<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, resolvePromise: Promise<V>, location: Location): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Navigate to a new path.
|
|
93
|
+
* @group Methods
|
|
94
|
+
* @category Router
|
|
95
|
+
* @param router router instance
|
|
96
|
+
* @param to path string
|
|
97
|
+
* @param state location state
|
|
98
|
+
*/
|
|
99
|
+
export declare function navigate<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, to: string, state?: any): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Refresh the page.
|
|
102
|
+
* @group Methods
|
|
103
|
+
* @category Router
|
|
104
|
+
* @param router router instance
|
|
105
|
+
*/
|
|
106
|
+
export declare function refresh<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Navigate in history stack.
|
|
109
|
+
* @group Methods
|
|
110
|
+
* @category Router
|
|
111
|
+
* @param router router instance
|
|
112
|
+
* @param delta history stack index
|
|
113
|
+
*/
|
|
114
|
+
export declare function go<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, delta: number): void;
|
|
115
|
+
/**
|
|
116
|
+
* Forward in history stack.
|
|
117
|
+
* @group Methods
|
|
118
|
+
* @category Router
|
|
119
|
+
* @param router router instance
|
|
120
|
+
*/
|
|
121
|
+
export declare function forward<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>): void;
|
|
122
|
+
/**
|
|
123
|
+
* Back in history stack.
|
|
124
|
+
* @group Methods
|
|
125
|
+
* @category Router
|
|
126
|
+
* @param router router instance
|
|
127
|
+
*/
|
|
128
|
+
export declare function back<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>): void;
|
|
129
|
+
/**
|
|
130
|
+
* Create href of a route path. For {@link Link Link Component} hover url preview.
|
|
131
|
+
* @group Methods
|
|
132
|
+
* @category Router
|
|
133
|
+
* @param router router instance
|
|
134
|
+
* @param to route path
|
|
135
|
+
* @returns href
|
|
136
|
+
*/
|
|
137
|
+
export declare function createHref<R extends BaseRoute = BaseRoute, V = any>({ baseUrl, history }: RouterInstance<R, V>, to: string): string;
|
|
138
|
+
/**
|
|
139
|
+
* Cancel the current navigate.
|
|
140
|
+
* @group Methods
|
|
141
|
+
* @category Router
|
|
142
|
+
* @param router router instance
|
|
143
|
+
*/
|
|
144
|
+
export declare function cancel<R extends BaseRoute = BaseRoute, V = any>({ cancelAll, onLoadingChange }: RouterInstance<R, V>): void;
|
|
145
|
+
export declare function initHistoryStack<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Listen the history change.
|
|
148
|
+
* @group Methods
|
|
149
|
+
* @category Router
|
|
150
|
+
* @param router router instance
|
|
151
|
+
* @param onViewChange a callback function will be call when view changed
|
|
152
|
+
* @returns unlisten - A function that may be used to stop listening
|
|
153
|
+
*/
|
|
154
|
+
export declare function listen<R extends BaseRoute = BaseRoute, V = any>(router: RouterInstance<R, V>, onViewChange: (v: V) => void): () => void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Path, MatchResult } from 'path-to-regexp';
|
|
2
|
+
import type { History, Path as HPath } from 'history';
|
|
3
|
+
import type { AnchorHTMLAttributes, ComponentType, Context as ReactContext, DetailedHTMLProps, ReactNode } from 'react';
|
|
4
|
+
export type Location<T = any> = HPath & {
|
|
5
|
+
state?: T;
|
|
6
|
+
};
|
|
7
|
+
export type HistoryState = {
|
|
8
|
+
locationStack: Location[];
|
|
9
|
+
index: number;
|
|
10
|
+
state?: any;
|
|
11
|
+
};
|
|
12
|
+
export type WrappedLocation = Location<HistoryState>;
|
|
13
|
+
export type Awaitable<T> = T | Promise<T>;
|
|
14
|
+
export type BaseRoute<T = any> = {
|
|
15
|
+
path?: Path;
|
|
16
|
+
children?: BaseRoute<T>[];
|
|
17
|
+
} & Omit<T, 'path' | 'children'>;
|
|
18
|
+
export type Matched<R extends BaseRoute = BaseRoute> = {
|
|
19
|
+
route: R;
|
|
20
|
+
} & MatchResult<Record<string, string>>;
|
|
21
|
+
export type ResolveViewContext<R extends BaseRoute> = {
|
|
22
|
+
router: RouterInstance<R>;
|
|
23
|
+
location: Location;
|
|
24
|
+
};
|
|
25
|
+
export type ResolveView<R extends BaseRoute, V> = (matched: Matched<R>[], ctx: ResolveViewContext<R>) => Promise<V>;
|
|
26
|
+
export type Options<V> = {
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
currentView?: V;
|
|
29
|
+
errorHandler?(e: Error): V | Promise<V>;
|
|
30
|
+
onLoadingChange?(status?: 'pending' | 'resolved' | 'rejected'): void;
|
|
31
|
+
};
|
|
32
|
+
export type RequiredOf<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
|
|
33
|
+
export type RouterInstance<R extends BaseRoute, V = any> = {
|
|
34
|
+
routes: R[];
|
|
35
|
+
baseUrl: string;
|
|
36
|
+
history: History & {
|
|
37
|
+
location: WrappedLocation;
|
|
38
|
+
};
|
|
39
|
+
viewStack: V[];
|
|
40
|
+
locationStack: Location[];
|
|
41
|
+
resolveView: ResolveView<R, V>;
|
|
42
|
+
currentGuard<T>(promise: Promise<T>): Promise<T>;
|
|
43
|
+
cancelAll(): void;
|
|
44
|
+
resolving?: Location;
|
|
45
|
+
} & RequiredOf<Options<V>, 'baseUrl'>;
|
|
46
|
+
export type Context<T extends BaseRoute> = {
|
|
47
|
+
matched: Matched<T>[];
|
|
48
|
+
index: number;
|
|
49
|
+
router: RouterInstance<BaseRoute>;
|
|
50
|
+
location: Location;
|
|
51
|
+
params: Record<string, string>;
|
|
52
|
+
};
|
|
53
|
+
export type Route = BaseRoute<{
|
|
54
|
+
name?: string;
|
|
55
|
+
data?(ctx: Context<Route>): any | Promise<any>;
|
|
56
|
+
component?(ctx: Context<Route>): ComponentType | Promise<ComponentType | {
|
|
57
|
+
default: ComponentType;
|
|
58
|
+
}>;
|
|
59
|
+
}>;
|
|
60
|
+
export type StateContext<S> = {
|
|
61
|
+
SetterContext: ReactContext<((v: S) => void) | undefined>;
|
|
62
|
+
ValueContext: ReactContext<S | undefined>;
|
|
63
|
+
Provider: ComponentType<{
|
|
64
|
+
children: ReactNode;
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
export type LoadStatus = {
|
|
68
|
+
key: number;
|
|
69
|
+
status: 'pending' | 'resolved' | 'rejected';
|
|
70
|
+
};
|
|
71
|
+
export type LinkProps = {
|
|
72
|
+
to: string;
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
} & DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function uniqId(): number;
|
|
2
|
+
export declare function noop(): void;
|
|
3
|
+
export declare const resolve: {
|
|
4
|
+
(): Promise<void>;
|
|
5
|
+
<T>(value: T): Promise<Awaited<T>>;
|
|
6
|
+
<T_1>(value: T_1 | PromiseLike<T_1>): Promise<Awaited<T_1>>;
|
|
7
|
+
};
|
|
8
|
+
export declare const reject: <T = never>(reason?: any) => Promise<T>;
|
|
9
|
+
export declare function cancelPromise(): Promise<unknown>;
|
|
10
|
+
export declare function createCurrentGuard(): readonly [<T>(promise: Promise<T>) => Promise<T>, () => void];
|
|
11
|
+
export declare function splitProps<T extends object = object, K extends keyof T = keyof T>(obj: T, keys: K[]): [Pick<T, K>, Omit<T, K>];
|
|
12
|
+
export declare function isString(maybeString: unknown): maybeString is string;
|
package/package.json
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@native-router/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"import": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/types/index.d.ts"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"react",
|
|
13
|
+
"router",
|
|
14
|
+
"react router",
|
|
15
|
+
"react-router",
|
|
16
|
+
"async",
|
|
17
|
+
"tiny",
|
|
18
|
+
"data-fetching",
|
|
19
|
+
"prefetch",
|
|
20
|
+
"preview"
|
|
21
|
+
],
|
|
22
|
+
"description": "A route close to the native experience for react.",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"start": "npm test -- --watch",
|
|
28
|
+
"build": "rm -rf dist && rollup -c && tsc -p tsconfig.production.json && tsc-alias -p tsconfig.production.json",
|
|
29
|
+
"commit": "lint-staged && git-cz -n",
|
|
30
|
+
"coverage": "nyc report --reporter=text-lcov > ./.nyc_output/coverage.txt",
|
|
31
|
+
"lint": "eslint --fix src test demos *.js --ext .js,.jsx,.ts,.tsx",
|
|
32
|
+
"doc:gen": "typedoc",
|
|
33
|
+
"deploy": "npm run doc:gen && npm run build:demo && gh-pages -d dist",
|
|
34
|
+
"test": "cross-env NODE_ENV=test nyc mocha",
|
|
35
|
+
"preversion": "npm run build",
|
|
36
|
+
"postversion": "npm publish",
|
|
37
|
+
"postpublish": "git push --follow-tags && npm run deploy"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/wmzy/@native-router/core"
|
|
42
|
+
},
|
|
43
|
+
"sideEffects": false,
|
|
44
|
+
"author": "wmzy",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/wmzy/@native-router/core/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/wmzy/@native-router/core",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=14"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"react": "^17.0.0 || ^18.0.0",
|
|
55
|
+
"react-dom": "^17.0.0 || ^18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"history": "^5.3.0",
|
|
59
|
+
"path-to-regexp": "^6.2.1"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@babel/core": "^7.22.9",
|
|
63
|
+
"@babel/preset-env": "^7.22.9",
|
|
64
|
+
"@babel/preset-react": "^7.22.5",
|
|
65
|
+
"@babel/preset-typescript": "^7.22.5",
|
|
66
|
+
"@babel/register": "^7.22.5",
|
|
67
|
+
"@linaria/babel-preset": "^4.5.4",
|
|
68
|
+
"@linaria/core": "^4.5.4",
|
|
69
|
+
"@rollup/plugin-babel": "^6.0.3",
|
|
70
|
+
"@rollup/plugin-commonjs": "^25.0.4",
|
|
71
|
+
"@rollup/plugin-node-resolve": "^15.1.0",
|
|
72
|
+
"@rollup/plugin-replace": "^5.0.2",
|
|
73
|
+
"@types/mocha": "^10.0.1",
|
|
74
|
+
"@types/node": "^20.4.5",
|
|
75
|
+
"@types/react": "^18.2.16",
|
|
76
|
+
"@types/react-dom": "^18.2.7",
|
|
77
|
+
"@types/sinon": "^10.0.15",
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
|
79
|
+
"@typescript-eslint/parser": "^6.2.0",
|
|
80
|
+
"@vitejs/plugin-react": "^4.0.3",
|
|
81
|
+
"babel-plugin-module-resolver": "^5.0.0",
|
|
82
|
+
"commitizen": "^4.3.0",
|
|
83
|
+
"core-js": "^3.31.1",
|
|
84
|
+
"coveralls": "^3.1.1",
|
|
85
|
+
"cross-env": "^7.0.3",
|
|
86
|
+
"eslint": "^8.45.0",
|
|
87
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
88
|
+
"eslint-config-airbnb-typescript": "^17.1.0",
|
|
89
|
+
"eslint-config-prettier": "^8.8.0",
|
|
90
|
+
"eslint-import-resolver-typescript": "^3.5.5",
|
|
91
|
+
"eslint-plugin-compat": "^4.1.4",
|
|
92
|
+
"eslint-plugin-import": "^2.27.5",
|
|
93
|
+
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
94
|
+
"eslint-plugin-mocha": "^10.1.0",
|
|
95
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
96
|
+
"eslint-plugin-react": "^7.33.0",
|
|
97
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
98
|
+
"gh-pages": "^5.0.0",
|
|
99
|
+
"global-jsdom": "^9.0.1",
|
|
100
|
+
"husky": "^8.0.3",
|
|
101
|
+
"jsdom": "^22.1.0",
|
|
102
|
+
"lint-staged": "^13.2.3",
|
|
103
|
+
"mocha": "^10.2.0",
|
|
104
|
+
"nyc": "^15.1.0",
|
|
105
|
+
"prettier": "^3.0.0",
|
|
106
|
+
"react": "^18.2.0",
|
|
107
|
+
"react-dom": "^18.2.0",
|
|
108
|
+
"rollup": "^3.28.0",
|
|
109
|
+
"should": "^13.2.3",
|
|
110
|
+
"should-sinon": "0.0.6",
|
|
111
|
+
"sinon": "^15.2.0",
|
|
112
|
+
"terser": "^5.19.2",
|
|
113
|
+
"tsc-alias": "^1.8.7",
|
|
114
|
+
"typedoc": "^0.24.8",
|
|
115
|
+
"typedoc-plugin-mark-react-functional-components": "^0.2.2",
|
|
116
|
+
"typedoc-plugin-missing-exports": "^2.0.0",
|
|
117
|
+
"typescript": "^5.1.6"
|
|
118
|
+
}
|
|
119
|
+
}
|