@alepha/react 0.9.3 → 0.9.5
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 +64 -6
- package/dist/index.browser.js +442 -328
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +644 -482
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +402 -339
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +412 -349
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +641 -484
- package/dist/index.js.map +1 -1
- package/package.json +16 -11
- package/src/components/Link.tsx +2 -5
- package/src/components/NestedView.tsx +164 -19
- package/src/components/NotFound.tsx +1 -1
- package/src/descriptors/$page.ts +100 -5
- package/src/errors/Redirection.ts +8 -5
- package/src/hooks/useActive.ts +25 -35
- package/src/hooks/useAlepha.ts +16 -2
- package/src/hooks/useClient.ts +7 -4
- package/src/hooks/useInject.ts +4 -1
- package/src/hooks/useQueryParams.ts +9 -6
- package/src/hooks/useRouter.ts +18 -31
- package/src/hooks/useRouterEvents.ts +30 -22
- package/src/hooks/useRouterState.ts +8 -20
- package/src/hooks/useSchema.ts +10 -15
- package/src/hooks/useStore.ts +0 -7
- package/src/index.browser.ts +14 -11
- package/src/index.shared.ts +2 -3
- package/src/index.ts +27 -31
- package/src/providers/ReactBrowserProvider.ts +151 -62
- package/src/providers/ReactBrowserRendererProvider.ts +22 -0
- package/src/providers/ReactBrowserRouterProvider.ts +137 -0
- package/src/providers/{PageDescriptorProvider.ts → ReactPageProvider.ts} +121 -104
- package/src/providers/ReactServerProvider.ts +90 -76
- package/src/{hooks/RouterHookApi.ts → services/ReactRouter.ts} +49 -62
- package/src/contexts/RouterContext.ts +0 -14
- package/src/providers/BrowserRouterProvider.ts +0 -155
- package/src/providers/ReactBrowserRenderer.ts +0 -93
package/src/hooks/useRouter.ts
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { RouterLayerContext } from "../contexts/RouterLayerContext.ts";
|
|
4
|
-
import { PageDescriptorProvider } from "../providers/PageDescriptorProvider.ts";
|
|
5
|
-
import { ReactBrowserProvider } from "../providers/ReactBrowserProvider.ts";
|
|
6
|
-
import { RouterHookApi } from "./RouterHookApi.ts";
|
|
7
|
-
import { useAlepha } from "./useAlepha.ts";
|
|
1
|
+
import { ReactRouter } from "../services/ReactRouter.ts";
|
|
2
|
+
import { useInject } from "./useInject.ts";
|
|
8
3
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
ctx.context,
|
|
26
|
-
ctx.state,
|
|
27
|
-
layer,
|
|
28
|
-
alepha.inject(PageDescriptorProvider),
|
|
29
|
-
alepha.isBrowser() ? alepha.inject(ReactBrowserProvider) : undefined,
|
|
30
|
-
),
|
|
31
|
-
[layer],
|
|
32
|
-
);
|
|
4
|
+
/**
|
|
5
|
+
* Use this hook to access the React Router instance.
|
|
6
|
+
*
|
|
7
|
+
* You can add a type parameter to specify the type of your application.
|
|
8
|
+
* This will allow you to use the router in a typesafe way.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* class App {
|
|
12
|
+
* home = $page();
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* const router = useRouter<App>();
|
|
16
|
+
* router.go("home"); // typesafe
|
|
17
|
+
*/
|
|
18
|
+
export const useRouter = <T extends object = any>(): ReactRouter<T> => {
|
|
19
|
+
return useInject(ReactRouter<T>);
|
|
33
20
|
};
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
import type { Hooks } from "@alepha/core";
|
|
1
2
|
import { useEffect } from "react";
|
|
2
|
-
import type {
|
|
3
|
-
PageReactContext,
|
|
4
|
-
RouterState,
|
|
5
|
-
} from "../providers/PageDescriptorProvider.ts";
|
|
6
3
|
import { useAlepha } from "./useAlepha.ts";
|
|
7
4
|
|
|
5
|
+
type Hook<T extends keyof Hooks> =
|
|
6
|
+
| ((ev: Hooks[T]) => void)
|
|
7
|
+
| {
|
|
8
|
+
priority?: "first" | "last";
|
|
9
|
+
callback: (ev: Hooks[T]) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to various router events.
|
|
14
|
+
*/
|
|
8
15
|
export const useRouterEvents = (
|
|
9
16
|
opts: {
|
|
10
|
-
onBegin?:
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
onBegin?: Hook<"react:transition:begin">;
|
|
18
|
+
onError?: Hook<"react:transition:error">;
|
|
19
|
+
onEnd?: Hook<"react:transition:end">;
|
|
20
|
+
onSuccess?: Hook<"react:transition:success">;
|
|
13
21
|
} = {},
|
|
14
22
|
deps: any[] = [],
|
|
15
23
|
) => {
|
|
@@ -20,33 +28,33 @@ export const useRouterEvents = (
|
|
|
20
28
|
return;
|
|
21
29
|
}
|
|
22
30
|
|
|
31
|
+
const cb = <T extends keyof Hooks>(callback: Hook<T>) => {
|
|
32
|
+
if (typeof callback === "function") {
|
|
33
|
+
return { callback };
|
|
34
|
+
}
|
|
35
|
+
return callback;
|
|
36
|
+
};
|
|
37
|
+
|
|
23
38
|
const subs: Function[] = [];
|
|
24
39
|
const onBegin = opts.onBegin;
|
|
25
40
|
const onEnd = opts.onEnd;
|
|
26
41
|
const onError = opts.onError;
|
|
42
|
+
const onSuccess = opts.onSuccess;
|
|
27
43
|
|
|
28
44
|
if (onBegin) {
|
|
29
|
-
subs.push(
|
|
30
|
-
alepha.on("react:transition:begin", {
|
|
31
|
-
callback: onBegin,
|
|
32
|
-
}),
|
|
33
|
-
);
|
|
45
|
+
subs.push(alepha.on("react:transition:begin", cb(onBegin)));
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
if (onEnd) {
|
|
37
|
-
subs.push(
|
|
38
|
-
alepha.on("react:transition:end", {
|
|
39
|
-
callback: onEnd,
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
49
|
+
subs.push(alepha.on("react:transition:end", cb(onEnd)));
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
if (onError) {
|
|
45
|
-
subs.push(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
53
|
+
subs.push(alepha.on("react:transition:error", cb(onError)));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (onSuccess) {
|
|
57
|
+
subs.push(alepha.on("react:transition:success", cb(onSuccess)));
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
return () => {
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const layer = useContext(RouterLayerContext);
|
|
10
|
-
if (!router || !layer) {
|
|
11
|
-
throw new Error(
|
|
12
|
-
"useRouterState must be used within a RouterContext.Provider",
|
|
13
|
-
);
|
|
1
|
+
import { AlephaError } from "@alepha/core";
|
|
2
|
+
import type { ReactRouterState } from "../providers/ReactPageProvider.ts";
|
|
3
|
+
import { useStore } from "./useStore.ts";
|
|
4
|
+
|
|
5
|
+
export const useRouterState = (): ReactRouterState => {
|
|
6
|
+
const [state] = useStore("react.router.state");
|
|
7
|
+
if (!state) {
|
|
8
|
+
throw new AlephaError("Missing react router state");
|
|
14
9
|
}
|
|
15
|
-
|
|
16
|
-
const [state, setState] = useState(router.state);
|
|
17
|
-
|
|
18
|
-
useRouterEvents({
|
|
19
|
-
onEnd: ({ state }) => setState({ ...state }),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
10
|
return state;
|
|
23
11
|
};
|
package/src/hooks/useSchema.ts
CHANGED
|
@@ -4,11 +4,7 @@ import {
|
|
|
4
4
|
HttpClient,
|
|
5
5
|
type RequestConfigSchema,
|
|
6
6
|
} from "@alepha/server";
|
|
7
|
-
import {
|
|
8
|
-
type HttpClientLink,
|
|
9
|
-
LinkProvider,
|
|
10
|
-
type VirtualAction,
|
|
11
|
-
} from "@alepha/server-links";
|
|
7
|
+
import { LinkProvider, type VirtualAction } from "@alepha/server-links";
|
|
12
8
|
import { useEffect, useState } from "react";
|
|
13
9
|
import { useAlepha } from "./useAlepha.ts";
|
|
14
10
|
import { useInject } from "./useInject.ts";
|
|
@@ -19,7 +15,6 @@ export const useSchema = <TConfig extends RequestConfigSchema>(
|
|
|
19
15
|
const name = action.name;
|
|
20
16
|
const alepha = useAlepha();
|
|
21
17
|
const httpClient = useInject(HttpClient);
|
|
22
|
-
const linkProvider = useInject(LinkProvider);
|
|
23
18
|
const [schema, setSchema] = useState<UseSchemaReturn<TConfig>>(
|
|
24
19
|
ssrSchemaLoading(alepha, name) as UseSchemaReturn<TConfig>,
|
|
25
20
|
);
|
|
@@ -34,7 +29,7 @@ export const useSchema = <TConfig extends RequestConfigSchema>(
|
|
|
34
29
|
};
|
|
35
30
|
|
|
36
31
|
httpClient
|
|
37
|
-
.fetch(`${
|
|
32
|
+
.fetch(`${LinkProvider.path.apiLinks}/${name}/schema`, {}, opts)
|
|
38
33
|
.then((it) => setSchema(it.data as UseSchemaReturn<TConfig>));
|
|
39
34
|
}, [name]);
|
|
40
35
|
|
|
@@ -54,26 +49,26 @@ export const ssrSchemaLoading = (alepha: Alepha, name: string) => {
|
|
|
54
49
|
// server-side rendering (SSR) context
|
|
55
50
|
if (!alepha.isBrowser()) {
|
|
56
51
|
// get user links
|
|
57
|
-
const
|
|
58
|
-
alepha.context.get<{ links: HttpClientLink[] }>("links")?.links ?? [];
|
|
52
|
+
const linkProvider = alepha.inject(LinkProvider);
|
|
59
53
|
|
|
60
54
|
// check if user can access the link
|
|
61
|
-
const can =
|
|
55
|
+
const can = linkProvider
|
|
56
|
+
.getServerLinks()
|
|
57
|
+
.find((link) => link.name === name);
|
|
62
58
|
|
|
63
59
|
// yes!
|
|
64
60
|
if (can) {
|
|
65
61
|
// user-links have no schema, so we need to get it from the provider
|
|
66
|
-
const schema =
|
|
67
|
-
.inject(LinkProvider)
|
|
68
|
-
.links?.find((it) => it.name === name)?.schema;
|
|
62
|
+
const schema = linkProvider.links.find((it) => it.name === name)?.schema;
|
|
69
63
|
|
|
70
64
|
// oh, we have a schema!
|
|
71
65
|
if (schema) {
|
|
72
|
-
// attach to user link, it will be used in the client during hydration
|
|
66
|
+
// attach to user link, it will be used in the client during hydration
|
|
73
67
|
can.schema = schema;
|
|
74
68
|
return schema;
|
|
75
69
|
}
|
|
76
70
|
}
|
|
71
|
+
|
|
77
72
|
return { loading: true };
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -81,7 +76,7 @@ export const ssrSchemaLoading = (alepha: Alepha, name: string) => {
|
|
|
81
76
|
// check if we have the schema already loaded
|
|
82
77
|
const schema = alepha
|
|
83
78
|
.inject(LinkProvider)
|
|
84
|
-
.links
|
|
79
|
+
.links.find((it) => it.name === name)?.schema;
|
|
85
80
|
|
|
86
81
|
// yes!
|
|
87
82
|
if (schema) {
|
package/src/hooks/useStore.ts
CHANGED
|
@@ -31,13 +31,6 @@ export const useStore = <Key extends keyof State>(
|
|
|
31
31
|
});
|
|
32
32
|
}, []);
|
|
33
33
|
|
|
34
|
-
if (!alepha.isBrowser()) {
|
|
35
|
-
const value = alepha.context.get(key) as State[Key];
|
|
36
|
-
if (value !== null) {
|
|
37
|
-
return [value, (_: State[Key]) => {}] as const;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
34
|
return [
|
|
42
35
|
state,
|
|
43
36
|
(value: State[Key]) => {
|
package/src/index.browser.ts
CHANGED
|
@@ -2,17 +2,18 @@ import { $module } from "@alepha/core";
|
|
|
2
2
|
import { AlephaServer } from "@alepha/server";
|
|
3
3
|
import { AlephaServerLinks } from "@alepha/server-links";
|
|
4
4
|
import { $page } from "./descriptors/$page.ts";
|
|
5
|
-
import { BrowserRouterProvider } from "./providers/BrowserRouterProvider.ts";
|
|
6
|
-
import { PageDescriptorProvider } from "./providers/PageDescriptorProvider.ts";
|
|
7
5
|
import { ReactBrowserProvider } from "./providers/ReactBrowserProvider.ts";
|
|
8
|
-
import {
|
|
6
|
+
import { ReactBrowserRendererProvider } from "./providers/ReactBrowserRendererProvider.ts";
|
|
7
|
+
import { ReactBrowserRouterProvider } from "./providers/ReactBrowserRouterProvider.ts";
|
|
8
|
+
import { ReactPageProvider } from "./providers/ReactPageProvider.ts";
|
|
9
|
+
import { ReactRouter } from "./services/ReactRouter.ts";
|
|
9
10
|
|
|
10
11
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
11
12
|
|
|
12
13
|
export * from "./index.shared.ts";
|
|
13
|
-
export * from "./providers/BrowserRouterProvider.ts";
|
|
14
|
-
export * from "./providers/PageDescriptorProvider.ts";
|
|
15
14
|
export * from "./providers/ReactBrowserProvider.ts";
|
|
15
|
+
export * from "./providers/ReactBrowserRouterProvider.ts";
|
|
16
|
+
export * from "./providers/ReactPageProvider.ts";
|
|
16
17
|
|
|
17
18
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
18
19
|
|
|
@@ -20,17 +21,19 @@ export const AlephaReact = $module({
|
|
|
20
21
|
name: "alepha.react",
|
|
21
22
|
descriptors: [$page],
|
|
22
23
|
services: [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
BrowserRouterProvider,
|
|
24
|
+
ReactPageProvider,
|
|
25
|
+
ReactBrowserRouterProvider,
|
|
26
26
|
ReactBrowserProvider,
|
|
27
|
+
ReactRouter,
|
|
28
|
+
ReactBrowserRendererProvider,
|
|
27
29
|
],
|
|
28
30
|
register: (alepha) =>
|
|
29
31
|
alepha
|
|
30
32
|
.with(AlephaServer)
|
|
31
33
|
.with(AlephaServerLinks)
|
|
32
|
-
.with(
|
|
34
|
+
.with(ReactPageProvider)
|
|
33
35
|
.with(ReactBrowserProvider)
|
|
34
|
-
.with(
|
|
35
|
-
.with(
|
|
36
|
+
.with(ReactBrowserRouterProvider)
|
|
37
|
+
.with(ReactBrowserRendererProvider)
|
|
38
|
+
.with(ReactRouter),
|
|
36
39
|
});
|
package/src/index.shared.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
export { default as ClientOnly } from "./components/ClientOnly.tsx";
|
|
2
2
|
export { default as ErrorBoundary } from "./components/ErrorBoundary.tsx";
|
|
3
|
-
export
|
|
3
|
+
export { default as ErrorViewer } from "./components/ErrorViewer.tsx";
|
|
4
4
|
export { default as Link, type LinkProps } from "./components/Link.tsx";
|
|
5
5
|
export { default as NestedView } from "./components/NestedView.tsx";
|
|
6
6
|
export { default as NotFound } from "./components/NotFound.tsx";
|
|
7
7
|
export * from "./contexts/AlephaContext.ts";
|
|
8
|
-
export * from "./contexts/RouterContext.ts";
|
|
9
8
|
export * from "./contexts/RouterLayerContext.ts";
|
|
10
9
|
export * from "./descriptors/$page.ts";
|
|
11
10
|
export * from "./errors/Redirection.ts";
|
|
12
|
-
export * from "./hooks/RouterHookApi.ts";
|
|
13
11
|
export * from "./hooks/useActive.ts";
|
|
14
12
|
export * from "./hooks/useAlepha.ts";
|
|
15
13
|
export * from "./hooks/useClient.ts";
|
|
@@ -20,3 +18,4 @@ export * from "./hooks/useRouterEvents.ts";
|
|
|
20
18
|
export * from "./hooks/useRouterState.ts";
|
|
21
19
|
export * from "./hooks/useSchema.ts";
|
|
22
20
|
export * from "./hooks/useStore.ts";
|
|
21
|
+
export * from "./services/ReactRouter.ts";
|
package/src/index.ts
CHANGED
|
@@ -2,66 +2,61 @@ import { $module } from "@alepha/core";
|
|
|
2
2
|
import { AlephaServer, type ServerRequest } from "@alepha/server";
|
|
3
3
|
import { AlephaServerCache } from "@alepha/server-cache";
|
|
4
4
|
import { AlephaServerLinks } from "@alepha/server-links";
|
|
5
|
-
import {
|
|
5
|
+
import type { ReactNode } from "react";
|
|
6
|
+
import { $page, type PageAnimation } from "./descriptors/$page.ts";
|
|
7
|
+
import type { ReactHydrationState } from "./providers/ReactBrowserProvider.ts";
|
|
6
8
|
import {
|
|
7
|
-
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
type RouterState,
|
|
11
|
-
} from "./providers/PageDescriptorProvider.ts";
|
|
12
|
-
import {
|
|
13
|
-
ReactBrowserProvider,
|
|
14
|
-
type ReactHydrationState,
|
|
15
|
-
} from "./providers/ReactBrowserProvider.ts";
|
|
9
|
+
ReactPageProvider,
|
|
10
|
+
type ReactRouterState,
|
|
11
|
+
} from "./providers/ReactPageProvider.ts";
|
|
16
12
|
import { ReactServerProvider } from "./providers/ReactServerProvider.ts";
|
|
13
|
+
import { ReactRouter } from "./services/ReactRouter.ts";
|
|
17
14
|
|
|
18
15
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
19
16
|
|
|
20
17
|
export * from "./index.shared.ts";
|
|
21
|
-
export * from "./providers/PageDescriptorProvider.ts";
|
|
22
18
|
export * from "./providers/ReactBrowserProvider.ts";
|
|
19
|
+
export * from "./providers/ReactPageProvider.ts";
|
|
23
20
|
export * from "./providers/ReactServerProvider.ts";
|
|
24
21
|
|
|
25
22
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
26
23
|
|
|
27
24
|
declare module "@alepha/core" {
|
|
25
|
+
interface State {
|
|
26
|
+
"react.router.state"?: ReactRouterState;
|
|
27
|
+
}
|
|
28
|
+
|
|
28
29
|
interface Hooks {
|
|
29
|
-
"react:router:createLayers": {
|
|
30
|
-
request: ServerRequest;
|
|
31
|
-
context: PageRequest;
|
|
32
|
-
layers: PageRequest[];
|
|
33
|
-
};
|
|
34
30
|
"react:server:render:begin": {
|
|
35
31
|
request?: ServerRequest;
|
|
36
|
-
|
|
32
|
+
state: ReactRouterState;
|
|
37
33
|
};
|
|
38
34
|
"react:server:render:end": {
|
|
39
35
|
request?: ServerRequest;
|
|
40
|
-
|
|
41
|
-
state: RouterState;
|
|
36
|
+
state: ReactRouterState;
|
|
42
37
|
html: string;
|
|
43
38
|
};
|
|
39
|
+
// -----------------------------------------------------------------------------------------------------------------
|
|
44
40
|
"react:browser:render": {
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
root: HTMLDivElement;
|
|
42
|
+
element: ReactNode;
|
|
43
|
+
state: ReactRouterState;
|
|
47
44
|
hydration?: ReactHydrationState;
|
|
48
45
|
};
|
|
49
46
|
"react:transition:begin": {
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
previous: ReactRouterState;
|
|
48
|
+
state: ReactRouterState;
|
|
49
|
+
animation?: PageAnimation;
|
|
52
50
|
};
|
|
53
51
|
"react:transition:success": {
|
|
54
|
-
state:
|
|
55
|
-
context: PageReactContext;
|
|
52
|
+
state: ReactRouterState;
|
|
56
53
|
};
|
|
57
54
|
"react:transition:error": {
|
|
55
|
+
state: ReactRouterState;
|
|
58
56
|
error: Error;
|
|
59
|
-
state: RouterState;
|
|
60
|
-
context: PageReactContext;
|
|
61
57
|
};
|
|
62
58
|
"react:transition:end": {
|
|
63
|
-
state:
|
|
64
|
-
context: PageReactContext;
|
|
59
|
+
state: ReactRouterState;
|
|
65
60
|
};
|
|
66
61
|
}
|
|
67
62
|
}
|
|
@@ -81,12 +76,13 @@ declare module "@alepha/core" {
|
|
|
81
76
|
export const AlephaReact = $module({
|
|
82
77
|
name: "alepha.react",
|
|
83
78
|
descriptors: [$page],
|
|
84
|
-
services: [ReactServerProvider,
|
|
79
|
+
services: [ReactServerProvider, ReactPageProvider, ReactRouter],
|
|
85
80
|
register: (alepha) =>
|
|
86
81
|
alepha
|
|
87
82
|
.with(AlephaServer)
|
|
88
83
|
.with(AlephaServerCache)
|
|
89
84
|
.with(AlephaServerLinks)
|
|
90
85
|
.with(ReactServerProvider)
|
|
91
|
-
.with(
|
|
86
|
+
.with(ReactPageProvider)
|
|
87
|
+
.with(ReactRouter),
|
|
92
88
|
});
|