@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.
@@ -1,674 +0,0 @@
1
- import { makeError, Injectable, inject, readonlyProxyHandler, comparePropsWithCallbacks, internalWrite, onUnmounted, reactive, createContext, shallowReactive } from '@viewfly/core';
2
- import { Subject, Subscription, fromEvent } from '@tanbo/stream';
3
- import { jsx } from '@viewfly/core/jsx-runtime';
4
-
5
- const routerErrorFn$1 = makeError('Router');
6
- class Router {
7
- get deep() {
8
- return this.parent ? this.parent.deep + 1 : 0;
9
- }
10
- get path() {
11
- return this.navigator.urlTree.paths.at(this.deep) || '';
12
- }
13
- constructor(navigator, parent) {
14
- Object.defineProperty(this, "navigator", {
15
- enumerable: true,
16
- configurable: true,
17
- writable: true,
18
- value: navigator
19
- });
20
- Object.defineProperty(this, "parent", {
21
- enumerable: true,
22
- configurable: true,
23
- writable: true,
24
- value: parent
25
- });
26
- Object.defineProperty(this, "onRefresh", {
27
- enumerable: true,
28
- configurable: true,
29
- writable: true,
30
- value: void 0
31
- });
32
- Object.defineProperty(this, "refreshEvent", {
33
- enumerable: true,
34
- configurable: true,
35
- writable: true,
36
- value: new Subject()
37
- });
38
- this.onRefresh = this.refreshEvent.asObservable();
39
- }
40
- navigateTo(path, params, fragment) {
41
- this.navigator.to(path, this, params, fragment || void 0);
42
- }
43
- replaceTo(path, params) {
44
- this.navigator.replace(path, this, params);
45
- }
46
- refresh() {
47
- this.refreshEvent.next();
48
- }
49
- consumeConfig(routes) {
50
- return this.matchRoute(routes, this.path);
51
- }
52
- back() {
53
- this.navigator.back();
54
- }
55
- forward() {
56
- this.navigator.forward();
57
- }
58
- go(offset) {
59
- this.navigator.go(offset);
60
- }
61
- matchRoute(configs, pathname) {
62
- let matchedConfig = null;
63
- let defaultConfig = null;
64
- let fallbackConfig = null;
65
- for (const item of configs) {
66
- if (item.path === pathname) {
67
- matchedConfig = item;
68
- break;
69
- }
70
- else if (item.path === '*') {
71
- if (!fallbackConfig) {
72
- fallbackConfig = item;
73
- }
74
- }
75
- else if (item.path === '') {
76
- if (!defaultConfig) {
77
- defaultConfig = item;
78
- }
79
- }
80
- }
81
- const config = matchedConfig || defaultConfig || fallbackConfig;
82
- if (!config) {
83
- return config;
84
- }
85
- if (typeof config.redirectTo === 'function') {
86
- const p = config.redirectTo(pathname);
87
- if (typeof p === 'string') {
88
- this.navigateTo(p);
89
- }
90
- else if (typeof p === 'object') {
91
- this.navigateTo(p.pathname, p.queryParams, p.fragment);
92
- }
93
- else {
94
- throw routerErrorFn$1(`Router redirect to '${pathname}' not supported`);
95
- }
96
- return null;
97
- }
98
- if (typeof config.redirectTo === 'string') {
99
- this.navigateTo(config.redirectTo);
100
- return null;
101
- }
102
- return config;
103
- }
104
- }
105
-
106
- /******************************************************************************
107
- Copyright (c) Microsoft Corporation.
108
-
109
- Permission to use, copy, modify, and/or distribute this software for any
110
- purpose with or without fee is hereby granted.
111
-
112
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
113
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
114
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
115
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
116
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
117
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
118
- PERFORMANCE OF THIS SOFTWARE.
119
- ***************************************************************************** */
120
- /* global Reflect, Promise, SuppressedError, Symbol */
121
-
122
-
123
- function __decorate(decorators, target, key, desc) {
124
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
125
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
126
- 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;
127
- return c > 3 && r && Object.defineProperty(target, key, r), r;
128
- }
129
-
130
- function __metadata(metadataKey, metadataValue) {
131
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
132
- }
133
-
134
- function __awaiter(thisArg, _arguments, P, generator) {
135
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
136
- return new (P || (P = Promise))(function (resolve, reject) {
137
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
138
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
139
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
140
- step((generator = generator.apply(thisArg, _arguments || [])).next());
141
- });
142
- }
143
-
144
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
145
- var e = new Error(message);
146
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
147
- };
148
-
149
- class UrlParser {
150
- constructor() {
151
- Object.defineProperty(this, "index", {
152
- enumerable: true,
153
- configurable: true,
154
- writable: true,
155
- value: 0
156
- });
157
- Object.defineProperty(this, "url", {
158
- enumerable: true,
159
- configurable: true,
160
- writable: true,
161
- value: ''
162
- });
163
- Object.defineProperty(this, "tokens", {
164
- enumerable: true,
165
- configurable: true,
166
- writable: true,
167
- value: []
168
- });
169
- }
170
- parse(url) {
171
- this.index = 0;
172
- this.url = url;
173
- this.tokens = [];
174
- while (this.index < this.url.length) {
175
- this.ignore('/');
176
- if (this.peek('../')) {
177
- this.tokens.push({
178
- type: 'toParent'
179
- });
180
- this.index += 3;
181
- }
182
- else if (this.peek('?')) {
183
- this.index++;
184
- this.tokens.push({
185
- type: 'query',
186
- params: this.readQuery()
187
- });
188
- }
189
- else if (this.peek('#')) {
190
- this.index++;
191
- this.tokens.push({
192
- type: 'hash',
193
- value: this.readHash()
194
- });
195
- }
196
- else {
197
- if (this.peek('./')) {
198
- this.index += 2;
199
- }
200
- const path = this.readPath();
201
- if (path) {
202
- this.tokens.push({
203
- type: 'toChild',
204
- value: path
205
- });
206
- }
207
- }
208
- }
209
- const urlTree = {
210
- paths: [],
211
- queryParams: {},
212
- hash: null
213
- };
214
- for (const item of this.tokens) {
215
- switch (item.type) {
216
- case 'toParent':
217
- urlTree.paths.pop();
218
- break;
219
- case 'toChild':
220
- urlTree.paths.push(item.value);
221
- break;
222
- case 'query':
223
- urlTree.queryParams = item.params;
224
- break;
225
- case 'hash':
226
- urlTree.hash = item.value;
227
- }
228
- }
229
- return urlTree;
230
- }
231
- readHash() {
232
- const hash = this.url.substring(this.index);
233
- this.index = this.url.length;
234
- return hash;
235
- }
236
- readQuery() {
237
- const query = {};
238
- while (this.index < this.url.length) {
239
- const key = this.readQueryKey();
240
- let value = '';
241
- if (this.peek('=')) {
242
- this.index++;
243
- value = this.readQueryValue();
244
- }
245
- const oldValue = query[key];
246
- if (oldValue) {
247
- if (Array.isArray(oldValue)) {
248
- oldValue.push(value);
249
- }
250
- else {
251
- query[key] = [oldValue, value];
252
- }
253
- }
254
- else {
255
- query[key] = value;
256
- }
257
- if (this.peek('&')) {
258
- this.index++;
259
- continue;
260
- }
261
- break;
262
- }
263
- return query;
264
- }
265
- readQueryValue() {
266
- const chars = [];
267
- while (this.index < this.url.length) {
268
- if (this.not('&#')) {
269
- chars.push(this.url.at(this.index));
270
- this.index++;
271
- continue;
272
- }
273
- break;
274
- }
275
- return chars.join('');
276
- }
277
- readQueryKey() {
278
- const chars = [];
279
- while (this.index < this.url.length) {
280
- if (this.not('=&#')) {
281
- chars.push(this.url.at(this.index));
282
- this.index++;
283
- continue;
284
- }
285
- break;
286
- }
287
- return chars.join('');
288
- }
289
- readPath() {
290
- const chars = [];
291
- while (this.index < this.url.length) {
292
- if (this.not('./?#')) {
293
- chars.push(this.url.at(this.index));
294
- this.index++;
295
- continue;
296
- }
297
- break;
298
- }
299
- return chars.join('');
300
- }
301
- not(text) {
302
- const ch = this.url.at(this.index);
303
- return text.indexOf(ch) === -1;
304
- }
305
- peek(str) {
306
- return this.url.slice(this.index, this.index + str.length) === str;
307
- }
308
- ignore(str) {
309
- while (this.peek(str)) {
310
- this.index++;
311
- }
312
- }
313
- }
314
-
315
- class Navigator {
316
- constructor(baseUrl) {
317
- Object.defineProperty(this, "baseUrl", {
318
- enumerable: true,
319
- configurable: true,
320
- writable: true,
321
- value: baseUrl
322
- });
323
- }
324
- }
325
- function formatUrl(pathname, urlFormatParams) {
326
- pathname = pathname.replace(/\/+/g, '/');
327
- const { queryParams, fragment } = urlFormatParams;
328
- return pathname + (queryParams ? '?' + formatQueryParams(queryParams) : '') + (fragment ? '#' + fragment : '');
329
- }
330
- function formatQueryParams(queryParams) {
331
- const params = [];
332
- Object.keys(queryParams).forEach(key => {
333
- const values = queryParams[key];
334
- if (Array.isArray(values)) {
335
- values.forEach(i => {
336
- params.push(`${key}=${decodeURIComponent(i)}`);
337
- });
338
- }
339
- else {
340
- params.push(`${key}=${decodeURIComponent(values)}`);
341
- }
342
- });
343
- return params.join('&');
344
- }
345
- let BrowserNavigator = class BrowserNavigator extends Navigator {
346
- /** 挂载在 location 上的路径前缀;'' 或 '/' 表示站点根,不做剥离 */
347
- get basePathPrefix() {
348
- return this.baseUrl === '/' || this.baseUrl === '' ? '' : this.baseUrl;
349
- }
350
- get pathname() {
351
- const pathname = location.pathname;
352
- if (!this.basePathPrefix) {
353
- return pathname;
354
- }
355
- return pathname.startsWith(this.basePathPrefix)
356
- ? pathname.substring(this.basePathPrefix.length)
357
- : pathname;
358
- }
359
- constructor(baseUrl, hooks = {}) {
360
- super(baseUrl);
361
- Object.defineProperty(this, "hooks", {
362
- enumerable: true,
363
- configurable: true,
364
- writable: true,
365
- value: hooks
366
- });
367
- Object.defineProperty(this, "onUrlChanged", {
368
- enumerable: true,
369
- configurable: true,
370
- writable: true,
371
- value: void 0
372
- });
373
- Object.defineProperty(this, "urlParser", {
374
- enumerable: true,
375
- configurable: true,
376
- writable: true,
377
- value: new UrlParser()
378
- });
379
- Object.defineProperty(this, "urlTree", {
380
- enumerable: true,
381
- configurable: true,
382
- writable: true,
383
- value: this.getUrlTree()
384
- });
385
- Object.defineProperty(this, "urlChangeEvent", {
386
- enumerable: true,
387
- configurable: true,
388
- writable: true,
389
- value: new Subject()
390
- });
391
- Object.defineProperty(this, "subscription", {
392
- enumerable: true,
393
- configurable: true,
394
- writable: true,
395
- value: new Subscription()
396
- });
397
- this.onUrlChanged = this.urlChangeEvent.asObservable();
398
- this.subscription.add(fromEvent(window, 'popstate').subscribe(() => {
399
- this.urlTree = this.getUrlTree();
400
- this.urlChangeEvent.next();
401
- }));
402
- if (this.basePathPrefix && !location.pathname.startsWith(this.basePathPrefix)) {
403
- history.replaceState(null, '', this.baseUrl);
404
- }
405
- }
406
- to(pathName, relative, queryParams, fragment) {
407
- const url = this.join(pathName, relative, queryParams, fragment);
408
- if (location.origin + url === location.href) {
409
- return true;
410
- }
411
- this.runHooks({
412
- pathname: this.pathname,
413
- queryParams: this.urlTree.queryParams,
414
- fragment: this.urlTree.hash
415
- }, {
416
- pathname: pathName,
417
- queryParams: queryParams || {},
418
- fragment: fragment || null
419
- }, () => {
420
- history.pushState(null, '', url);
421
- this.urlTree = this.getUrlTree();
422
- this.urlChangeEvent.next();
423
- });
424
- return true;
425
- }
426
- replace(pathName, relative, queryParams, fragment) {
427
- const url = this.join(pathName, relative, queryParams, fragment);
428
- if (location.origin + url === location.href) {
429
- return true;
430
- }
431
- this.runHooks({
432
- pathname: this.pathname,
433
- queryParams: this.urlTree.queryParams,
434
- fragment: this.urlTree.hash
435
- }, {
436
- pathname: pathName,
437
- queryParams: queryParams || {},
438
- fragment: fragment || null
439
- }, () => {
440
- history.replaceState(null, '', url);
441
- this.urlTree = this.getUrlTree();
442
- this.urlChangeEvent.next();
443
- });
444
- return true;
445
- }
446
- join(pathname, relative, queryParams, fragment) {
447
- if (pathname.startsWith('/')) {
448
- return formatUrl(this.baseUrl + pathname, { queryParams, fragment });
449
- }
450
- const beforePath = this.urlTree.paths.slice(0, relative.deep);
451
- while (true) {
452
- if (pathname.startsWith('./')) {
453
- pathname = pathname.substring(2);
454
- continue;
455
- }
456
- if (pathname.startsWith('../')) {
457
- pathname = pathname.substring(3);
458
- beforePath.pop();
459
- continue;
460
- }
461
- break;
462
- }
463
- return formatUrl(this.baseUrl + '/' + beforePath.join('/') + '/' + pathname, { queryParams, fragment });
464
- }
465
- back() {
466
- history.back();
467
- }
468
- forward() {
469
- history.forward();
470
- }
471
- go(offset) {
472
- history.go(offset);
473
- }
474
- destroy() {
475
- this.subscription.unsubscribe();
476
- }
477
- runHooks(beforeParams, currentParams, next) {
478
- var _a, _b, _c, _d;
479
- if (typeof this.hooks.beforeEach === 'function') {
480
- (_b = (_a = this.hooks).beforeEach) === null || _b === void 0 ? void 0 : _b.call(_a, beforeParams, currentParams, () => {
481
- var _a, _b;
482
- next();
483
- (_b = (_a = this.hooks).afterEach) === null || _b === void 0 ? void 0 : _b.call(_a, currentParams);
484
- });
485
- }
486
- else {
487
- next();
488
- (_d = (_c = this.hooks).afterEach) === null || _d === void 0 ? void 0 : _d.call(_c, currentParams);
489
- }
490
- }
491
- getUrlTree() {
492
- return this.urlParser.parse(this.pathname + location.search + location.hash);
493
- }
494
- };
495
- BrowserNavigator = __decorate([
496
- Injectable(),
497
- __metadata("design:paramtypes", [String, Object])
498
- ], BrowserNavigator);
499
-
500
- function useQueryParams() {
501
- const router = inject(Router);
502
- const navigator = inject(Navigator);
503
- const params = Object.assign({}, navigator.urlTree.queryParams);
504
- const queryParams = new Proxy(params, readonlyProxyHandler);
505
- const subscription = router.onRefresh.subscribe(() => {
506
- comparePropsWithCallbacks(params, navigator.urlTree.queryParams, key => {
507
- internalWrite(() => {
508
- Reflect.deleteProperty(params, key);
509
- });
510
- }, (key, value) => {
511
- internalWrite(() => {
512
- params[key] = value;
513
- });
514
- }, (key, value) => {
515
- internalWrite(() => {
516
- params[key] = value;
517
- });
518
- });
519
- });
520
- onUnmounted(() => {
521
- subscription.unsubscribe();
522
- });
523
- return queryParams;
524
- }
525
-
526
- function Link(props) {
527
- const navigator = inject(Navigator);
528
- const router = inject(Router);
529
- function getActive() {
530
- return props.exact ?
531
- (navigator.pathname === navigator.join(props.to, router) ||
532
- (navigator.pathname + '/') === navigator.join(props.to, router)) :
533
- navigator.pathname.startsWith(navigator.join(props.to, router));
534
- }
535
- const isActive = reactive({
536
- value: getActive()
537
- });
538
- const subscription = navigator.onUrlChanged.subscribe(() => {
539
- isActive.value = getActive();
540
- });
541
- onUnmounted(() => {
542
- subscription.unsubscribe();
543
- });
544
- function navigate(ev) {
545
- if ((!props.tag || props.tag === 'a') && props.target === '_blank') {
546
- return;
547
- }
548
- ev.preventDefault();
549
- router.navigateTo(props.to, props.queryParams, props.fragment);
550
- }
551
- return () => {
552
- const Tag = props.tag || 'a';
553
- const attrs = Object.assign({}, props, Object.assign({ onClick(ev) {
554
- var _a;
555
- navigate(ev);
556
- (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, ev);
557
- } }, props));
558
- if (Tag === 'a') {
559
- attrs.href = navigator.join(props.to, router, props.queryParams, props.fragment);
560
- }
561
- if (isActive.value && props.active) {
562
- attrs.class = [attrs.class, props.active];
563
- }
564
- return jsx(Tag, Object.assign({}, attrs, { children: props.children }));
565
- };
566
- }
567
-
568
- class RouterModule {
569
- constructor(baseUrl = '', hooks = {}) {
570
- Object.defineProperty(this, "baseUrl", {
571
- enumerable: true,
572
- configurable: true,
573
- writable: true,
574
- value: baseUrl
575
- });
576
- Object.defineProperty(this, "subscription", {
577
- enumerable: true,
578
- configurable: true,
579
- writable: true,
580
- value: new Subscription()
581
- });
582
- Object.defineProperty(this, "navigator", {
583
- enumerable: true,
584
- configurable: true,
585
- writable: true,
586
- value: void 0
587
- });
588
- this.navigator = new BrowserNavigator(this.baseUrl, hooks);
589
- }
590
- setup(app) {
591
- const navigator = this.navigator;
592
- const router = new Router(navigator, null);
593
- this.subscription.add(navigator.onUrlChanged.subscribe(() => {
594
- router.refresh();
595
- }));
596
- app.provide([
597
- {
598
- provide: Navigator,
599
- useValue: navigator
600
- },
601
- {
602
- provide: Router,
603
- useValue: router
604
- }
605
- ]);
606
- }
607
- onDestroy() {
608
- this.subscription.unsubscribe();
609
- this.navigator.destroy();
610
- }
611
- }
612
-
613
- const routerErrorFn = makeError('RouterOutlet');
614
- function RouterOutlet(props) {
615
- const router = inject(Router, null);
616
- if (router === null) {
617
- throw routerErrorFn('cannot found parent Router.');
618
- }
619
- const navigator = inject(Navigator);
620
- const childRouter = new Router(navigator, router);
621
- const Context = createContext([{
622
- provide: Router,
623
- useValue: childRouter
624
- }]);
625
- const children = shallowReactive({
626
- value: null
627
- });
628
- const subscription = router.onRefresh.subscribe(() => {
629
- updateChildren();
630
- });
631
- onUnmounted(() => {
632
- subscription.unsubscribe();
633
- });
634
- let currentComponent = null;
635
- function updateChildren() {
636
- return __awaiter(this, void 0, void 0, function* () {
637
- const routeConfig = router.consumeConfig(props.config);
638
- if (!routeConfig) {
639
- currentComponent = null;
640
- children.value = props.children || null;
641
- return;
642
- }
643
- if (typeof routeConfig.beforeEach === 'function') {
644
- const is = yield routeConfig.beforeEach();
645
- if (!is) {
646
- return;
647
- }
648
- }
649
- if (routeConfig.component) {
650
- _updateChildren(routeConfig.component);
651
- }
652
- else if (routeConfig.asyncComponent) {
653
- const c = yield routeConfig.asyncComponent();
654
- _updateChildren(c);
655
- }
656
- if (typeof routeConfig.afterEach === 'function') {
657
- routeConfig.afterEach();
658
- }
659
- });
660
- }
661
- function _updateChildren(Component) {
662
- childRouter.refresh();
663
- if (Component !== currentComponent) {
664
- children.value = jsx(Component, {});
665
- }
666
- currentComponent = Component;
667
- }
668
- updateChildren();
669
- return () => {
670
- return jsx(Context, { children: children.value });
671
- };
672
- }
673
-
674
- export { BrowserNavigator, Link, Navigator, Router, RouterModule, RouterOutlet, UrlParser, formatQueryParams, formatUrl, useQueryParams };