@viewfly/router 2.1.0 → 3.0.0-alpha.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 +58 -112
- package/dist/hooks/_api.d.ts +1 -0
- package/dist/hooks/use-query-params.d.ts +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.esm.js +479 -0
- package/dist/index.js +494 -0
- package/dist/link.d.ts +12 -0
- package/dist/providers/_api.d.ts +3 -0
- package/dist/providers/navigator.d.ts +56 -0
- package/dist/providers/router.d.ts +28 -0
- package/dist/providers/url-parser.d.ts +38 -0
- package/dist/router-module.d.ts +10 -0
- package/dist/router-outlet.d.ts +6 -0
- package/package.json +27 -20
- package/bundles/index.d.ts +0 -151
- package/bundles/index.esm.js +0 -674
- package/bundles/index.js +0 -684
- package/rollup-d.config.ts +0 -14
package/dist/index.js
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _viewfly_core = require("@viewfly/core");
|
|
3
|
+
let _tanbo_stream = require("@tanbo/stream");
|
|
4
|
+
//#region src/providers/router.ts
|
|
5
|
+
var routerErrorFn$1 = (0, _viewfly_core.makeError)("Router");
|
|
6
|
+
var Router = class {
|
|
7
|
+
onRefresh;
|
|
8
|
+
get deep() {
|
|
9
|
+
return this.parent ? this.parent.deep + 1 : 0;
|
|
10
|
+
}
|
|
11
|
+
get path() {
|
|
12
|
+
return this.navigator.urlTree.paths.at(this.deep) || "";
|
|
13
|
+
}
|
|
14
|
+
refreshEvent = new _tanbo_stream.Subject();
|
|
15
|
+
constructor(navigator, parent) {
|
|
16
|
+
this.navigator = navigator;
|
|
17
|
+
this.parent = parent;
|
|
18
|
+
this.onRefresh = this.refreshEvent.asObservable();
|
|
19
|
+
}
|
|
20
|
+
navigateTo(path, params, fragment) {
|
|
21
|
+
this.navigator.to(path, this, params, fragment || void 0);
|
|
22
|
+
}
|
|
23
|
+
replaceTo(path, params) {
|
|
24
|
+
this.navigator.replace(path, this, params);
|
|
25
|
+
}
|
|
26
|
+
refresh() {
|
|
27
|
+
this.refreshEvent.next();
|
|
28
|
+
}
|
|
29
|
+
consumeConfig(routes) {
|
|
30
|
+
return this.matchRoute(routes, this.path);
|
|
31
|
+
}
|
|
32
|
+
back() {
|
|
33
|
+
this.navigator.back();
|
|
34
|
+
}
|
|
35
|
+
forward() {
|
|
36
|
+
this.navigator.forward();
|
|
37
|
+
}
|
|
38
|
+
go(offset) {
|
|
39
|
+
this.navigator.go(offset);
|
|
40
|
+
}
|
|
41
|
+
matchRoute(configs, pathname) {
|
|
42
|
+
let matchedConfig = null;
|
|
43
|
+
let defaultConfig = null;
|
|
44
|
+
let fallbackConfig = null;
|
|
45
|
+
for (const item of configs) if (item.path === pathname) {
|
|
46
|
+
matchedConfig = item;
|
|
47
|
+
break;
|
|
48
|
+
} else if (item.path === "*") {
|
|
49
|
+
if (!fallbackConfig) fallbackConfig = item;
|
|
50
|
+
} else if (item.path === "") {
|
|
51
|
+
if (!defaultConfig) defaultConfig = item;
|
|
52
|
+
}
|
|
53
|
+
const config = matchedConfig || defaultConfig || fallbackConfig;
|
|
54
|
+
if (!config) return config;
|
|
55
|
+
if (typeof config.redirectTo === "function") {
|
|
56
|
+
const p = config.redirectTo(pathname);
|
|
57
|
+
if (typeof p === "string") this.navigateTo(p);
|
|
58
|
+
else if (typeof p === "object") this.navigateTo(p.pathname, p.queryParams, p.fragment);
|
|
59
|
+
else throw routerErrorFn$1(`Router redirect to '${pathname}' not supported`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (typeof config.redirectTo === "string") {
|
|
63
|
+
this.navigateTo(config.redirectTo);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return config;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/providers/url-parser.ts
|
|
71
|
+
var UrlParser = class {
|
|
72
|
+
index = 0;
|
|
73
|
+
url = "";
|
|
74
|
+
tokens = [];
|
|
75
|
+
parse(url) {
|
|
76
|
+
this.index = 0;
|
|
77
|
+
this.url = url;
|
|
78
|
+
this.tokens = [];
|
|
79
|
+
while (this.index < this.url.length) {
|
|
80
|
+
this.ignore("/");
|
|
81
|
+
if (this.peek("../")) {
|
|
82
|
+
this.tokens.push({ type: "toParent" });
|
|
83
|
+
this.index += 3;
|
|
84
|
+
} else if (this.peek("?")) {
|
|
85
|
+
this.index++;
|
|
86
|
+
this.tokens.push({
|
|
87
|
+
type: "query",
|
|
88
|
+
params: this.readQuery()
|
|
89
|
+
});
|
|
90
|
+
} else if (this.peek("#")) {
|
|
91
|
+
this.index++;
|
|
92
|
+
this.tokens.push({
|
|
93
|
+
type: "hash",
|
|
94
|
+
value: this.readHash()
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
if (this.peek("./")) this.index += 2;
|
|
98
|
+
const path = this.readPath();
|
|
99
|
+
if (path) this.tokens.push({
|
|
100
|
+
type: "toChild",
|
|
101
|
+
value: path
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const urlTree = {
|
|
106
|
+
paths: [],
|
|
107
|
+
queryParams: {},
|
|
108
|
+
hash: null
|
|
109
|
+
};
|
|
110
|
+
for (const item of this.tokens) switch (item.type) {
|
|
111
|
+
case "toParent":
|
|
112
|
+
urlTree.paths.pop();
|
|
113
|
+
break;
|
|
114
|
+
case "toChild":
|
|
115
|
+
urlTree.paths.push(item.value);
|
|
116
|
+
break;
|
|
117
|
+
case "query":
|
|
118
|
+
urlTree.queryParams = item.params;
|
|
119
|
+
break;
|
|
120
|
+
case "hash": urlTree.hash = item.value;
|
|
121
|
+
}
|
|
122
|
+
return urlTree;
|
|
123
|
+
}
|
|
124
|
+
readHash() {
|
|
125
|
+
const hash = this.url.substring(this.index);
|
|
126
|
+
this.index = this.url.length;
|
|
127
|
+
return hash;
|
|
128
|
+
}
|
|
129
|
+
readQuery() {
|
|
130
|
+
const query = {};
|
|
131
|
+
while (this.index < this.url.length) {
|
|
132
|
+
const key = this.readQueryKey();
|
|
133
|
+
let value = "";
|
|
134
|
+
if (this.peek("=")) {
|
|
135
|
+
this.index++;
|
|
136
|
+
value = this.readQueryValue();
|
|
137
|
+
}
|
|
138
|
+
const oldValue = query[key];
|
|
139
|
+
if (oldValue) if (Array.isArray(oldValue)) oldValue.push(value);
|
|
140
|
+
else query[key] = [oldValue, value];
|
|
141
|
+
else query[key] = value;
|
|
142
|
+
if (this.peek("&")) {
|
|
143
|
+
this.index++;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
return query;
|
|
149
|
+
}
|
|
150
|
+
readQueryValue() {
|
|
151
|
+
const chars = [];
|
|
152
|
+
while (this.index < this.url.length) {
|
|
153
|
+
if (this.not("&#")) {
|
|
154
|
+
chars.push(this.url.at(this.index));
|
|
155
|
+
this.index++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
return chars.join("");
|
|
161
|
+
}
|
|
162
|
+
readQueryKey() {
|
|
163
|
+
const chars = [];
|
|
164
|
+
while (this.index < this.url.length) {
|
|
165
|
+
if (this.not("=&#")) {
|
|
166
|
+
chars.push(this.url.at(this.index));
|
|
167
|
+
this.index++;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
return chars.join("");
|
|
173
|
+
}
|
|
174
|
+
readPath() {
|
|
175
|
+
const chars = [];
|
|
176
|
+
while (this.index < this.url.length) {
|
|
177
|
+
if (this.not("./?#")) {
|
|
178
|
+
chars.push(this.url.at(this.index));
|
|
179
|
+
this.index++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
return chars.join("");
|
|
185
|
+
}
|
|
186
|
+
not(text) {
|
|
187
|
+
const ch = this.url.at(this.index);
|
|
188
|
+
return text.indexOf(ch) === -1;
|
|
189
|
+
}
|
|
190
|
+
peek(str) {
|
|
191
|
+
return this.url.slice(this.index, this.index + str.length) === str;
|
|
192
|
+
}
|
|
193
|
+
ignore(str) {
|
|
194
|
+
while (this.peek(str)) this.index++;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region \0@oxc-project+runtime@0.126.0/helpers/decorateMetadata.js
|
|
199
|
+
function __decorateMetadata(k, v) {
|
|
200
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region \0@oxc-project+runtime@0.126.0/helpers/decorate.js
|
|
204
|
+
function __decorate(decorators, target, key, desc) {
|
|
205
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
206
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
207
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
208
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/providers/navigator.ts
|
|
212
|
+
var Navigator = class {
|
|
213
|
+
constructor(baseUrl) {
|
|
214
|
+
this.baseUrl = baseUrl;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
function formatUrl(pathname, urlFormatParams) {
|
|
218
|
+
pathname = pathname.replace(/\/+/g, "/");
|
|
219
|
+
const { queryParams, fragment } = urlFormatParams;
|
|
220
|
+
return pathname + (queryParams ? "?" + formatQueryParams(queryParams) : "") + (fragment ? "#" + fragment : "");
|
|
221
|
+
}
|
|
222
|
+
function formatQueryParams(queryParams) {
|
|
223
|
+
const params = [];
|
|
224
|
+
Object.keys(queryParams).forEach((key) => {
|
|
225
|
+
const values = queryParams[key];
|
|
226
|
+
if (Array.isArray(values)) values.forEach((i) => {
|
|
227
|
+
params.push(`${key}=${decodeURIComponent(i)}`);
|
|
228
|
+
});
|
|
229
|
+
else params.push(`${key}=${decodeURIComponent(values)}`);
|
|
230
|
+
});
|
|
231
|
+
return params.join("&");
|
|
232
|
+
}
|
|
233
|
+
var BrowserNavigator = class BrowserNavigator extends Navigator {
|
|
234
|
+
onUrlChanged;
|
|
235
|
+
/** 挂载在 location 上的路径前缀;'' 或 '/' 表示站点根,不做剥离 */
|
|
236
|
+
get basePathPrefix() {
|
|
237
|
+
return this.baseUrl === "/" || this.baseUrl === "" ? "" : this.baseUrl;
|
|
238
|
+
}
|
|
239
|
+
get pathname() {
|
|
240
|
+
const pathname = location.pathname;
|
|
241
|
+
if (!this.basePathPrefix) return pathname;
|
|
242
|
+
return pathname.startsWith(this.basePathPrefix) ? pathname.substring(this.basePathPrefix.length) : pathname;
|
|
243
|
+
}
|
|
244
|
+
urlParser = new UrlParser();
|
|
245
|
+
urlTree = this.getUrlTree();
|
|
246
|
+
urlChangeEvent = new _tanbo_stream.Subject();
|
|
247
|
+
subscription = new _tanbo_stream.Subscription();
|
|
248
|
+
constructor(baseUrl, hooks = {}) {
|
|
249
|
+
super(baseUrl);
|
|
250
|
+
this.hooks = hooks;
|
|
251
|
+
this.onUrlChanged = this.urlChangeEvent.asObservable();
|
|
252
|
+
this.subscription.add((0, _tanbo_stream.fromEvent)(window, "popstate").subscribe(() => {
|
|
253
|
+
this.urlTree = this.getUrlTree();
|
|
254
|
+
this.urlChangeEvent.next();
|
|
255
|
+
}));
|
|
256
|
+
if (this.basePathPrefix && !location.pathname.startsWith(this.basePathPrefix)) history.replaceState(null, "", this.baseUrl);
|
|
257
|
+
}
|
|
258
|
+
to(pathName, relative, queryParams, fragment) {
|
|
259
|
+
const url = this.join(pathName, relative, queryParams, fragment);
|
|
260
|
+
if (location.origin + url === location.href) return true;
|
|
261
|
+
this.runHooks({
|
|
262
|
+
pathname: this.pathname,
|
|
263
|
+
queryParams: this.urlTree.queryParams,
|
|
264
|
+
fragment: this.urlTree.hash
|
|
265
|
+
}, {
|
|
266
|
+
pathname: pathName,
|
|
267
|
+
queryParams: queryParams || {},
|
|
268
|
+
fragment: fragment || null
|
|
269
|
+
}, () => {
|
|
270
|
+
history.pushState(null, "", url);
|
|
271
|
+
this.urlTree = this.getUrlTree();
|
|
272
|
+
this.urlChangeEvent.next();
|
|
273
|
+
});
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
replace(pathName, relative, queryParams, fragment) {
|
|
277
|
+
const url = this.join(pathName, relative, queryParams, fragment);
|
|
278
|
+
if (location.origin + url === location.href) return true;
|
|
279
|
+
this.runHooks({
|
|
280
|
+
pathname: this.pathname,
|
|
281
|
+
queryParams: this.urlTree.queryParams,
|
|
282
|
+
fragment: this.urlTree.hash
|
|
283
|
+
}, {
|
|
284
|
+
pathname: pathName,
|
|
285
|
+
queryParams: queryParams || {},
|
|
286
|
+
fragment: fragment || null
|
|
287
|
+
}, () => {
|
|
288
|
+
history.replaceState(null, "", url);
|
|
289
|
+
this.urlTree = this.getUrlTree();
|
|
290
|
+
this.urlChangeEvent.next();
|
|
291
|
+
});
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
join(pathname, relative, queryParams, fragment) {
|
|
295
|
+
if (pathname.startsWith("/")) return formatUrl(this.baseUrl + pathname, {
|
|
296
|
+
queryParams,
|
|
297
|
+
fragment
|
|
298
|
+
});
|
|
299
|
+
const beforePath = this.urlTree.paths.slice(0, relative.deep);
|
|
300
|
+
while (true) {
|
|
301
|
+
if (pathname.startsWith("./")) {
|
|
302
|
+
pathname = pathname.substring(2);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (pathname.startsWith("../")) {
|
|
306
|
+
pathname = pathname.substring(3);
|
|
307
|
+
beforePath.pop();
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
return formatUrl(this.baseUrl + "/" + beforePath.join("/") + "/" + pathname, {
|
|
313
|
+
queryParams,
|
|
314
|
+
fragment
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
back() {
|
|
318
|
+
history.back();
|
|
319
|
+
}
|
|
320
|
+
forward() {
|
|
321
|
+
history.forward();
|
|
322
|
+
}
|
|
323
|
+
go(offset) {
|
|
324
|
+
history.go(offset);
|
|
325
|
+
}
|
|
326
|
+
destroy() {
|
|
327
|
+
this.subscription.unsubscribe();
|
|
328
|
+
}
|
|
329
|
+
runHooks(beforeParams, currentParams, next) {
|
|
330
|
+
if (typeof this.hooks.beforeEach === "function") this.hooks.beforeEach?.(beforeParams, currentParams, () => {
|
|
331
|
+
next();
|
|
332
|
+
this.hooks.afterEach?.(currentParams);
|
|
333
|
+
});
|
|
334
|
+
else {
|
|
335
|
+
next();
|
|
336
|
+
this.hooks.afterEach?.(currentParams);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
getUrlTree() {
|
|
340
|
+
return this.urlParser.parse(this.pathname + location.search + location.hash);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
BrowserNavigator = __decorate([(0, _viewfly_core.Injectable)(), __decorateMetadata("design:paramtypes", [String, Object])], BrowserNavigator);
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/hooks/use-query-params.ts
|
|
346
|
+
function useQueryParams() {
|
|
347
|
+
const router = (0, _viewfly_core.inject)(Router);
|
|
348
|
+
const navigator = (0, _viewfly_core.inject)(Navigator);
|
|
349
|
+
const params = { ...navigator.urlTree.queryParams };
|
|
350
|
+
const queryParams = new Proxy(params, _viewfly_core.readonlyProxyHandler);
|
|
351
|
+
const subscription = router.onRefresh.subscribe(() => {
|
|
352
|
+
(0, _viewfly_core.comparePropsWithCallbacks)(params, navigator.urlTree.queryParams, (key) => {
|
|
353
|
+
(0, _viewfly_core.internalWrite)(() => {
|
|
354
|
+
Reflect.deleteProperty(params, key);
|
|
355
|
+
});
|
|
356
|
+
}, (key, value) => {
|
|
357
|
+
(0, _viewfly_core.internalWrite)(() => {
|
|
358
|
+
params[key] = value;
|
|
359
|
+
});
|
|
360
|
+
}, (key, value) => {
|
|
361
|
+
(0, _viewfly_core.internalWrite)(() => {
|
|
362
|
+
params[key] = value;
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
(0, _viewfly_core.onUnmounted)(() => {
|
|
367
|
+
subscription.unsubscribe();
|
|
368
|
+
});
|
|
369
|
+
return queryParams;
|
|
370
|
+
}
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/link.tsx
|
|
373
|
+
function Link(props) {
|
|
374
|
+
const navigator = (0, _viewfly_core.inject)(Navigator);
|
|
375
|
+
const router = (0, _viewfly_core.inject)(Router);
|
|
376
|
+
function getActive() {
|
|
377
|
+
return props.exact ? navigator.pathname === navigator.join(props.to, router) || navigator.pathname + "/" === navigator.join(props.to, router) : navigator.pathname.startsWith(navigator.join(props.to, router));
|
|
378
|
+
}
|
|
379
|
+
const isActive = (0, _viewfly_core.reactive)({ value: getActive() });
|
|
380
|
+
const subscription = navigator.onUrlChanged.subscribe(() => {
|
|
381
|
+
isActive.value = getActive();
|
|
382
|
+
});
|
|
383
|
+
(0, _viewfly_core.onUnmounted)(() => {
|
|
384
|
+
subscription.unsubscribe();
|
|
385
|
+
});
|
|
386
|
+
function navigate(ev) {
|
|
387
|
+
if ((!props.tag || props.tag === "a") && props.target === "_blank") return;
|
|
388
|
+
ev.preventDefault();
|
|
389
|
+
router.navigateTo(props.to, props.queryParams, props.fragment);
|
|
390
|
+
}
|
|
391
|
+
return () => {
|
|
392
|
+
const Tag = props.tag || "a";
|
|
393
|
+
const attrs = Object.assign({}, props, {
|
|
394
|
+
onClick(ev) {
|
|
395
|
+
navigate(ev);
|
|
396
|
+
props.onClick?.(ev);
|
|
397
|
+
},
|
|
398
|
+
...props
|
|
399
|
+
});
|
|
400
|
+
if (Tag === "a") attrs.href = navigator.join(props.to, router, props.queryParams, props.fragment);
|
|
401
|
+
if (isActive.value && props.active) attrs.class = [attrs.class, props.active];
|
|
402
|
+
return /* @__PURE__ */ (0, _viewfly_core.jsx)(Tag, {
|
|
403
|
+
...attrs,
|
|
404
|
+
children: props.children
|
|
405
|
+
});
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region src/router-module.ts
|
|
410
|
+
var RouterModule = class {
|
|
411
|
+
subscription = new _tanbo_stream.Subscription();
|
|
412
|
+
navigator;
|
|
413
|
+
constructor(baseUrl = "", hooks = {}) {
|
|
414
|
+
this.baseUrl = baseUrl;
|
|
415
|
+
this.navigator = new BrowserNavigator(this.baseUrl, hooks);
|
|
416
|
+
}
|
|
417
|
+
setup(app) {
|
|
418
|
+
const navigator = this.navigator;
|
|
419
|
+
const router = new Router(navigator, null);
|
|
420
|
+
this.subscription.add(navigator.onUrlChanged.subscribe(() => {
|
|
421
|
+
router.refresh();
|
|
422
|
+
}));
|
|
423
|
+
app.provide([{
|
|
424
|
+
provide: Navigator,
|
|
425
|
+
useValue: navigator
|
|
426
|
+
}, {
|
|
427
|
+
provide: Router,
|
|
428
|
+
useValue: router
|
|
429
|
+
}]);
|
|
430
|
+
}
|
|
431
|
+
onDestroy() {
|
|
432
|
+
this.subscription.unsubscribe();
|
|
433
|
+
this.navigator.destroy();
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/router-outlet.tsx
|
|
438
|
+
var routerErrorFn = (0, _viewfly_core.makeError)("RouterOutlet");
|
|
439
|
+
function RouterOutlet(props) {
|
|
440
|
+
const router = (0, _viewfly_core.inject)(Router, null);
|
|
441
|
+
if (router === null) throw routerErrorFn("cannot found parent Router.");
|
|
442
|
+
const childRouter = new Router((0, _viewfly_core.inject)(Navigator), router);
|
|
443
|
+
const Context = (0, _viewfly_core.createContext)([{
|
|
444
|
+
provide: Router,
|
|
445
|
+
useValue: childRouter
|
|
446
|
+
}]);
|
|
447
|
+
const children = (0, _viewfly_core.shallowReactive)({ value: null });
|
|
448
|
+
const subscription = router.onRefresh.subscribe(() => {
|
|
449
|
+
updateChildren();
|
|
450
|
+
});
|
|
451
|
+
(0, _viewfly_core.onUnmounted)(() => {
|
|
452
|
+
subscription.unsubscribe();
|
|
453
|
+
});
|
|
454
|
+
let currentComponent = null;
|
|
455
|
+
async function updateChildren() {
|
|
456
|
+
const routeConfig = router.consumeConfig(props.config);
|
|
457
|
+
if (!routeConfig) {
|
|
458
|
+
currentComponent = null;
|
|
459
|
+
children.value = props.children || null;
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (typeof routeConfig.beforeEach === "function") {
|
|
463
|
+
if (!await routeConfig.beforeEach()) return;
|
|
464
|
+
}
|
|
465
|
+
if (routeConfig.component) _updateChildren(routeConfig.component);
|
|
466
|
+
else if (routeConfig.asyncComponent) _updateChildren(await routeConfig.asyncComponent());
|
|
467
|
+
if (typeof routeConfig.afterEach === "function") routeConfig.afterEach();
|
|
468
|
+
}
|
|
469
|
+
function _updateChildren(Component) {
|
|
470
|
+
childRouter.refresh();
|
|
471
|
+
if (Component !== currentComponent) children.value = /* @__PURE__ */ (0, _viewfly_core.jsx)(Component, {});
|
|
472
|
+
currentComponent = Component;
|
|
473
|
+
}
|
|
474
|
+
updateChildren();
|
|
475
|
+
return () => {
|
|
476
|
+
return /* @__PURE__ */ (0, _viewfly_core.jsx)(Context, { children: children.value });
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
//#endregion
|
|
480
|
+
Object.defineProperty(exports, "BrowserNavigator", {
|
|
481
|
+
enumerable: true,
|
|
482
|
+
get: function() {
|
|
483
|
+
return BrowserNavigator;
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
exports.Link = Link;
|
|
487
|
+
exports.Navigator = Navigator;
|
|
488
|
+
exports.Router = Router;
|
|
489
|
+
exports.RouterModule = RouterModule;
|
|
490
|
+
exports.RouterOutlet = RouterOutlet;
|
|
491
|
+
exports.UrlParser = UrlParser;
|
|
492
|
+
exports.formatQueryParams = formatQueryParams;
|
|
493
|
+
exports.formatUrl = formatUrl;
|
|
494
|
+
exports.useQueryParams = useQueryParams;
|
package/dist/link.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Props } from '@viewfly/core';
|
|
2
|
+
import { QueryParams } from './providers/_api';
|
|
3
|
+
export interface LinkProps extends Props {
|
|
4
|
+
to: string;
|
|
5
|
+
active?: string;
|
|
6
|
+
exact?: boolean;
|
|
7
|
+
queryParams?: QueryParams;
|
|
8
|
+
fragment?: string;
|
|
9
|
+
tag?: string;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
export declare function Link(props: LinkProps): () => import("@viewfly/core").JSX.Element;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Observable } from '@tanbo/stream';
|
|
2
|
+
import { Router } from './router';
|
|
3
|
+
import { UrlTree } from './url-parser';
|
|
4
|
+
export interface QueryParams {
|
|
5
|
+
[key: string]: string | string[];
|
|
6
|
+
}
|
|
7
|
+
export declare abstract class Navigator {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
abstract urlTree: UrlTree;
|
|
10
|
+
protected constructor(baseUrl: string);
|
|
11
|
+
abstract onUrlChanged: Observable<void>;
|
|
12
|
+
abstract get pathname(): string;
|
|
13
|
+
abstract to(pathName: string, relative: Router, queryParams?: QueryParams, fragment?: string): boolean;
|
|
14
|
+
abstract replace(pathName: string, relative: Router, queryParams?: QueryParams, fragment?: string): boolean;
|
|
15
|
+
abstract join(pathName: string, relative: Router, queryParams?: QueryParams, fragment?: string): string;
|
|
16
|
+
abstract back(): void;
|
|
17
|
+
abstract forward(): void;
|
|
18
|
+
abstract go(offset: number): void;
|
|
19
|
+
abstract destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
export interface UrlFormatParams {
|
|
22
|
+
queryParams?: QueryParams;
|
|
23
|
+
fragment?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function formatUrl(pathname: string, urlFormatParams: UrlFormatParams): string;
|
|
26
|
+
export declare function formatQueryParams(queryParams: QueryParams): string;
|
|
27
|
+
export interface NavigatorParams {
|
|
28
|
+
pathname: string;
|
|
29
|
+
queryParams: QueryParams;
|
|
30
|
+
fragment: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface NavigatorHooks {
|
|
33
|
+
beforeEach?(currentParams: NavigatorParams, nextParams: NavigatorParams, next: () => void): void;
|
|
34
|
+
afterEach?(params: NavigatorParams): void;
|
|
35
|
+
}
|
|
36
|
+
export declare class BrowserNavigator extends Navigator {
|
|
37
|
+
private hooks;
|
|
38
|
+
onUrlChanged: Observable<void>;
|
|
39
|
+
/** 挂载在 location 上的路径前缀;'' 或 '/' 表示站点根,不做剥离 */
|
|
40
|
+
private get basePathPrefix();
|
|
41
|
+
get pathname(): string;
|
|
42
|
+
private urlParser;
|
|
43
|
+
urlTree: UrlTree;
|
|
44
|
+
private urlChangeEvent;
|
|
45
|
+
private subscription;
|
|
46
|
+
constructor(baseUrl: string, hooks?: NavigatorHooks);
|
|
47
|
+
to(pathName: string, relative: Router, queryParams?: QueryParams, fragment?: string): boolean;
|
|
48
|
+
replace(pathName: string, relative: Router, queryParams?: QueryParams, fragment?: string): boolean;
|
|
49
|
+
join(pathname: string, relative: Router, queryParams?: QueryParams, fragment?: string): string;
|
|
50
|
+
back(): void;
|
|
51
|
+
forward(): void;
|
|
52
|
+
go(offset: number): void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
private runHooks;
|
|
55
|
+
private getUrlTree;
|
|
56
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Observable } from '@tanbo/stream';
|
|
2
|
+
import { ComponentSetup } from '@viewfly/core';
|
|
3
|
+
import { Navigator, NavigatorParams, QueryParams } from './navigator';
|
|
4
|
+
export interface RouteConfig {
|
|
5
|
+
path: string;
|
|
6
|
+
component?: ComponentSetup;
|
|
7
|
+
asyncComponent?: () => Promise<ComponentSetup>;
|
|
8
|
+
beforeEach?(): boolean | Promise<boolean>;
|
|
9
|
+
afterEach?(): void;
|
|
10
|
+
redirectTo?: string | ((path: string) => string | NavigatorParams);
|
|
11
|
+
}
|
|
12
|
+
export declare class Router {
|
|
13
|
+
private navigator;
|
|
14
|
+
parent: Router | null;
|
|
15
|
+
onRefresh: Observable<void>;
|
|
16
|
+
get deep(): number;
|
|
17
|
+
get path(): string;
|
|
18
|
+
private refreshEvent;
|
|
19
|
+
constructor(navigator: Navigator, parent: Router | null);
|
|
20
|
+
navigateTo(path: string, params?: QueryParams, fragment?: string | null): void;
|
|
21
|
+
replaceTo(path: string, params?: QueryParams): void;
|
|
22
|
+
refresh(): void;
|
|
23
|
+
consumeConfig(routes: RouteConfig[]): RouteConfig | null;
|
|
24
|
+
back(): void;
|
|
25
|
+
forward(): void;
|
|
26
|
+
go(offset: number): void;
|
|
27
|
+
private matchRoute;
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface UrlRelativePath {
|
|
2
|
+
type: 'toParent';
|
|
3
|
+
}
|
|
4
|
+
export interface UrlChildPath {
|
|
5
|
+
type: 'toChild';
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
export interface UrlQuery {
|
|
9
|
+
type: 'query';
|
|
10
|
+
params: UrlQueryParams;
|
|
11
|
+
}
|
|
12
|
+
export interface UrlQueryParams {
|
|
13
|
+
[key: string]: string | string[];
|
|
14
|
+
}
|
|
15
|
+
export interface UrlHash {
|
|
16
|
+
type: 'hash';
|
|
17
|
+
value: string;
|
|
18
|
+
}
|
|
19
|
+
export type UrlToken = UrlRelativePath | UrlChildPath | UrlQuery | UrlHash;
|
|
20
|
+
export interface UrlTree {
|
|
21
|
+
paths: string[];
|
|
22
|
+
queryParams: UrlQueryParams;
|
|
23
|
+
hash: string | null;
|
|
24
|
+
}
|
|
25
|
+
export declare class UrlParser {
|
|
26
|
+
private index;
|
|
27
|
+
private url;
|
|
28
|
+
private tokens;
|
|
29
|
+
parse(url: string): UrlTree;
|
|
30
|
+
private readHash;
|
|
31
|
+
private readQuery;
|
|
32
|
+
private readQueryValue;
|
|
33
|
+
private readQueryKey;
|
|
34
|
+
private readPath;
|
|
35
|
+
private not;
|
|
36
|
+
private peek;
|
|
37
|
+
private ignore;
|
|
38
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Application, Module } from '@viewfly/core';
|
|
2
|
+
import { NavigatorHooks } from './providers/navigator';
|
|
3
|
+
export declare class RouterModule implements Module {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
private subscription;
|
|
6
|
+
private navigator;
|
|
7
|
+
constructor(baseUrl?: string, hooks?: NavigatorHooks);
|
|
8
|
+
setup(app: Application): void;
|
|
9
|
+
onDestroy(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Props } from '@viewfly/core';
|
|
2
|
+
import { RouteConfig } from './providers/_api';
|
|
3
|
+
export interface RouterOutletProps extends Props {
|
|
4
|
+
config: RouteConfig[];
|
|
5
|
+
}
|
|
6
|
+
export declare function RouterOutlet(props: RouterOutletProps): () => import("@viewfly/core").JSX.Element;
|