@viewfly/router 0.0.1-alpha.13 → 0.0.1-alpha.15

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.
@@ -31,24 +31,29 @@ function __metadata(metadataKey, metadataValue) {
31
31
  }
32
32
 
33
33
  class Navigator {
34
- constructor(basePath) {
35
- this.basePath = basePath;
34
+ constructor(baseUrl) {
35
+ this.baseUrl = baseUrl;
36
36
  }
37
37
  }
38
38
  function formatUrl(pathname, query) {
39
+ pathname = pathname.replace(/\/+/g, '/');
39
40
  if (query) {
40
- return pathname + '?' + formatQueryParam(query);
41
+ return pathname + '?' + formatQueryParams(query);
41
42
  }
42
43
  return pathname;
43
44
  }
44
- function formatQueryParam(queryParam) {
45
- const map = new Map();
46
- Object.keys(queryParam).forEach(key => {
47
- map.set(key, queryParam[key]);
48
- });
45
+ function formatQueryParams(queryParams) {
49
46
  const params = [];
50
- map.forEach((value, key) => {
51
- params.push(`${key}=${String(value)}`);
47
+ Object.keys(queryParams).forEach(key => {
48
+ const values = queryParams[key];
49
+ if (Array.isArray(values)) {
50
+ values.forEach(i => {
51
+ params.push(`${key}=${decodeURIComponent(i)}`);
52
+ });
53
+ }
54
+ else {
55
+ params.push(`${key}=${decodeURIComponent(values)}`);
56
+ }
52
57
  });
53
58
  return params.join('&');
54
59
  }
@@ -56,30 +61,41 @@ let BrowserNavigator = class BrowserNavigator extends Navigator {
56
61
  get pathname() {
57
62
  return location.pathname;
58
63
  }
59
- constructor(basePath) {
60
- super(basePath);
64
+ constructor(baseUrl) {
65
+ super(baseUrl);
61
66
  this.urlChangeEvent = new Subject();
62
67
  this.subscription = new Subscription();
63
68
  this.onUrlChanged = this.urlChangeEvent.asObservable();
64
69
  this.subscription.add(fromEvent(window, 'popstate').subscribe(() => {
65
70
  this.urlChangeEvent.next();
66
71
  }));
72
+ if (!this.pathname.startsWith(this.baseUrl)) {
73
+ history.replaceState(null, '', this.baseUrl);
74
+ }
67
75
  }
68
76
  to(pathName, relative, queryParams) {
69
77
  const url = this.join(pathName, relative, queryParams);
70
78
  if (location.origin + url === location.href) {
71
79
  return true;
72
80
  }
73
- history.pushState(null, '', this.basePath + url);
81
+ history.pushState(null, '', url);
82
+ this.urlChangeEvent.next();
83
+ return true;
84
+ }
85
+ replace(pathName, relative, queryParams) {
86
+ const url = this.join(pathName, relative, queryParams);
87
+ if (location.origin + url === location.href) {
88
+ return true;
89
+ }
90
+ history.replaceState(null, '', url);
74
91
  this.urlChangeEvent.next();
75
92
  return true;
76
93
  }
77
94
  join(pathname, relative, queryParams) {
78
- var _a;
79
- let beforePath = relative.beforePath;
80
95
  if (pathname.startsWith('/')) {
81
- return formatUrl(pathname, queryParams);
96
+ return formatUrl(this.baseUrl + pathname, queryParams);
82
97
  }
98
+ let beforePath = relative.beforePath;
83
99
  while (true) {
84
100
  if (pathname.startsWith('./')) {
85
101
  pathname = pathname.substring(2);
@@ -87,7 +103,13 @@ let BrowserNavigator = class BrowserNavigator extends Navigator {
87
103
  }
88
104
  if (pathname.startsWith('../')) {
89
105
  pathname = pathname.substring(3);
90
- beforePath = ((_a = relative.parent) === null || _a === void 0 ? void 0 : _a.beforePath) || '';
106
+ if (relative.parent) {
107
+ beforePath = relative.parent.beforePath;
108
+ relative = relative.parent;
109
+ }
110
+ else {
111
+ beforePath = '';
112
+ }
91
113
  if (!beforePath) {
92
114
  break;
93
115
  }
@@ -95,7 +117,7 @@ let BrowserNavigator = class BrowserNavigator extends Navigator {
95
117
  }
96
118
  break;
97
119
  }
98
- return formatUrl(beforePath + '/' + pathname, queryParams);
120
+ return formatUrl(this.baseUrl + '/' + beforePath + '/' + pathname, queryParams);
99
121
  }
100
122
  back() {
101
123
  history.back();
@@ -117,9 +139,11 @@ BrowserNavigator = __decorate([
117
139
 
118
140
  class Router {
119
141
  get pathname() {
120
- var _a;
121
142
  if (this.parent) {
122
- return ((_a = this.parent.path.match(/[^\/?#]+/)) === null || _a === void 0 ? void 0 : _a[0]) || '';
143
+ const name = this.parent.path.match(/[^\/?#]+/);
144
+ if (name) {
145
+ return name[0];
146
+ }
123
147
  }
124
148
  return '';
125
149
  }
@@ -139,6 +163,9 @@ class Router {
139
163
  navigateTo(path, params) {
140
164
  this.navigator.to(path, this, params);
141
165
  }
166
+ replaceTo(path, params) {
167
+ this.navigator.replace(path, this, params);
168
+ }
142
169
  refresh(path) {
143
170
  this.path = path;
144
171
  this.refreshEvent.next();
@@ -203,7 +230,8 @@ function Link(props) {
203
230
  const router = inject(Router);
204
231
  function getActive() {
205
232
  return props.exact ?
206
- navigator.pathname === navigator.join(props.to, router) :
233
+ (navigator.pathname === navigator.join(props.to, router) ||
234
+ (navigator.pathname + '/') === navigator.join(props.to, router)) :
207
235
  navigator.pathname.startsWith(navigator.join(props.to, router));
208
236
  }
209
237
  const isActive = useSignal(getActive());
@@ -214,14 +242,15 @@ function Link(props) {
214
242
  subscription.unsubscribe();
215
243
  });
216
244
  function navigate(ev) {
245
+ if ((!props.tag || props.tag === 'a') && props.target === '_blank') {
246
+ return;
247
+ }
217
248
  ev.preventDefault();
218
249
  router.navigateTo(props.to, props.queryParams);
219
250
  }
220
251
  return () => {
221
252
  const Tag = props.tag || 'a';
222
- const attrs = Object.assign({
223
- target: '_blank'
224
- }, props, Object.assign({ onClick: navigate }, props));
253
+ const attrs = Object.assign({}, props, Object.assign({ onClick: navigate }, props));
225
254
  if (Tag === 'a') {
226
255
  attrs.href = navigator.join(props.to, router, props.queryParams);
227
256
  }
@@ -232,12 +261,12 @@ function Link(props) {
232
261
  else if (typeof attrs.class === 'string') {
233
262
  attrs.class += ' ' + props.active;
234
263
  }
235
- else if (typeof props.active === 'object') {
236
- attrs.class[props.active] = true;
237
- }
238
264
  else if (Array.isArray(attrs.class)) {
239
265
  attrs.class.push(props.active);
240
266
  }
267
+ else if (typeof attrs.class === 'object') {
268
+ attrs.class[props.active] = true;
269
+ }
241
270
  }
242
271
  return jsx(Tag, Object.assign({}, attrs, { children: props.children }));
243
272
  };
@@ -317,4 +346,4 @@ function RouterOutlet(props) {
317
346
  };
318
347
  }
319
348
 
320
- export { BrowserNavigator, Link, Navigator, RootRouter, Router, RouterOutlet, formatQueryParam, formatUrl };
349
+ export { BrowserNavigator, Link, Navigator, RootRouter, Router, RouterOutlet, formatQueryParams, formatUrl };
package/bundles/index.js CHANGED
@@ -33,24 +33,29 @@ function __metadata(metadataKey, metadataValue) {
33
33
  }
34
34
 
35
35
  class Navigator {
36
- constructor(basePath) {
37
- this.basePath = basePath;
36
+ constructor(baseUrl) {
37
+ this.baseUrl = baseUrl;
38
38
  }
39
39
  }
40
40
  function formatUrl(pathname, query) {
41
+ pathname = pathname.replace(/\/+/g, '/');
41
42
  if (query) {
42
- return pathname + '?' + formatQueryParam(query);
43
+ return pathname + '?' + formatQueryParams(query);
43
44
  }
44
45
  return pathname;
45
46
  }
46
- function formatQueryParam(queryParam) {
47
- const map = new Map();
48
- Object.keys(queryParam).forEach(key => {
49
- map.set(key, queryParam[key]);
50
- });
47
+ function formatQueryParams(queryParams) {
51
48
  const params = [];
52
- map.forEach((value, key) => {
53
- params.push(`${key}=${String(value)}`);
49
+ Object.keys(queryParams).forEach(key => {
50
+ const values = queryParams[key];
51
+ if (Array.isArray(values)) {
52
+ values.forEach(i => {
53
+ params.push(`${key}=${decodeURIComponent(i)}`);
54
+ });
55
+ }
56
+ else {
57
+ params.push(`${key}=${decodeURIComponent(values)}`);
58
+ }
54
59
  });
55
60
  return params.join('&');
56
61
  }
@@ -58,30 +63,41 @@ exports.BrowserNavigator = class BrowserNavigator extends Navigator {
58
63
  get pathname() {
59
64
  return location.pathname;
60
65
  }
61
- constructor(basePath) {
62
- super(basePath);
66
+ constructor(baseUrl) {
67
+ super(baseUrl);
63
68
  this.urlChangeEvent = new stream.Subject();
64
69
  this.subscription = new stream.Subscription();
65
70
  this.onUrlChanged = this.urlChangeEvent.asObservable();
66
71
  this.subscription.add(stream.fromEvent(window, 'popstate').subscribe(() => {
67
72
  this.urlChangeEvent.next();
68
73
  }));
74
+ if (!this.pathname.startsWith(this.baseUrl)) {
75
+ history.replaceState(null, '', this.baseUrl);
76
+ }
69
77
  }
70
78
  to(pathName, relative, queryParams) {
71
79
  const url = this.join(pathName, relative, queryParams);
72
80
  if (location.origin + url === location.href) {
73
81
  return true;
74
82
  }
75
- history.pushState(null, '', this.basePath + url);
83
+ history.pushState(null, '', url);
84
+ this.urlChangeEvent.next();
85
+ return true;
86
+ }
87
+ replace(pathName, relative, queryParams) {
88
+ const url = this.join(pathName, relative, queryParams);
89
+ if (location.origin + url === location.href) {
90
+ return true;
91
+ }
92
+ history.replaceState(null, '', url);
76
93
  this.urlChangeEvent.next();
77
94
  return true;
78
95
  }
79
96
  join(pathname, relative, queryParams) {
80
- var _a;
81
- let beforePath = relative.beforePath;
82
97
  if (pathname.startsWith('/')) {
83
- return formatUrl(pathname, queryParams);
98
+ return formatUrl(this.baseUrl + pathname, queryParams);
84
99
  }
100
+ let beforePath = relative.beforePath;
85
101
  while (true) {
86
102
  if (pathname.startsWith('./')) {
87
103
  pathname = pathname.substring(2);
@@ -89,7 +105,13 @@ exports.BrowserNavigator = class BrowserNavigator extends Navigator {
89
105
  }
90
106
  if (pathname.startsWith('../')) {
91
107
  pathname = pathname.substring(3);
92
- beforePath = ((_a = relative.parent) === null || _a === void 0 ? void 0 : _a.beforePath) || '';
108
+ if (relative.parent) {
109
+ beforePath = relative.parent.beforePath;
110
+ relative = relative.parent;
111
+ }
112
+ else {
113
+ beforePath = '';
114
+ }
93
115
  if (!beforePath) {
94
116
  break;
95
117
  }
@@ -97,7 +119,7 @@ exports.BrowserNavigator = class BrowserNavigator extends Navigator {
97
119
  }
98
120
  break;
99
121
  }
100
- return formatUrl(beforePath + '/' + pathname, queryParams);
122
+ return formatUrl(this.baseUrl + '/' + beforePath + '/' + pathname, queryParams);
101
123
  }
102
124
  back() {
103
125
  history.back();
@@ -119,9 +141,11 @@ exports.BrowserNavigator = __decorate([
119
141
 
120
142
  class Router {
121
143
  get pathname() {
122
- var _a;
123
144
  if (this.parent) {
124
- return ((_a = this.parent.path.match(/[^\/?#]+/)) === null || _a === void 0 ? void 0 : _a[0]) || '';
145
+ const name = this.parent.path.match(/[^\/?#]+/);
146
+ if (name) {
147
+ return name[0];
148
+ }
125
149
  }
126
150
  return '';
127
151
  }
@@ -141,6 +165,9 @@ class Router {
141
165
  navigateTo(path, params) {
142
166
  this.navigator.to(path, this, params);
143
167
  }
168
+ replaceTo(path, params) {
169
+ this.navigator.replace(path, this, params);
170
+ }
144
171
  refresh(path) {
145
172
  this.path = path;
146
173
  this.refreshEvent.next();
@@ -205,7 +232,8 @@ function Link(props) {
205
232
  const router = core.inject(Router);
206
233
  function getActive() {
207
234
  return props.exact ?
208
- navigator.pathname === navigator.join(props.to, router) :
235
+ (navigator.pathname === navigator.join(props.to, router) ||
236
+ (navigator.pathname + '/') === navigator.join(props.to, router)) :
209
237
  navigator.pathname.startsWith(navigator.join(props.to, router));
210
238
  }
211
239
  const isActive = core.useSignal(getActive());
@@ -216,14 +244,15 @@ function Link(props) {
216
244
  subscription.unsubscribe();
217
245
  });
218
246
  function navigate(ev) {
247
+ if ((!props.tag || props.tag === 'a') && props.target === '_blank') {
248
+ return;
249
+ }
219
250
  ev.preventDefault();
220
251
  router.navigateTo(props.to, props.queryParams);
221
252
  }
222
253
  return () => {
223
254
  const Tag = props.tag || 'a';
224
- const attrs = Object.assign({
225
- target: '_blank'
226
- }, props, Object.assign({ onClick: navigate }, props));
255
+ const attrs = Object.assign({}, props, Object.assign({ onClick: navigate }, props));
227
256
  if (Tag === 'a') {
228
257
  attrs.href = navigator.join(props.to, router, props.queryParams);
229
258
  }
@@ -234,12 +263,12 @@ function Link(props) {
234
263
  else if (typeof attrs.class === 'string') {
235
264
  attrs.class += ' ' + props.active;
236
265
  }
237
- else if (typeof props.active === 'object') {
238
- attrs.class[props.active] = true;
239
- }
240
266
  else if (Array.isArray(attrs.class)) {
241
267
  attrs.class.push(props.active);
242
268
  }
269
+ else if (typeof attrs.class === 'object') {
270
+ attrs.class[props.active] = true;
271
+ }
243
272
  }
244
273
  return jsxRuntime.jsx(Tag, Object.assign({}, attrs, { children: props.children }));
245
274
  };
@@ -324,5 +353,5 @@ exports.Navigator = Navigator;
324
353
  exports.RootRouter = RootRouter;
325
354
  exports.Router = Router;
326
355
  exports.RouterOutlet = RouterOutlet;
327
- exports.formatQueryParam = formatQueryParam;
356
+ exports.formatQueryParams = formatQueryParams;
328
357
  exports.formatUrl = formatUrl;
@@ -4,27 +4,28 @@ export interface QueryParams {
4
4
  [key: string]: string | string[];
5
5
  }
6
6
  export declare abstract class Navigator {
7
- basePath: string;
8
- protected constructor(basePath: string);
7
+ baseUrl: string;
8
+ protected constructor(baseUrl: string);
9
9
  abstract onUrlChanged: Observable<void>;
10
10
  abstract get pathname(): string;
11
11
  abstract to(pathName: string, relative: Router, queryParams?: QueryParams): boolean;
12
+ abstract replace(pathName: string, relative: Router, queryParams?: QueryParams): boolean;
12
13
  abstract join(pathName: string, relative: Router, queryParams?: QueryParams): string;
13
14
  abstract back(): void;
14
15
  abstract forward(): void;
15
16
  abstract go(offset: number): void;
16
17
  abstract destroy(): void;
17
18
  }
18
- export type QueryParam = Record<string, string | boolean | number>;
19
19
  export declare function formatUrl(pathname: string, query?: QueryParams): string;
20
- export declare function formatQueryParam(queryParam: QueryParams): string;
20
+ export declare function formatQueryParams(queryParams: QueryParams): string;
21
21
  export declare class BrowserNavigator extends Navigator {
22
22
  onUrlChanged: Observable<void>;
23
23
  get pathname(): string;
24
24
  private urlChangeEvent;
25
25
  private subscription;
26
- constructor(basePath: string);
26
+ constructor(baseUrl: string);
27
27
  to(pathName: string, relative: Router, queryParams?: QueryParams): boolean;
28
+ replace(pathName: string, relative: Router, queryParams?: QueryParams): boolean;
28
29
  join(pathname: string, relative: Router, queryParams?: QueryParams): string;
29
30
  back(): void;
30
31
  forward(): void;
@@ -16,6 +16,7 @@ export declare class Router {
16
16
  private refreshEvent;
17
17
  constructor(navigator: Navigator, parent: Router | null, path: string);
18
18
  navigateTo(path: string, params?: QueryParams): void;
19
+ replaceTo(path: string, params?: QueryParams): void;
19
20
  refresh(path: string): void;
20
21
  consumeConfig(routes: RouteConfig[]): {
21
22
  remainingPath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viewfly/router",
3
- "version": "0.0.1-alpha.13",
3
+ "version": "0.0.1-alpha.15",
4
4
  "description": "A routing library based on the Viewfly framework that can be run in the browser or Nodejs background.",
5
5
  "main": "./bundles/index.js",
6
6
  "module": "./bundles/index.esm.js",
@@ -12,8 +12,8 @@
12
12
  "license": "MIT",
13
13
  "keywords": [],
14
14
  "dependencies": {
15
- "@tanbo/stream": "^1.1.9",
16
- "@viewfly/core": "^0.0.1-alpha.13",
15
+ "@tanbo/stream": "^1.2.0",
16
+ "@viewfly/core": "^0.0.1-alpha.15",
17
17
  "url": "^0.11.1"
18
18
  },
19
19
  "devDependencies": {
@@ -33,5 +33,6 @@
33
33
  },
34
34
  "bugs": {
35
35
  "url": "https://github.com/viewfly/viewfly.git/issues"
36
- }
36
+ },
37
+ "gitHead": "8eccbdc9402ab506f98acb5946e19c16d8b74b43"
37
38
  }