@dharmax/state-router 1.2.2 → 2.0.1
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 +24 -29
- package/dist/router.d.ts +16 -16
- package/dist/router.js +51 -64
- package/dist/state-manager.d.ts +2 -2
- package/dist/state-manager.js +9 -6
- package/package.json +3 -3
- package/src/router.ts +67 -73
- package/tsconfig.json +3 -2
package/ReadMe.md
CHANGED
|
@@ -6,48 +6,43 @@ What is a functional router? it's a router that captures a url changes and
|
|
|
6
6
|
per specific pattern of url, it simply triggers a handler. It supports hash notation
|
|
7
7
|
as well as normal url patterns. It also supports contexts (url parameters).
|
|
8
8
|
|
|
9
|
-
Together with the
|
|
10
|
-
to work with, you get a very
|
|
9
|
+
Together with the state manager - which will be the main object you'd need
|
|
10
|
+
to work with, you get a very simple semantic application state management:
|
|
11
11
|
each state can be given a logical name, route and an associated page/component.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* Doesn't monopolise the URL
|
|
20
|
-
* Supports state contexts
|
|
13
|
+
The router by default ignores file extensions '.json', '.css', '.js', '.png', '.jpg', '.svg', '.webp','md'
|
|
14
|
+
and you can access the router's staticFilters member to replace or add other rules
|
|
15
|
+
for static serving support.
|
|
16
|
+
|
|
17
|
+
you can use the hash notation or not (set the router's mode to 'history' or 'hash')
|
|
18
|
+
|
|
21
19
|
|
|
22
20
|
# Example
|
|
23
21
|
|
|
24
22
|
## state definitions
|
|
25
23
|
|
|
26
24
|
```javascript
|
|
27
|
-
|
|
28
|
-
// this is how you define the states: logical name, component name, route (as string or regex)
|
|
29
25
|
stateManager.addState('main', 'main-page', /main$/);
|
|
30
26
|
stateManager.addState('login', 'login-box', 'login')
|
|
31
27
|
stateManager.addState('signup', 'signup-box', /signup/)
|
|
32
28
|
stateManager.addState('my-profile') // will assume the page name and the route are the same...
|
|
33
|
-
stateManager.addState('inbox')
|
|
29
|
+
stateManager.addState('inbox')
|
|
34
30
|
stateManager.addState('about')
|
|
35
|
-
stateManager.addState('discussion', 'discussion-page', 'discussion/%')
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// this specific example works with RiotJs, but you get the drift
|
|
40
|
-
this.update({
|
|
41
|
-
currentPage: event.data.pageName
|
|
42
|
-
})
|
|
43
|
-
})
|
|
31
|
+
stateManager.addState('discussion', 'discussion-page', 'discussion/%')
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## usage in the gui
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
In your main component, you write something like that:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
|
|
40
|
+
stateManager.onChange( event => {
|
|
41
|
+
// this specific example works with RiotJs, but you get the drift
|
|
42
|
+
this.update({
|
|
43
|
+
currentPage: event.data.pageName
|
|
51
44
|
})
|
|
52
|
-
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
|
|
53
48
|
```
|
package/dist/router.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
constructor();
|
|
3
|
-
re: RegExp;
|
|
4
|
-
handler: Function;
|
|
5
|
-
}
|
|
1
|
+
type RouteHandler = (...args: string[]) => void;
|
|
6
2
|
export type RoutingMode = 'history' | 'hash';
|
|
7
|
-
|
|
3
|
+
declare class Router {
|
|
8
4
|
mode: RoutingMode;
|
|
9
|
-
routes
|
|
10
|
-
root
|
|
11
|
-
baseLocation
|
|
5
|
+
private routes;
|
|
6
|
+
private root;
|
|
7
|
+
private baseLocation;
|
|
8
|
+
staticFilters: ((url: string) => boolean)[];
|
|
9
|
+
constructor();
|
|
10
|
+
private clearSlashes;
|
|
11
|
+
private clearQuery;
|
|
12
|
+
private isStaticFile;
|
|
12
13
|
resetRoot(root: string): void;
|
|
13
14
|
getLocation(): string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
15
|
+
add(pattern: RegExp | RouteHandler, handler?: RouteHandler): Router;
|
|
16
|
+
process(location?: string): Router;
|
|
17
|
+
listen(): void;
|
|
18
|
+
navigate(path?: string): Router;
|
|
19
|
+
}
|
|
20
|
+
export declare const router: Router;
|
|
21
21
|
export {};
|
package/dist/router.js
CHANGED
|
@@ -1,94 +1,81 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Router {
|
|
2
|
+
mode = 'hash';
|
|
3
|
+
routes = [];
|
|
4
|
+
root = '/';
|
|
5
|
+
baseLocation = null;
|
|
6
|
+
staticFilters = [];
|
|
2
7
|
constructor() {
|
|
3
|
-
this.
|
|
4
|
-
|
|
8
|
+
this.staticFilters.push(url => {
|
|
9
|
+
const staticFileExtensions = ['.json', '.css', '.js', '.png', '.jpg', '.svg', '.webp', 'md'];
|
|
10
|
+
return staticFileExtensions.some(ext => url.endsWith(ext));
|
|
11
|
+
});
|
|
12
|
+
window.addEventListener(this.mode === 'hash' ? 'hashchange' : 'popstate', this.listen.bind(this));
|
|
5
13
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
clearSlashes(path) {
|
|
15
|
+
return path.replace(/\/$/, '').replace(/^\//, '');
|
|
16
|
+
}
|
|
17
|
+
clearQuery(url) {
|
|
18
|
+
const [path, query] = url.split('?');
|
|
19
|
+
if (!query)
|
|
20
|
+
return path;
|
|
21
|
+
const [_, hash] = query.split('#');
|
|
22
|
+
return hash ? `${path}#${hash}` : path;
|
|
23
|
+
}
|
|
24
|
+
isStaticFile(url) {
|
|
25
|
+
return (this.staticFilters || []).some(filter => filter(url));
|
|
13
26
|
}
|
|
14
27
|
resetRoot(root) {
|
|
15
28
|
this.root = '/' + this.clearSlashes(root) + '/';
|
|
16
29
|
}
|
|
17
30
|
getLocation() {
|
|
18
|
-
let fragment = '';
|
|
19
31
|
if (this.mode === 'history') {
|
|
20
|
-
fragment = this.clearSlashes(decodeURI(location.pathname + location.search));
|
|
32
|
+
let fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search));
|
|
21
33
|
fragment = this.clearQuery(fragment);
|
|
22
|
-
|
|
23
|
-
fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment;
|
|
34
|
+
return this.root !== '/' ? fragment.replace(this.root, '') : fragment;
|
|
24
35
|
}
|
|
25
36
|
else {
|
|
26
37
|
const match = window.location.href.match(/#(.*)$/);
|
|
27
|
-
|
|
28
|
-
fragment = match ? match[1] : '';
|
|
38
|
+
return match ? this.clearQuery(match[1]) : '';
|
|
29
39
|
}
|
|
30
|
-
return this.clearSlashes(fragment);
|
|
31
|
-
}
|
|
32
|
-
clearSlashes(path) {
|
|
33
|
-
return path.toString().replace(/\/$/, '').replace(/^\//, '');
|
|
34
|
-
}
|
|
35
|
-
clearQuery(url) {
|
|
36
|
-
if (url.indexOf('?') === -1)
|
|
37
|
-
return url;
|
|
38
|
-
const a = url.split('?');
|
|
39
|
-
const afterHash = a[1].split('#');
|
|
40
|
-
if (!afterHash)
|
|
41
|
-
return a[0];
|
|
42
|
-
return `${a[0]}#${afterHash}`;
|
|
43
40
|
}
|
|
44
|
-
add(
|
|
45
|
-
if (typeof
|
|
46
|
-
handler =
|
|
47
|
-
|
|
41
|
+
add(pattern, handler) {
|
|
42
|
+
if (typeof pattern === 'function') {
|
|
43
|
+
handler = pattern;
|
|
44
|
+
pattern = /^.*$/; // Match any path
|
|
48
45
|
}
|
|
49
|
-
this.routes.push({
|
|
46
|
+
this.routes.push({ pattern, handler: handler });
|
|
50
47
|
return this;
|
|
51
48
|
}
|
|
52
49
|
process(location) {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
console.warn(`No routing found for ${fragment}`);
|
|
64
|
-
return;
|
|
50
|
+
const path = location || this.getLocation();
|
|
51
|
+
if (this.isStaticFile(path))
|
|
52
|
+
return this; // Bypass routing for static files
|
|
53
|
+
for (const route of this.routes) {
|
|
54
|
+
const match = path.match(route.pattern);
|
|
55
|
+
if (match) {
|
|
56
|
+
match.shift(); // Remove the full match element
|
|
57
|
+
route.handler.apply({}, match);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
65
60
|
}
|
|
66
|
-
|
|
67
|
-
longestMatch.match.shift();
|
|
68
|
-
longestMatch.r.handler.apply({}, longestMatch.match);
|
|
61
|
+
console.warn(`No routing found for ${path}`);
|
|
69
62
|
return this;
|
|
70
63
|
}
|
|
71
64
|
listen() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.process(place);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
return this;
|
|
65
|
+
const currentLocation = this.getLocation();
|
|
66
|
+
if (this.baseLocation !== currentLocation) {
|
|
67
|
+
this.baseLocation = currentLocation;
|
|
68
|
+
this.process(currentLocation);
|
|
69
|
+
}
|
|
81
70
|
}
|
|
82
|
-
navigate(path) {
|
|
83
|
-
path = path ? path : '';
|
|
71
|
+
navigate(path = '') {
|
|
84
72
|
if (this.mode === 'history') {
|
|
85
73
|
history.pushState(null, null, this.root + this.clearSlashes(path));
|
|
86
74
|
}
|
|
87
75
|
else {
|
|
88
|
-
|
|
89
|
-
window.location.href = window.location.href.replace(/#(.*)$/, '') + path;
|
|
90
|
-
this.process();
|
|
76
|
+
window.location.hash = '#' + this.clearSlashes(path);
|
|
91
77
|
}
|
|
92
78
|
return this;
|
|
93
79
|
}
|
|
94
|
-
}
|
|
80
|
+
}
|
|
81
|
+
export const router = new Router();
|
package/dist/state-manager.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare class StateManager {
|
|
|
17
17
|
private changeAuthorities;
|
|
18
18
|
constructor(mode?: RoutingMode);
|
|
19
19
|
onChange(handler: (event: PubSubEvent, data: any) => void): IPubSubHandle;
|
|
20
|
-
registerChangeAuthority(authorityCallback: (
|
|
20
|
+
registerChangeAuthority(authorityCallback: (targetState: ApplicationState) => Promise<boolean>): void;
|
|
21
21
|
getState(): ApplicationState;
|
|
22
22
|
get previous(): ApplicationState;
|
|
23
23
|
get context(): ApplicationState;
|
|
@@ -26,7 +26,7 @@ export declare class StateManager {
|
|
|
26
26
|
* @param state can be either just a state or a state and context (which can be sub-state, or anything else)
|
|
27
27
|
*/
|
|
28
28
|
set state(state: ApplicationStateName | [ApplicationStateName, any]);
|
|
29
|
-
/** attempts to restore state from current url */
|
|
29
|
+
/** attempts to restore state from current url. Currently, works only in hash mode */
|
|
30
30
|
restoreState(defaultState: ApplicationStateName): void;
|
|
31
31
|
/**
|
|
32
32
|
*
|
package/dist/state-manager.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { router } from "./router";
|
|
2
2
|
import dispatcher from "@dharmax/pubsub";
|
|
3
3
|
export class StateManager {
|
|
4
|
+
allStates = {};
|
|
5
|
+
appState;
|
|
6
|
+
previousState;
|
|
7
|
+
stateContext;
|
|
8
|
+
static dispatcher = dispatcher;
|
|
9
|
+
changeAuthorities = [];
|
|
4
10
|
constructor(mode = 'hash') {
|
|
5
|
-
this.allStates = {};
|
|
6
|
-
this.changeAuthorities = [];
|
|
7
11
|
router.mode = mode;
|
|
8
12
|
router.listen();
|
|
9
13
|
}
|
|
@@ -37,10 +41,10 @@ export class StateManager {
|
|
|
37
41
|
else
|
|
38
42
|
this.setState(state);
|
|
39
43
|
}
|
|
40
|
-
/** attempts to restore state from current url */
|
|
44
|
+
/** attempts to restore state from current url. Currently, works only in hash mode */
|
|
41
45
|
restoreState(defaultState) {
|
|
42
46
|
let dest = window.location.hash;
|
|
43
|
-
if (dest
|
|
47
|
+
if (dest == '#login' || dest == '')
|
|
44
48
|
dest = '#' + defaultState;
|
|
45
49
|
router.navigate(dest);
|
|
46
50
|
}
|
|
@@ -56,7 +60,7 @@ export class StateManager {
|
|
|
56
60
|
return false;
|
|
57
61
|
}
|
|
58
62
|
// check if the state change was declined by any change authority and if so - don't do it and return false
|
|
59
|
-
const changeConfirmations = await Promise.all(this.changeAuthorities.map(
|
|
63
|
+
const changeConfirmations = await Promise.all(this.changeAuthorities.map(authority => authority(newState)));
|
|
60
64
|
if (changeConfirmations.includes(false))
|
|
61
65
|
return false;
|
|
62
66
|
// perform the change
|
|
@@ -100,5 +104,4 @@ export class StateManager {
|
|
|
100
104
|
});
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
StateManager.dispatcher = dispatcher;
|
|
104
107
|
export const stateManager = new StateManager();
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dharmax/state-router",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A cute and tight router and application state controller",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
|
|
7
8
|
"scripts": {
|
|
8
9
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
10
|
"build": "npx tsc",
|
|
@@ -15,7 +16,6 @@
|
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|
|
17
18
|
"router",
|
|
18
|
-
"navigation",
|
|
19
19
|
"state"
|
|
20
20
|
],
|
|
21
21
|
"author": "Avi Tshuva, dharmax",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/dharmax/state-routerr",
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"typescript": "^4.9.
|
|
28
|
+
"typescript": "^4.9.5"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@dharmax/pubsub": "^1.1.0"
|
package/src/router.ts
CHANGED
|
@@ -1,108 +1,102 @@
|
|
|
1
|
-
|
|
2
|
-
constructor() {
|
|
3
|
-
}
|
|
1
|
+
type RouteHandler = (...args: string[]) => void;
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
interface Route {
|
|
4
|
+
pattern: RegExp | null;
|
|
5
|
+
handler: RouteHandler;
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
export type RoutingMode = 'history' | 'hash'
|
|
10
|
-
export const router = new class {
|
|
8
|
+
export type RoutingMode = 'history' | 'hash';
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
class Router {
|
|
11
|
+
mode: RoutingMode = 'hash';
|
|
12
|
+
private routes: Route[] = [];
|
|
13
|
+
private root: string = '/';
|
|
14
|
+
private baseLocation: string | null = null;
|
|
15
|
+
public staticFilters:((url:string) => boolean)[] = []
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
constructor() {
|
|
18
|
+
this.staticFilters.push( url => {
|
|
19
|
+
const staticFileExtensions = ['.json', '.css', '.js', '.png', '.jpg', '.svg', '.webp','md'];
|
|
20
|
+
return staticFileExtensions.some(ext => url.endsWith(ext));
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
this.
|
|
22
|
+
})
|
|
23
|
+
window.addEventListener(this.mode === 'hash' ? 'hashchange' : 'popstate', this.listen.bind(this));
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
private clearSlashes(path: string): string {
|
|
27
|
+
return path.replace(/\/$/, '').replace(/^\//, '');
|
|
28
|
+
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
fragment = fragment.replace(/\?(.*)$/, '');
|
|
29
|
-
fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment;
|
|
30
|
-
} else {
|
|
31
|
-
const match = window.location.href.match(/#(.*)$/);
|
|
32
|
-
fragment = this.clearQuery(fragment)
|
|
33
|
-
fragment = match ? match[1] : '';
|
|
34
|
-
}
|
|
35
|
-
return this.clearSlashes(fragment);
|
|
30
|
+
private clearQuery(url: string): string {
|
|
31
|
+
const [path, query] = url.split('?');
|
|
32
|
+
if (!query) return path;
|
|
33
|
+
const [_, hash] = query.split('#');
|
|
34
|
+
return hash ? `${path}#${hash}` : path;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
return
|
|
37
|
+
private isStaticFile(url: string): boolean {
|
|
38
|
+
return (this.staticFilters || []).some( filter => filter(url))
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return url
|
|
45
|
-
const a = url.split('?')
|
|
46
|
-
const afterHash = a[1].split('#')
|
|
47
|
-
if (!afterHash)
|
|
48
|
-
return a[0]
|
|
49
|
-
return `${a[0]}#${afterHash}`
|
|
41
|
+
public resetRoot(root: string): void {
|
|
42
|
+
this.root = '/' + this.clearSlashes(root) + '/';
|
|
50
43
|
}
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
public getLocation(): string {
|
|
46
|
+
if (this.mode === 'history') {
|
|
47
|
+
let fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search));
|
|
48
|
+
fragment = this.clearQuery(fragment);
|
|
49
|
+
return this.root !== '/' ? fragment.replace(this.root, '') : fragment;
|
|
50
|
+
} else {
|
|
51
|
+
const match = window.location.href.match(/#(.*)$/);
|
|
52
|
+
return match ? this.clearQuery(match[1]) : '';
|
|
56
53
|
}
|
|
57
|
-
this.routes.push({re: re as RegExp, handler});
|
|
58
|
-
return this;
|
|
59
54
|
}
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
.sort((r1, r2) => {
|
|
66
|
-
const [n1, n2] = [r1, r2].map(r => r.re.source.split('/'))
|
|
67
|
-
return n2.length - n1.length
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
.map(r => {
|
|
71
|
-
return {r, match: fragment.match(r.re)}
|
|
72
|
-
});
|
|
73
|
-
if (!matches.length) {
|
|
74
|
-
console.warn(`No routing found for ${fragment}`)
|
|
75
|
-
return
|
|
56
|
+
public add(pattern: RegExp | RouteHandler, handler?: RouteHandler): Router {
|
|
57
|
+
if (typeof pattern === 'function') {
|
|
58
|
+
handler = pattern;
|
|
59
|
+
pattern = /^.*$/; // Match any path
|
|
76
60
|
}
|
|
77
|
-
|
|
78
|
-
const longestMatch = matches[0]
|
|
79
|
-
longestMatch.match.shift()
|
|
80
|
-
longestMatch.r.handler.apply({}, longestMatch.match)
|
|
61
|
+
this.routes.push({ pattern, handler: handler as RouteHandler });
|
|
81
62
|
return this;
|
|
82
63
|
}
|
|
83
64
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
65
|
+
public process(location?: string): Router {
|
|
66
|
+
const path = location || this.getLocation();
|
|
67
|
+
if (this.isStaticFile(path))
|
|
68
|
+
return this; // Bypass routing for static files
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
for (const route of this.routes) {
|
|
72
|
+
const match = path.match(route.pattern);
|
|
73
|
+
if (match) {
|
|
74
|
+
match.shift(); // Remove the full match element
|
|
75
|
+
route.handler.apply({}, match);
|
|
76
|
+
return this;
|
|
91
77
|
}
|
|
92
78
|
}
|
|
79
|
+
|
|
80
|
+
console.warn(`No routing found for ${path}`);
|
|
93
81
|
return this;
|
|
94
82
|
}
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
listen(): void {
|
|
85
|
+
const currentLocation = this.getLocation();
|
|
86
|
+
if (this.baseLocation !== currentLocation) {
|
|
87
|
+
this.baseLocation = currentLocation;
|
|
88
|
+
this.process(currentLocation);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public navigate(path: string = ''): Router {
|
|
98
93
|
if (this.mode === 'history') {
|
|
99
94
|
history.pushState(null, null, this.root + this.clearSlashes(path));
|
|
100
95
|
} else {
|
|
101
|
-
|
|
102
|
-
window.location.href = window.location.href.replace(/#(.*)$/, '') + path;
|
|
103
|
-
this.process()
|
|
96
|
+
window.location.hash = '#' + this.clearSlashes(path);
|
|
104
97
|
}
|
|
105
98
|
return this;
|
|
106
99
|
}
|
|
107
100
|
}
|
|
108
101
|
|
|
102
|
+
export const router = new Router();
|
package/tsconfig.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
3
|
+
"target": "ES2022",
|
|
4
4
|
"lib": [
|
|
5
5
|
"DOM",
|
|
6
|
-
"
|
|
6
|
+
"ES2022"
|
|
7
7
|
],
|
|
8
8
|
"module": "ES6",
|
|
9
9
|
"moduleResolution": "Node",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"exclude": [
|
|
19
|
+
"dist/",
|
|
19
20
|
"node_modules",
|
|
20
21
|
"**/__tests__/*"
|
|
21
22
|
]
|