@cosystem/router 0.0.2 → 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/dist/index.d.ts +27 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -4
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Plugin, ProviderInput, Token } from "@cosystem/core";
|
|
1
|
+
import { App, Plugin, ProviderInput, Token } from "@cosystem/core";
|
|
2
2
|
|
|
3
3
|
//#region src/index.d.ts
|
|
4
4
|
interface RouteLocation {
|
|
@@ -14,11 +14,35 @@ interface Router {
|
|
|
14
14
|
interface RouterOptions {
|
|
15
15
|
readonly initialPath?: string;
|
|
16
16
|
}
|
|
17
|
+
interface BrowserRouterOptions {
|
|
18
|
+
readonly window?: BrowserWindowLike;
|
|
19
|
+
}
|
|
20
|
+
interface BrowserWindowLike {
|
|
21
|
+
readonly location: BrowserLocationLike;
|
|
22
|
+
readonly history: BrowserHistoryLike;
|
|
23
|
+
addEventListener(type: "popstate", listener: () => void): void;
|
|
24
|
+
removeEventListener(type: "popstate", listener: () => void): void;
|
|
25
|
+
}
|
|
26
|
+
interface BrowserLocationLike {
|
|
27
|
+
readonly pathname: string;
|
|
28
|
+
readonly search: string;
|
|
29
|
+
readonly hash: string;
|
|
30
|
+
}
|
|
31
|
+
interface BrowserHistoryLike {
|
|
32
|
+
pushState(data: unknown, unused: string, url?: string | URL | null): void;
|
|
33
|
+
}
|
|
34
|
+
interface RouterPluginOptions {
|
|
35
|
+
readonly immediate?: boolean;
|
|
36
|
+
readonly onChange?: (location: RouteLocation, app: App) => void | Promise<void>;
|
|
37
|
+
readonly onError?: (error: unknown) => void;
|
|
38
|
+
}
|
|
17
39
|
declare const RouterToken: Token<Router>;
|
|
18
40
|
declare function createMemoryRouter(options?: RouterOptions): Router;
|
|
19
|
-
declare function
|
|
41
|
+
declare function createBrowserRouter(options?: BrowserRouterOptions): Router;
|
|
42
|
+
declare function createRouterPlugin(router: Router, options?: RouterPluginOptions): Plugin;
|
|
20
43
|
declare function provideRouter(router?: Router): ProviderInput;
|
|
21
44
|
declare function parseLocation(value: string): RouteLocation;
|
|
45
|
+
declare function formatLocation(location: RouteLocation): string;
|
|
22
46
|
//#endregion
|
|
23
|
-
export { RouteLocation, Router, RouterOptions, RouterToken, createMemoryRouter, createRouterPlugin, parseLocation, provideRouter };
|
|
47
|
+
export { BrowserHistoryLike, BrowserLocationLike, BrowserRouterOptions, BrowserWindowLike, RouteLocation, Router, RouterOptions, RouterPluginOptions, RouterToken, createBrowserRouter, createMemoryRouter, createRouterPlugin, formatLocation, parseLocation, provideRouter };
|
|
24
48
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;UASiB,aAAA;EAAA,SACN,IAAA;EAAA,SACA,MAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,MAAA;EAAA,SACN,OAAA,EAAS,aAAA;EAClB,QAAA,CAAS,EAAA,WAAa,aAAA;EACtB,SAAA,CAAU,QAAA,GAAW,QAAA,EAAU,aAAA;AAAA;AAAA,UAGhB,aAAA;EAAA,SACN,WAAA;AAAA;AAAA,UAGM,oBAAA;EAAA,SACN,MAAA,GAAS,iBAAA;AAAA;AAAA,UAGH,iBAAA;EAAA,SACN,QAAA,EAAU,mBAAA;EAAA,SACV,OAAA,EAAS,kBAAA;EAClB,gBAAA,CAAiB,IAAA,cAAkB,QAAA;EACnC,mBAAA,CAAoB,IAAA,cAAkB,QAAA;AAAA;AAAA,UAGvB,mBAAA;EAAA,SACN,QAAA;EAAA,SACA,MAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,kBAAA;EACf,SAAA,CAAU,IAAA,WAAe,MAAA,UAAgB,GAAA,YAAe,GAAA;AAAA;AAAA,UAGzC,mBAAA;EAAA,SACN,SAAA;EAAA,SACA,QAAA,IAAY,QAAA,EAAU,aAAA,EAAe,GAAA,EAAK,GAAA,YAAe,OAAA;EAAA,SACzD,OAAA,IAAW,KAAA;AAAA;AAAA,cAGT,WAAA,EAAa,KAAA,CAAM,MAAA;AAAA,iBAEhB,kBAAA,CAAmB,OAAA,GAAS,aAAA,GAAqB,MAAA;AAAA,iBAwBjD,mBAAA,CAAoB,OAAA,GAAS,oBAAA,GAA4B,MAAA;AAAA,iBA2DzD,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,OAAA,GAAS,mBAAA,GAA2B,MAAA;AAAA,iBAqCvE,aAAA,CAAc,MAAA,GAAQ,MAAA,GAAgC,aAAA;AAAA,iBAItD,aAAA,CAAc,KAAA,WAAgB,aAAA;AAAA,iBAe9B,cAAA,CAAe,QAAU,EAAA,aAAA"}
|
package/dist/index.js
CHANGED
|
@@ -20,12 +20,62 @@ function createMemoryRouter(options = {}) {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
function
|
|
23
|
+
function createBrowserRouter(options = {}) {
|
|
24
|
+
const targetWindow = options.window ?? resolveGlobalWindow();
|
|
25
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
26
|
+
let current = readBrowserLocation(targetWindow.location);
|
|
27
|
+
let listening = false;
|
|
28
|
+
const notify = () => {
|
|
29
|
+
current = readBrowserLocation(targetWindow.location);
|
|
30
|
+
for (const listener of listeners) listener(current);
|
|
31
|
+
};
|
|
32
|
+
const start = () => {
|
|
33
|
+
if (listening) return;
|
|
34
|
+
listening = true;
|
|
35
|
+
targetWindow.addEventListener("popstate", notify);
|
|
36
|
+
};
|
|
37
|
+
const stop = () => {
|
|
38
|
+
if (!listening) return;
|
|
39
|
+
listening = false;
|
|
40
|
+
targetWindow.removeEventListener("popstate", notify);
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
get current() {
|
|
44
|
+
return current;
|
|
45
|
+
},
|
|
46
|
+
navigate(to) {
|
|
47
|
+
current = typeof to === "string" ? parseLocation(to) : to;
|
|
48
|
+
targetWindow.history.pushState(null, "", formatLocation(current));
|
|
49
|
+
for (const listener of listeners) listener(current);
|
|
50
|
+
},
|
|
51
|
+
subscribe(listener) {
|
|
52
|
+
listeners.add(listener);
|
|
53
|
+
start();
|
|
54
|
+
return () => {
|
|
55
|
+
listeners.delete(listener);
|
|
56
|
+
if (listeners.size === 0) stop();
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function createRouterPlugin(router, options = {}) {
|
|
24
62
|
let unsubscribe;
|
|
25
63
|
return {
|
|
26
64
|
name: "cosystem:router",
|
|
27
|
-
setup() {
|
|
28
|
-
|
|
65
|
+
setup(app) {
|
|
66
|
+
const notify = (location) => {
|
|
67
|
+
if (options.onChange === void 0) return;
|
|
68
|
+
try {
|
|
69
|
+
const result = options.onChange(location, app);
|
|
70
|
+
if (isPromiseLike(result)) result.catch((error) => {
|
|
71
|
+
options.onError?.(error);
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
options.onError?.(error);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
unsubscribe = router.subscribe(notify);
|
|
78
|
+
if (options.immediate === true) notify(router.current);
|
|
29
79
|
},
|
|
30
80
|
dispose() {
|
|
31
81
|
unsubscribe?.();
|
|
@@ -49,7 +99,25 @@ function parseLocation(value) {
|
|
|
49
99
|
search
|
|
50
100
|
};
|
|
51
101
|
}
|
|
102
|
+
function formatLocation(location) {
|
|
103
|
+
return `${location.path === "" ? "/" : location.path}${location.search}${location.hash}`;
|
|
104
|
+
}
|
|
105
|
+
function readBrowserLocation(location) {
|
|
106
|
+
return {
|
|
107
|
+
hash: location.hash,
|
|
108
|
+
path: location.pathname === "" ? "/" : location.pathname,
|
|
109
|
+
search: location.search
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function resolveGlobalWindow() {
|
|
113
|
+
const globalWithWindow = globalThis;
|
|
114
|
+
if (globalWithWindow.window !== void 0) return globalWithWindow.window;
|
|
115
|
+
throw new Error("createBrowserRouter() requires a browser window.");
|
|
116
|
+
}
|
|
117
|
+
function isPromiseLike(value) {
|
|
118
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
119
|
+
}
|
|
52
120
|
//#endregion
|
|
53
|
-
export { RouterToken, createMemoryRouter, createRouterPlugin, parseLocation, provideRouter };
|
|
121
|
+
export { RouterToken, createBrowserRouter, createMemoryRouter, createRouterPlugin, formatLocation, parseLocation, provideRouter };
|
|
54
122
|
|
|
55
123
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n provide,\n token,\n type App,\n type Plugin,\n type ProviderInput,\n type Token,\n} from \"@cosystem/core\";\n\nexport interface RouteLocation {\n readonly path: string;\n readonly search: string;\n readonly hash: string;\n}\n\nexport interface Router {\n readonly current: RouteLocation;\n navigate(to: string | RouteLocation): void;\n subscribe(listener: (location: RouteLocation) => void): () => void;\n}\n\nexport interface RouterOptions {\n readonly initialPath?: string;\n}\n\nexport interface BrowserRouterOptions {\n readonly window?: BrowserWindowLike;\n}\n\nexport interface BrowserWindowLike {\n readonly location: BrowserLocationLike;\n readonly history: BrowserHistoryLike;\n addEventListener(type: \"popstate\", listener: () => void): void;\n removeEventListener(type: \"popstate\", listener: () => void): void;\n}\n\nexport interface BrowserLocationLike {\n readonly pathname: string;\n readonly search: string;\n readonly hash: string;\n}\n\nexport interface BrowserHistoryLike {\n pushState(data: unknown, unused: string, url?: string | URL | null): void;\n}\n\nexport interface RouterPluginOptions {\n readonly immediate?: boolean;\n readonly onChange?: (location: RouteLocation, app: App) => void | Promise<void>;\n readonly onError?: (error: unknown) => void;\n}\n\nexport const RouterToken: Token<Router> = token<Router>(\"CoSystem Router\");\n\nexport function createMemoryRouter(options: RouterOptions = {}): Router {\n const listeners = new Set<(location: RouteLocation) => void>();\n let current = parseLocation(options.initialPath ?? \"/\");\n\n return {\n get current() {\n return current;\n },\n navigate(to) {\n current = typeof to === \"string\" ? parseLocation(to) : to;\n\n for (const listener of listeners) {\n listener(current);\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n\nexport function createBrowserRouter(options: BrowserRouterOptions = {}): Router {\n const targetWindow = options.window ?? resolveGlobalWindow();\n const listeners = new Set<(location: RouteLocation) => void>();\n let current = readBrowserLocation(targetWindow.location);\n let listening = false;\n\n const notify = () => {\n current = readBrowserLocation(targetWindow.location);\n\n for (const listener of listeners) {\n listener(current);\n }\n };\n\n const start = () => {\n if (listening) {\n return;\n }\n\n listening = true;\n targetWindow.addEventListener(\"popstate\", notify);\n };\n\n const stop = () => {\n if (!listening) {\n return;\n }\n\n listening = false;\n targetWindow.removeEventListener(\"popstate\", notify);\n };\n\n return {\n get current() {\n return current;\n },\n navigate(to) {\n current = typeof to === \"string\" ? parseLocation(to) : to;\n targetWindow.history.pushState(null, \"\", formatLocation(current));\n\n for (const listener of listeners) {\n listener(current);\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n start();\n\n return () => {\n listeners.delete(listener);\n\n if (listeners.size === 0) {\n stop();\n }\n };\n },\n };\n}\n\nexport function createRouterPlugin(router: Router, options: RouterPluginOptions = {}): Plugin {\n let unsubscribe: (() => void) | undefined;\n\n return {\n name: \"cosystem:router\",\n setup(app) {\n const notify = (location: RouteLocation): void => {\n if (options.onChange === undefined) {\n return;\n }\n\n try {\n const result = options.onChange(location, app);\n\n if (isPromiseLike(result)) {\n void result.catch((error: unknown) => {\n options.onError?.(error);\n });\n }\n } catch (error) {\n options.onError?.(error);\n }\n };\n\n unsubscribe = router.subscribe(notify);\n\n if (options.immediate === true) {\n notify(router.current);\n }\n },\n dispose() {\n unsubscribe?.();\n unsubscribe = undefined;\n },\n };\n}\n\nexport function provideRouter(router: Router = createMemoryRouter()): ProviderInput {\n return provide(RouterToken, { useValue: router });\n}\n\nexport function parseLocation(value: string): RouteLocation {\n const hashIndex = value.indexOf(\"#\");\n const withoutHash = hashIndex === -1 ? value : value.slice(0, hashIndex);\n const hash = hashIndex === -1 ? \"\" : value.slice(hashIndex);\n const searchIndex = withoutHash.indexOf(\"?\");\n const path = searchIndex === -1 ? withoutHash : withoutHash.slice(0, searchIndex);\n const search = searchIndex === -1 ? \"\" : withoutHash.slice(searchIndex);\n\n return {\n hash,\n path: path === \"\" ? \"/\" : path,\n search,\n };\n}\n\nexport function formatLocation(location: RouteLocation): string {\n return `${location.path === \"\" ? \"/\" : location.path}${location.search}${location.hash}`;\n}\n\nfunction readBrowserLocation(location: BrowserLocationLike): RouteLocation {\n return {\n hash: location.hash,\n path: location.pathname === \"\" ? \"/\" : location.pathname,\n search: location.search,\n };\n}\n\nfunction resolveGlobalWindow(): BrowserWindowLike {\n const globalWithWindow = globalThis as { readonly window?: BrowserWindowLike };\n\n if (globalWithWindow.window !== undefined) {\n return globalWithWindow.window;\n }\n\n throw new Error(\"createBrowserRouter() requires a browser window.\");\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"then\" in value &&\n typeof (value as { readonly then?: unknown }).then === \"function\"\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosystem/router",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Router integration primitives for CoSystem.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/coactionjs/cosystem.git",
|
|
9
|
+
"directory": "packages/router"
|
|
10
|
+
},
|
|
6
11
|
"files": [
|
|
7
12
|
"dist"
|
|
8
13
|
],
|
|
@@ -20,7 +25,7 @@
|
|
|
20
25
|
"access": "public"
|
|
21
26
|
},
|
|
22
27
|
"dependencies": {
|
|
23
|
-
"@cosystem/core": "0.0
|
|
28
|
+
"@cosystem/core": "1.0.0"
|
|
24
29
|
},
|
|
25
30
|
"devDependencies": {
|
|
26
31
|
"tsdown": "0.22.3",
|