@alepha/react 0.6.0 → 0.6.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/dist/index.browser.cjs +0 -0
- package/dist/index.browser.js +0 -0
- package/dist/index.cjs +11 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -14
- package/package.json +4 -4
- package/src/components/Link.tsx +0 -22
- package/src/components/NestedView.tsx +0 -36
- package/src/constants/SSID.ts +0 -1
- package/src/contexts/RouterContext.ts +0 -15
- package/src/contexts/RouterLayerContext.ts +0 -10
- package/src/descriptors/$auth.ts +0 -28
- package/src/descriptors/$page.ts +0 -144
- package/src/errors/RedirectionError.ts +0 -7
- package/src/hooks/RouterHookApi.ts +0 -154
- package/src/hooks/useActive.ts +0 -57
- package/src/hooks/useAuth.ts +0 -29
- package/src/hooks/useClient.ts +0 -6
- package/src/hooks/useInject.ts +0 -12
- package/src/hooks/useQueryParams.ts +0 -59
- package/src/hooks/useRouter.ts +0 -28
- package/src/hooks/useRouterEvents.ts +0 -43
- package/src/hooks/useRouterState.ts +0 -23
- package/src/index.browser.ts +0 -21
- package/src/index.shared.ts +0 -28
- package/src/index.ts +0 -46
- package/src/providers/PageDescriptorProvider.ts +0 -52
- package/src/providers/ReactAuthProvider.ts +0 -410
- package/src/providers/ReactBrowserProvider.ts +0 -250
- package/src/providers/ReactServerProvider.ts +0 -301
- package/src/services/Auth.ts +0 -45
- package/src/services/Router.ts +0 -855
package/dist/index.browser.cjs
CHANGED
|
File without changes
|
package/dist/index.browser.js
CHANGED
|
File without changes
|
package/dist/index.cjs
CHANGED
|
@@ -142,7 +142,7 @@ class ReactAuthProvider {
|
|
|
142
142
|
*/
|
|
143
143
|
login = server.$route({
|
|
144
144
|
security: false,
|
|
145
|
-
|
|
145
|
+
internal: true,
|
|
146
146
|
url: "/_oauth/login",
|
|
147
147
|
group: "auth",
|
|
148
148
|
method: "GET",
|
|
@@ -153,13 +153,13 @@ class ReactAuthProvider {
|
|
|
153
153
|
})
|
|
154
154
|
},
|
|
155
155
|
handler: async ({ query, cookies, url }) => {
|
|
156
|
-
const { client } = this.provider(query.provider);
|
|
156
|
+
const { client, redirectUri } = this.provider(query.provider);
|
|
157
157
|
const codeVerifier = openidClient.randomPKCECodeVerifier();
|
|
158
158
|
const codeChallenge = await openidClient.calculatePKCECodeChallenge(codeVerifier);
|
|
159
159
|
const scope = "openid profile email";
|
|
160
|
-
let redirect_uri =
|
|
160
|
+
let redirect_uri = redirectUri;
|
|
161
161
|
if (redirect_uri.startsWith("/")) {
|
|
162
|
-
redirect_uri = `${url.protocol}
|
|
162
|
+
redirect_uri = `${url.protocol}//${url.host}${redirect_uri}`;
|
|
163
163
|
}
|
|
164
164
|
const parameters = {
|
|
165
165
|
redirect_uri,
|
|
@@ -184,7 +184,7 @@ class ReactAuthProvider {
|
|
|
184
184
|
*/
|
|
185
185
|
callback = server.$route({
|
|
186
186
|
security: false,
|
|
187
|
-
|
|
187
|
+
internal: true,
|
|
188
188
|
url: "/_oauth/callback",
|
|
189
189
|
group: "auth",
|
|
190
190
|
method: "GET",
|
|
@@ -246,7 +246,7 @@ class ReactAuthProvider {
|
|
|
246
246
|
*/
|
|
247
247
|
logout = server.$route({
|
|
248
248
|
security: false,
|
|
249
|
-
|
|
249
|
+
internal: true,
|
|
250
250
|
url: "/_oauth/logout",
|
|
251
251
|
group: "auth",
|
|
252
252
|
method: "GET",
|
|
@@ -339,7 +339,7 @@ class ReactServerProvider {
|
|
|
339
339
|
}
|
|
340
340
|
if (process.env.VITE_ALEPHA_DEV === "true") {
|
|
341
341
|
this.log.info("SSR (vite) OK");
|
|
342
|
-
const templateUrl =
|
|
342
|
+
const templateUrl = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}/index.html`;
|
|
343
343
|
this.log.debug(`Fetch template from ${templateUrl}`);
|
|
344
344
|
const route2 = this.createHandler(
|
|
345
345
|
() => fetch(templateUrl).then((it) => it.text()).catch(() => void 0).then((it) => it ? this.checkTemplate(it) : void 0)
|
|
@@ -434,10 +434,7 @@ class ReactServerProvider {
|
|
|
434
434
|
if (response) {
|
|
435
435
|
return response;
|
|
436
436
|
}
|
|
437
|
-
return await this.ssr(ctx.url, template,
|
|
438
|
-
user: ctx.user,
|
|
439
|
-
cookies: ctx.cookies
|
|
440
|
-
});
|
|
437
|
+
return await this.ssr(ctx.url, template, ctx);
|
|
441
438
|
}
|
|
442
439
|
};
|
|
443
440
|
}
|
|
@@ -479,13 +476,13 @@ class ReactServerProvider {
|
|
|
479
476
|
*
|
|
480
477
|
* @param url
|
|
481
478
|
* @param template
|
|
482
|
-
* @param
|
|
479
|
+
* @param args
|
|
483
480
|
*/
|
|
484
|
-
async ssr(url, template = this.env.REACT_SSR_OUTLET,
|
|
481
|
+
async ssr(url, template = this.env.REACT_SSR_OUTLET, args = {}) {
|
|
485
482
|
const { element, layers, redirect, context } = await this.router.render(
|
|
486
483
|
url.pathname + url.search,
|
|
487
484
|
{
|
|
488
|
-
args
|
|
485
|
+
args
|
|
489
486
|
}
|
|
490
487
|
);
|
|
491
488
|
if (redirect) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1014,9 +1014,9 @@ declare class ReactServerProvider {
|
|
|
1014
1014
|
*
|
|
1015
1015
|
* @param url
|
|
1016
1016
|
* @param template
|
|
1017
|
-
* @param
|
|
1017
|
+
* @param args
|
|
1018
1018
|
*/
|
|
1019
|
-
ssr(url: URL, template?: string,
|
|
1019
|
+
ssr(url: URL, template?: string, args?: PageContext): Promise<Response>;
|
|
1020
1020
|
protected renderHelmetContext(template: string, helmetContext: RouterRenderHelmetContext): string;
|
|
1021
1021
|
}
|
|
1022
1022
|
|
package/dist/index.js
CHANGED
|
@@ -141,7 +141,7 @@ class ReactAuthProvider {
|
|
|
141
141
|
*/
|
|
142
142
|
login = $route({
|
|
143
143
|
security: false,
|
|
144
|
-
|
|
144
|
+
internal: true,
|
|
145
145
|
url: "/_oauth/login",
|
|
146
146
|
group: "auth",
|
|
147
147
|
method: "GET",
|
|
@@ -152,13 +152,13 @@ class ReactAuthProvider {
|
|
|
152
152
|
})
|
|
153
153
|
},
|
|
154
154
|
handler: async ({ query, cookies, url }) => {
|
|
155
|
-
const { client } = this.provider(query.provider);
|
|
155
|
+
const { client, redirectUri } = this.provider(query.provider);
|
|
156
156
|
const codeVerifier = randomPKCECodeVerifier();
|
|
157
157
|
const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
|
|
158
158
|
const scope = "openid profile email";
|
|
159
|
-
let redirect_uri =
|
|
159
|
+
let redirect_uri = redirectUri;
|
|
160
160
|
if (redirect_uri.startsWith("/")) {
|
|
161
|
-
redirect_uri = `${url.protocol}
|
|
161
|
+
redirect_uri = `${url.protocol}//${url.host}${redirect_uri}`;
|
|
162
162
|
}
|
|
163
163
|
const parameters = {
|
|
164
164
|
redirect_uri,
|
|
@@ -183,7 +183,7 @@ class ReactAuthProvider {
|
|
|
183
183
|
*/
|
|
184
184
|
callback = $route({
|
|
185
185
|
security: false,
|
|
186
|
-
|
|
186
|
+
internal: true,
|
|
187
187
|
url: "/_oauth/callback",
|
|
188
188
|
group: "auth",
|
|
189
189
|
method: "GET",
|
|
@@ -245,7 +245,7 @@ class ReactAuthProvider {
|
|
|
245
245
|
*/
|
|
246
246
|
logout = $route({
|
|
247
247
|
security: false,
|
|
248
|
-
|
|
248
|
+
internal: true,
|
|
249
249
|
url: "/_oauth/logout",
|
|
250
250
|
group: "auth",
|
|
251
251
|
method: "GET",
|
|
@@ -338,7 +338,7 @@ class ReactServerProvider {
|
|
|
338
338
|
}
|
|
339
339
|
if (process.env.VITE_ALEPHA_DEV === "true") {
|
|
340
340
|
this.log.info("SSR (vite) OK");
|
|
341
|
-
const templateUrl =
|
|
341
|
+
const templateUrl = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}/index.html`;
|
|
342
342
|
this.log.debug(`Fetch template from ${templateUrl}`);
|
|
343
343
|
const route2 = this.createHandler(
|
|
344
344
|
() => fetch(templateUrl).then((it) => it.text()).catch(() => void 0).then((it) => it ? this.checkTemplate(it) : void 0)
|
|
@@ -433,10 +433,7 @@ class ReactServerProvider {
|
|
|
433
433
|
if (response) {
|
|
434
434
|
return response;
|
|
435
435
|
}
|
|
436
|
-
return await this.ssr(ctx.url, template,
|
|
437
|
-
user: ctx.user,
|
|
438
|
-
cookies: ctx.cookies
|
|
439
|
-
});
|
|
436
|
+
return await this.ssr(ctx.url, template, ctx);
|
|
440
437
|
}
|
|
441
438
|
};
|
|
442
439
|
}
|
|
@@ -478,13 +475,13 @@ class ReactServerProvider {
|
|
|
478
475
|
*
|
|
479
476
|
* @param url
|
|
480
477
|
* @param template
|
|
481
|
-
* @param
|
|
478
|
+
* @param args
|
|
482
479
|
*/
|
|
483
|
-
async ssr(url, template = this.env.REACT_SSR_OUTLET,
|
|
480
|
+
async ssr(url, template = this.env.REACT_SSR_OUTLET, args = {}) {
|
|
484
481
|
const { element, layers, redirect, context } = await this.router.render(
|
|
485
482
|
url.pathname + url.search,
|
|
486
483
|
{
|
|
487
|
-
args
|
|
484
|
+
args
|
|
488
485
|
}
|
|
489
486
|
);
|
|
490
487
|
if (redirect) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alepha/react",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"./dist/index.js": "./dist/index.browser.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@alepha/core": "0.6.
|
|
13
|
-
"@alepha/security": "0.6.
|
|
14
|
-
"@alepha/server": "0.6.
|
|
12
|
+
"@alepha/core": "0.6.1",
|
|
13
|
+
"@alepha/security": "0.6.1",
|
|
14
|
+
"@alepha/server": "0.6.1",
|
|
15
15
|
"openid-client": "^6.4.2",
|
|
16
16
|
"path-to-regexp": "^8.2.0",
|
|
17
17
|
"react-dom": "^18.3.1"
|
package/src/components/Link.tsx
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { AnchorHTMLAttributes } from "react";
|
|
3
|
-
import { RouterContext } from "../contexts/RouterContext";
|
|
4
|
-
import { useRouter } from "../hooks/useRouter";
|
|
5
|
-
|
|
6
|
-
export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
7
|
-
to: string;
|
|
8
|
-
children?: React.ReactNode;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const Link = (props: LinkProps) => {
|
|
12
|
-
React.useContext(RouterContext);
|
|
13
|
-
|
|
14
|
-
const router = useRouter();
|
|
15
|
-
return (
|
|
16
|
-
<a {...router.createAnchorProps(props.to)} {...props}>
|
|
17
|
-
{props.children}
|
|
18
|
-
</a>
|
|
19
|
-
);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default Link;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import { useContext, useEffect, useState } from "react";
|
|
3
|
-
import { RouterContext } from "../contexts/RouterContext";
|
|
4
|
-
import { RouterLayerContext } from "../contexts/RouterLayerContext";
|
|
5
|
-
|
|
6
|
-
export interface NestedViewProps {
|
|
7
|
-
children?: ReactNode;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Nested view component
|
|
12
|
-
*
|
|
13
|
-
* @param props
|
|
14
|
-
* @constructor
|
|
15
|
-
*/
|
|
16
|
-
const NestedView = (props: NestedViewProps) => {
|
|
17
|
-
const app = useContext(RouterContext);
|
|
18
|
-
const layer = useContext(RouterLayerContext);
|
|
19
|
-
const index = layer?.index ?? 0;
|
|
20
|
-
|
|
21
|
-
const [view, setView] = useState<ReactNode | undefined>(
|
|
22
|
-
app?.state.layers[index]?.element,
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (app?.alepha.isBrowser()) {
|
|
27
|
-
return app?.router.on("end", (state) => {
|
|
28
|
-
setView(state.layers[index]?.element);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}, [app]);
|
|
32
|
-
|
|
33
|
-
return view ?? props.children ?? null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default NestedView;
|
package/src/constants/SSID.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const SSID = "ssid";
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Alepha } from "@alepha/core";
|
|
2
|
-
import { createContext } from "react";
|
|
3
|
-
import type { PageContext } from "../descriptors/$page";
|
|
4
|
-
import type { Router, RouterState } from "../services/Router";
|
|
5
|
-
|
|
6
|
-
export interface RouterContextValue {
|
|
7
|
-
router: Router;
|
|
8
|
-
alepha: Alepha;
|
|
9
|
-
state: RouterState;
|
|
10
|
-
args: PageContext;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const RouterContext = createContext<RouterContextValue | undefined>(
|
|
14
|
-
undefined,
|
|
15
|
-
);
|
package/src/descriptors/$auth.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { KIND, __descriptor } from "@alepha/core";
|
|
2
|
-
|
|
3
|
-
const KEY = "AUTH";
|
|
4
|
-
|
|
5
|
-
export interface AuthDescriptorOptions {
|
|
6
|
-
name?: string;
|
|
7
|
-
oidc?: {
|
|
8
|
-
issuer: string;
|
|
9
|
-
clientId: string;
|
|
10
|
-
clientSecret?: string;
|
|
11
|
-
redirectUri?: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface AuthDescriptor {
|
|
16
|
-
[KIND]: typeof KEY;
|
|
17
|
-
options: AuthDescriptorOptions;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const $auth = (options: AuthDescriptorOptions): AuthDescriptor => {
|
|
21
|
-
__descriptor(KEY);
|
|
22
|
-
return {
|
|
23
|
-
[KIND]: KEY,
|
|
24
|
-
options,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
$auth[KIND] = KEY;
|
package/src/descriptors/$page.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import type { Async, Static, TSchema } from "@alepha/core";
|
|
2
|
-
import { KIND, NotImplementedError, __descriptor } from "@alepha/core";
|
|
3
|
-
import type { UserAccountToken } from "@alepha/security";
|
|
4
|
-
import type { CookieManager } from "@alepha/server";
|
|
5
|
-
import type { FC } from "react";
|
|
6
|
-
import type { RouterHookApi } from "../hooks/RouterHookApi";
|
|
7
|
-
import {} from "../services/Router";
|
|
8
|
-
import type { RouterRenderHelmetContext } from "../services/Router";
|
|
9
|
-
|
|
10
|
-
export const pageDescriptorKey = "PAGE";
|
|
11
|
-
|
|
12
|
-
export interface PageDescriptorConfigSchema {
|
|
13
|
-
query?: TSchema;
|
|
14
|
-
params?: TSchema;
|
|
15
|
-
}
|
|
16
|
-
export type TPropsDefault = any;
|
|
17
|
-
export type TPropsParentDefault = object;
|
|
18
|
-
|
|
19
|
-
export interface PageDescriptorOptions<
|
|
20
|
-
TConfig extends PageDescriptorConfigSchema = PageDescriptorConfigSchema,
|
|
21
|
-
TProps extends object = TPropsDefault,
|
|
22
|
-
TPropsParent extends object = TPropsParentDefault,
|
|
23
|
-
> {
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
*/
|
|
27
|
-
name?: string;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
|
-
path?: string;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
*
|
|
36
|
-
*/
|
|
37
|
-
schema?: TConfig;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Function to call when the page is loaded.
|
|
41
|
-
*/
|
|
42
|
-
resolve?: (
|
|
43
|
-
config: PageDescriptorConfigValue<TConfig> &
|
|
44
|
-
TPropsParent & { context: PageContext },
|
|
45
|
-
context: PageContext,
|
|
46
|
-
) => Async<TProps>;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Component to render when the page is loaded.
|
|
50
|
-
*/
|
|
51
|
-
component?: FC<TProps & TPropsParent>;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Component to render when the page is loaded. (like .component)
|
|
55
|
-
*/
|
|
56
|
-
lazy?: () => Promise<{ default: FC<TProps & TPropsParent> }>;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
*/
|
|
61
|
-
children?: () => Array<{ options: PageDescriptorOptions }>;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
66
|
-
parent?: { options: PageDescriptorOptions<any, TPropsParent> };
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
*
|
|
70
|
-
*/
|
|
71
|
-
helmet?:
|
|
72
|
-
| RouterRenderHelmetContext
|
|
73
|
-
| ((props: TProps) => RouterRenderHelmetContext);
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
*
|
|
77
|
-
*/
|
|
78
|
-
notFoundHandler?: FC<{ error: Error }>;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
*
|
|
82
|
-
*/
|
|
83
|
-
errorHandler?: FC<{ error: Error; url: string }>;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface PageContext {
|
|
87
|
-
user?: UserAccountToken;
|
|
88
|
-
cookies?: CookieManager;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface PageDescriptorConfigValue<
|
|
92
|
-
TConfig extends PageDescriptorConfigSchema = PageDescriptorConfigSchema,
|
|
93
|
-
> {
|
|
94
|
-
query: TConfig["query"] extends TSchema
|
|
95
|
-
? Static<TConfig["query"]>
|
|
96
|
-
: Record<string, string>;
|
|
97
|
-
params: TConfig["params"] extends TSchema
|
|
98
|
-
? Static<TConfig["params"]>
|
|
99
|
-
: Record<string, string>;
|
|
100
|
-
pathname: string;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export interface PageDescriptor<
|
|
104
|
-
TConfig extends PageDescriptorConfigSchema = PageDescriptorConfigSchema,
|
|
105
|
-
TProps extends object = TPropsDefault,
|
|
106
|
-
TPropsParent extends object = TPropsParentDefault,
|
|
107
|
-
> {
|
|
108
|
-
[KIND]: typeof pageDescriptorKey;
|
|
109
|
-
render: (options?: {
|
|
110
|
-
params?: Record<string, string>;
|
|
111
|
-
query?: Record<string, string>;
|
|
112
|
-
}) => Promise<string>;
|
|
113
|
-
go: () => void;
|
|
114
|
-
createAnchorProps: (routerHook: RouterHookApi) => {
|
|
115
|
-
href: string;
|
|
116
|
-
onClick: () => void;
|
|
117
|
-
};
|
|
118
|
-
options: PageDescriptorOptions<TConfig, TProps, TPropsParent>;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export const $page = <
|
|
122
|
-
TConfig extends PageDescriptorConfigSchema = PageDescriptorConfigSchema,
|
|
123
|
-
TProps extends object = TPropsDefault,
|
|
124
|
-
TPropsParent extends object = TPropsParentDefault,
|
|
125
|
-
>(
|
|
126
|
-
options: PageDescriptorOptions<TConfig, TProps, TPropsParent>,
|
|
127
|
-
): PageDescriptor<TConfig, TProps, TPropsParent> => {
|
|
128
|
-
__descriptor(pageDescriptorKey);
|
|
129
|
-
return {
|
|
130
|
-
[KIND]: pageDescriptorKey,
|
|
131
|
-
options,
|
|
132
|
-
render: () => {
|
|
133
|
-
throw new NotImplementedError(pageDescriptorKey);
|
|
134
|
-
},
|
|
135
|
-
go: () => {
|
|
136
|
-
throw new NotImplementedError(pageDescriptorKey);
|
|
137
|
-
},
|
|
138
|
-
createAnchorProps: () => {
|
|
139
|
-
throw new NotImplementedError(pageDescriptorKey);
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
$page[KIND] = pageDescriptorKey;
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import {} from "react";
|
|
2
|
-
import type {
|
|
3
|
-
ReactBrowserProvider,
|
|
4
|
-
RouterGoOptions,
|
|
5
|
-
} from "../providers/ReactBrowserProvider";
|
|
6
|
-
import type { AnchorProps, RouterState } from "../services/Router";
|
|
7
|
-
|
|
8
|
-
export class RouterHookApi {
|
|
9
|
-
constructor(
|
|
10
|
-
private readonly state: RouterState,
|
|
11
|
-
private readonly layer: {
|
|
12
|
-
path: string;
|
|
13
|
-
},
|
|
14
|
-
private readonly browser?: ReactBrowserProvider,
|
|
15
|
-
) {}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
|
-
public get current(): RouterState {
|
|
21
|
-
return this.state;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
*/
|
|
27
|
-
public get pathname(): string {
|
|
28
|
-
return this.state.pathname;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
public get query(): Record<string, string> {
|
|
35
|
-
const query: Record<string, string> = {};
|
|
36
|
-
|
|
37
|
-
for (const [key, value] of new URLSearchParams(
|
|
38
|
-
this.state.search,
|
|
39
|
-
).entries()) {
|
|
40
|
-
query[key] = String(value);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return query;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
*/
|
|
49
|
-
public async back() {
|
|
50
|
-
this.browser?.history.back();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
public async forward() {
|
|
57
|
-
this.browser?.history.forward();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
*
|
|
62
|
-
* @param props
|
|
63
|
-
*/
|
|
64
|
-
public async invalidate(props?: Record<string, any>) {
|
|
65
|
-
await this.browser?.invalidate(props);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Create a valid href for the given pathname.
|
|
70
|
-
*
|
|
71
|
-
* @param pathname
|
|
72
|
-
* @param layer
|
|
73
|
-
*/
|
|
74
|
-
public createHref(pathname: HrefLike, layer: { path: string } = this.layer) {
|
|
75
|
-
if (typeof pathname === "object") {
|
|
76
|
-
pathname = pathname.options.path ?? "";
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return pathname.startsWith("/")
|
|
80
|
-
? pathname
|
|
81
|
-
: `${layer.path}/${pathname}`.replace(/\/\/+/g, "/");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
*
|
|
86
|
-
* @param path
|
|
87
|
-
* @param options
|
|
88
|
-
*/
|
|
89
|
-
public async go(
|
|
90
|
-
path: HrefLike,
|
|
91
|
-
options: RouterGoOptions = {},
|
|
92
|
-
): Promise<void> {
|
|
93
|
-
return await this.browser?.go(this.createHref(path, this.layer), options);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
*
|
|
98
|
-
* @param path
|
|
99
|
-
*/
|
|
100
|
-
public createAnchorProps(path: string): AnchorProps {
|
|
101
|
-
const href = this.createHref(path, this.layer);
|
|
102
|
-
return {
|
|
103
|
-
href,
|
|
104
|
-
onClick: (ev: any) => {
|
|
105
|
-
ev.stopPropagation();
|
|
106
|
-
ev.preventDefault();
|
|
107
|
-
|
|
108
|
-
this.go(path).catch(console.error);
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Set query params.
|
|
115
|
-
*
|
|
116
|
-
* @param record
|
|
117
|
-
* @param options
|
|
118
|
-
*/
|
|
119
|
-
public setQueryParams(
|
|
120
|
-
record: Record<string, any>,
|
|
121
|
-
options: {
|
|
122
|
-
/**
|
|
123
|
-
* If true, this will merge current query params with the new ones.
|
|
124
|
-
*/
|
|
125
|
-
merge?: boolean;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* If true, this will add a new entry to the history stack.
|
|
129
|
-
*/
|
|
130
|
-
push?: boolean;
|
|
131
|
-
} = {},
|
|
132
|
-
) {
|
|
133
|
-
const search = new URLSearchParams(
|
|
134
|
-
options.merge
|
|
135
|
-
? {
|
|
136
|
-
...this.query,
|
|
137
|
-
...record,
|
|
138
|
-
}
|
|
139
|
-
: {
|
|
140
|
-
...record,
|
|
141
|
-
},
|
|
142
|
-
).toString();
|
|
143
|
-
|
|
144
|
-
const state = search ? `${this.pathname}?${search}` : this.pathname;
|
|
145
|
-
|
|
146
|
-
if (options.push) {
|
|
147
|
-
window.history.pushState({}, "", state);
|
|
148
|
-
} else {
|
|
149
|
-
window.history.replaceState({}, "", state);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export type HrefLike = string | { options: { path?: string; name?: string } };
|
package/src/hooks/useActive.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { useContext, useEffect, useMemo, useState } from "react";
|
|
2
|
-
import { RouterContext } from "../contexts/RouterContext";
|
|
3
|
-
import { RouterLayerContext } from "../contexts/RouterLayerContext";
|
|
4
|
-
import type { AnchorProps } from "../services/Router";
|
|
5
|
-
import type { HrefLike } from "./RouterHookApi";
|
|
6
|
-
import { useRouter } from "./useRouter";
|
|
7
|
-
|
|
8
|
-
export const useActive = (path: HrefLike): UseActiveHook => {
|
|
9
|
-
const router = useRouter();
|
|
10
|
-
const ctx = useContext(RouterContext);
|
|
11
|
-
const layer = useContext(RouterLayerContext);
|
|
12
|
-
if (!ctx || !layer) {
|
|
13
|
-
throw new Error("useRouter must be used within a RouterProvider");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let name: string | undefined;
|
|
17
|
-
if (typeof path === "object" && path.options.name) {
|
|
18
|
-
name = path.options.name;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const [current, setCurrent] = useState(ctx.state.pathname);
|
|
22
|
-
const href = useMemo(() => router.createHref(path, layer), [path, layer]);
|
|
23
|
-
const [isPending, setPending] = useState(false);
|
|
24
|
-
const isActive = current === href;
|
|
25
|
-
|
|
26
|
-
useEffect(
|
|
27
|
-
() => ctx.router.on("end", ({ pathname }) => setCurrent(pathname)),
|
|
28
|
-
[],
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
name,
|
|
33
|
-
isPending,
|
|
34
|
-
isActive,
|
|
35
|
-
anchorProps: {
|
|
36
|
-
href,
|
|
37
|
-
onClick: (ev: any) => {
|
|
38
|
-
ev.stopPropagation();
|
|
39
|
-
ev.preventDefault();
|
|
40
|
-
if (isActive) return;
|
|
41
|
-
if (isPending) return;
|
|
42
|
-
|
|
43
|
-
setPending(true);
|
|
44
|
-
router.go(href).then(() => {
|
|
45
|
-
setPending(false);
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export interface UseActiveHook {
|
|
53
|
-
isActive: boolean;
|
|
54
|
-
anchorProps: AnchorProps;
|
|
55
|
-
isPending: boolean;
|
|
56
|
-
name?: string;
|
|
57
|
-
}
|