@alepha/react 0.14.1 → 0.14.3
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/auth/index.browser.js +1488 -4
- package/dist/auth/index.browser.js.map +1 -1
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +1827 -4
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +58 -937
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +139 -2014
- package/dist/core/index.js.map +1 -1
- package/dist/form/index.d.ts.map +1 -1
- package/dist/form/index.js +6 -1
- package/dist/form/index.js.map +1 -1
- package/dist/head/index.browser.js +3 -1
- package/dist/head/index.browser.js.map +1 -1
- package/dist/head/index.d.ts +552 -8
- package/dist/head/index.d.ts.map +1 -1
- package/dist/head/index.js +17 -2
- package/dist/head/index.js.map +1 -1
- package/dist/{core → router}/index.browser.js +126 -516
- package/dist/router/index.browser.js.map +1 -0
- package/dist/router/index.d.ts +1334 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +1939 -0
- package/dist/router/index.js.map +1 -0
- package/package.json +12 -6
- package/src/auth/__tests__/$auth.spec.ts +188 -0
- package/src/auth/index.ts +1 -1
- package/src/auth/services/ReactAuth.ts +1 -1
- package/src/core/__tests__/Router.spec.tsx +169 -0
- package/src/core/components/ClientOnly.tsx +14 -0
- package/src/core/components/ErrorBoundary.tsx +3 -2
- package/src/core/contexts/AlephaContext.ts +3 -0
- package/src/core/contexts/AlephaProvider.tsx +2 -1
- package/src/core/hooks/useAction.browser.spec.tsx +569 -0
- package/src/core/hooks/useAction.ts +11 -0
- package/src/core/index.ts +13 -102
- package/src/form/hooks/useForm.browser.spec.tsx +366 -0
- package/src/form/services/FormModel.ts +5 -0
- package/src/head/__tests__/expandSeo.spec.ts +203 -0
- package/src/head/__tests__/page-head.spec.ts +39 -0
- package/src/head/__tests__/seo-head.spec.ts +121 -0
- package/src/head/hooks/useHead.spec.tsx +288 -0
- package/src/head/index.ts +18 -8
- package/src/head/interfaces/Head.ts +3 -0
- package/src/head/providers/BrowserHeadProvider.browser.spec.ts +271 -0
- package/src/head/providers/HeadProvider.ts +6 -1
- package/src/head/providers/ServerHeadProvider.spec.ts +163 -0
- package/src/head/providers/ServerHeadProvider.ts +20 -0
- package/src/i18n/__tests__/integration.spec.tsx +239 -0
- package/src/i18n/components/Localize.spec.tsx +357 -0
- package/src/i18n/hooks/useI18n.browser.spec.tsx +438 -0
- package/src/i18n/providers/I18nProvider.spec.ts +389 -0
- package/src/{core → router}/components/ErrorViewer.tsx +2 -0
- package/src/router/components/Link.tsx +21 -0
- package/src/{core → router}/components/NestedView.tsx +3 -5
- package/src/router/components/NotFound.tsx +30 -0
- package/src/router/errors/Redirection.ts +28 -0
- package/src/{core → router}/hooks/useActive.ts +6 -2
- package/src/{core → router}/hooks/useQueryParams.ts +2 -2
- package/src/{core → router}/hooks/useRouter.ts +1 -1
- package/src/{core → router}/hooks/useRouterState.ts +1 -1
- package/src/{core → router}/index.browser.ts +14 -12
- package/src/{core/index.shared-router.ts → router/index.shared.ts} +6 -3
- package/src/router/index.ts +125 -0
- package/src/router/primitives/$page.browser.spec.tsx +702 -0
- package/src/router/primitives/$page.spec.tsx +702 -0
- package/src/{core → router}/primitives/$page.ts +1 -1
- package/src/{core → router}/providers/ReactBrowserProvider.ts +3 -13
- package/src/{core → router}/providers/ReactBrowserRendererProvider.ts +3 -0
- package/src/{core → router}/providers/ReactBrowserRouterProvider.ts +3 -0
- package/src/{core → router}/providers/ReactPageProvider.ts +5 -3
- package/src/router/providers/ReactServerProvider.spec.tsx +316 -0
- package/src/{core → router}/providers/ReactServerProvider.ts +12 -30
- package/src/{core → router}/services/ReactPageServerService.ts +3 -0
- package/src/{core → router}/services/ReactPageService.ts +5 -5
- package/src/{core → router}/services/ReactRouter.ts +26 -5
- package/dist/core/index.browser.js.map +0 -1
- package/dist/core/index.native.js +0 -403
- package/dist/core/index.native.js.map +0 -1
- package/src/core/components/Link.tsx +0 -18
- package/src/core/components/NotFound.tsx +0 -27
- package/src/core/errors/Redirection.ts +0 -13
- package/src/core/hooks/useSchema.ts +0 -88
- package/src/core/index.native.ts +0 -21
- package/src/core/index.shared.ts +0 -9
- /package/src/{core → router}/contexts/RouterLayerContext.ts +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Alepha, t } from "alepha";
|
|
2
|
+
import { renderToString } from "react-dom/server";
|
|
3
|
+
import { test } from "vitest";
|
|
4
|
+
import { NestedView } from "../../router/index.ts";
|
|
5
|
+
import { ReactBrowserRouterProvider } from "../../router/providers/ReactBrowserRouterProvider.ts";
|
|
6
|
+
|
|
7
|
+
const setup = () => {
|
|
8
|
+
const alepha = Alepha.create();
|
|
9
|
+
const router = alepha.inject(ReactBrowserRouterProvider);
|
|
10
|
+
|
|
11
|
+
const render = async (path: string): Promise<string> => {
|
|
12
|
+
await router.transition(new URL(`http://localhost${path}`));
|
|
13
|
+
const state = alepha.store.get("alepha.react.router.state");
|
|
14
|
+
if (!state) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
"Router state not found. Ensure the router is properly configured.",
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
const element = router.root(state);
|
|
20
|
+
return renderToString(element).replaceAll("<!-- -->", "");
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
router,
|
|
25
|
+
render,
|
|
26
|
+
alepha,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
test("Router - Basic", async ({ expect }) => {
|
|
31
|
+
const { router, render, alepha } = setup();
|
|
32
|
+
|
|
33
|
+
router.add({
|
|
34
|
+
name: "Test",
|
|
35
|
+
path: "/",
|
|
36
|
+
component: () => "Hey",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
router.add({
|
|
40
|
+
name: "NotFound",
|
|
41
|
+
path: "/*",
|
|
42
|
+
component: () => "Not Found",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await alepha.start();
|
|
46
|
+
|
|
47
|
+
expect(await render("/")).toEqual("Hey");
|
|
48
|
+
expect(await render("/zz")).toEqual("Not Found");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("Router - NestedView", async ({ expect }) => {
|
|
52
|
+
const { router, render, alepha } = setup();
|
|
53
|
+
|
|
54
|
+
router.add({
|
|
55
|
+
name: "Test",
|
|
56
|
+
component: () => (
|
|
57
|
+
<>
|
|
58
|
+
((
|
|
59
|
+
<NestedView />
|
|
60
|
+
))
|
|
61
|
+
</>
|
|
62
|
+
),
|
|
63
|
+
children: [
|
|
64
|
+
{
|
|
65
|
+
name: "Home",
|
|
66
|
+
path: "/",
|
|
67
|
+
component: () => "Home",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "Hello",
|
|
71
|
+
path: "/hello/:name",
|
|
72
|
+
schema: {
|
|
73
|
+
params: t.object({
|
|
74
|
+
name: t.text(),
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
resolve: ({ params }) => params,
|
|
78
|
+
component: (props) => `Hello, ${props.name}!`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await alepha.start();
|
|
84
|
+
|
|
85
|
+
expect(await render("/")).toEqual("((Home))");
|
|
86
|
+
expect(await render("/hello/jack")).toEqual("((Hello, jack!))");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("Router - All routes", async ({ expect }) => {
|
|
90
|
+
const { router, render, alepha } = setup();
|
|
91
|
+
|
|
92
|
+
router.add({
|
|
93
|
+
children: [
|
|
94
|
+
{
|
|
95
|
+
path: "/*",
|
|
96
|
+
component: () => "404",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
component: () => "home",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
path: "about",
|
|
103
|
+
component: () => "about",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
path: "sub",
|
|
107
|
+
children: [
|
|
108
|
+
{
|
|
109
|
+
component: () => "a",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
path: "b",
|
|
113
|
+
component: () => "b",
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
path: "users",
|
|
119
|
+
component: () => <NestedView>yo</NestedView>,
|
|
120
|
+
children: [
|
|
121
|
+
{
|
|
122
|
+
path: "new",
|
|
123
|
+
component: () => "users/new",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
path: ":id",
|
|
127
|
+
schema: { params: t.object({ id: t.text() }) },
|
|
128
|
+
resolve: ({ params }) => {
|
|
129
|
+
if (params.id === "boom") throw new Error("boom");
|
|
130
|
+
return params;
|
|
131
|
+
},
|
|
132
|
+
children: [
|
|
133
|
+
{
|
|
134
|
+
resolve: ({ params }) => params,
|
|
135
|
+
component: ({ id }) => `hey ${id}`,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
path: "profile",
|
|
139
|
+
resolve: ({ params }) => params,
|
|
140
|
+
component: ({ id }) => `profile of ${id}`,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
errorHandler: (error) => {
|
|
146
|
+
return `Error: ${error.message}`;
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await alepha.start();
|
|
153
|
+
|
|
154
|
+
expect(await render("/")).toEqual("home");
|
|
155
|
+
expect(await render("/about")).toEqual("about");
|
|
156
|
+
expect(await render("/noop")).toEqual("404");
|
|
157
|
+
expect(await render("/noop/noop")).toEqual("404");
|
|
158
|
+
expect(await render("/sub")).toEqual("a");
|
|
159
|
+
expect(await render("/sub/")).toEqual("a");
|
|
160
|
+
expect(await render("/sub/b")).toEqual("b");
|
|
161
|
+
expect(await render("/sub/noop")).toEqual("404");
|
|
162
|
+
expect(await render("/users")).toEqual("yo");
|
|
163
|
+
expect(await render("/users/")).toEqual("yo");
|
|
164
|
+
expect(await render("/users/a")).toEqual("hey a");
|
|
165
|
+
expect(await render("/users/boom")).toEqual("Error: boom");
|
|
166
|
+
expect(await render("/users/new")).toEqual("users/new");
|
|
167
|
+
expect(await render("/users/hey/ho")).toEqual("404");
|
|
168
|
+
expect(await render("/users/a/profile")).toEqual("profile of a");
|
|
169
|
+
});
|
|
@@ -19,6 +19,20 @@ export interface ClientOnlyProps {
|
|
|
19
19
|
* - you have code that relies on browser-specific APIs
|
|
20
20
|
* - you want to avoid server-side rendering for a specific part of your application
|
|
21
21
|
* - you want to prevent pre-rendering of a component
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { ClientOnly } from "@alepha/react";
|
|
26
|
+
*
|
|
27
|
+
* const MyComponent = () => {
|
|
28
|
+
* // Avoids SSR issues with Date API
|
|
29
|
+
* return (
|
|
30
|
+
* <ClientOnly>
|
|
31
|
+
* {new Date().toLocaleTimeString()}
|
|
32
|
+
* </ClientOnly>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
22
36
|
*/
|
|
23
37
|
const ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {
|
|
24
38
|
const [mounted, setMounted] = useState(false);
|
|
@@ -29,8 +29,9 @@ interface ErrorBoundaryState {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* A reusable error boundary for catching rendering errors
|
|
33
|
-
*
|
|
32
|
+
* A reusable error boundary for catching rendering errors in any part of the React component tree.
|
|
33
|
+
*
|
|
34
|
+
* It's already included in the Alepha React framework when using page or layout components.
|
|
34
35
|
*/
|
|
35
36
|
export class ErrorBoundary extends React.Component<
|
|
36
37
|
PropsWithChildren<ErrorBoundaryProps>,
|
|
@@ -10,7 +10,8 @@ export interface AlephaProviderProps {
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* AlephaProvider component to initialize and provide Alepha instance to the app.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
|
+
* This isn't recommended for apps using `@alepha/react/router`, as Router will handle this for you.
|
|
14
15
|
*/
|
|
15
16
|
export const AlephaProvider = (props: AlephaProviderProps) => {
|
|
16
17
|
const alepha = useMemo(() => Alepha.create(), []);
|