@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.
Files changed (86) hide show
  1. package/dist/auth/index.browser.js +1488 -4
  2. package/dist/auth/index.browser.js.map +1 -1
  3. package/dist/auth/index.d.ts +2 -2
  4. package/dist/auth/index.js +1827 -4
  5. package/dist/auth/index.js.map +1 -1
  6. package/dist/core/index.d.ts +58 -937
  7. package/dist/core/index.d.ts.map +1 -1
  8. package/dist/core/index.js +139 -2014
  9. package/dist/core/index.js.map +1 -1
  10. package/dist/form/index.d.ts.map +1 -1
  11. package/dist/form/index.js +6 -1
  12. package/dist/form/index.js.map +1 -1
  13. package/dist/head/index.browser.js +3 -1
  14. package/dist/head/index.browser.js.map +1 -1
  15. package/dist/head/index.d.ts +552 -8
  16. package/dist/head/index.d.ts.map +1 -1
  17. package/dist/head/index.js +17 -2
  18. package/dist/head/index.js.map +1 -1
  19. package/dist/{core → router}/index.browser.js +126 -516
  20. package/dist/router/index.browser.js.map +1 -0
  21. package/dist/router/index.d.ts +1334 -0
  22. package/dist/router/index.d.ts.map +1 -0
  23. package/dist/router/index.js +1939 -0
  24. package/dist/router/index.js.map +1 -0
  25. package/package.json +12 -6
  26. package/src/auth/__tests__/$auth.spec.ts +188 -0
  27. package/src/auth/index.ts +1 -1
  28. package/src/auth/services/ReactAuth.ts +1 -1
  29. package/src/core/__tests__/Router.spec.tsx +169 -0
  30. package/src/core/components/ClientOnly.tsx +14 -0
  31. package/src/core/components/ErrorBoundary.tsx +3 -2
  32. package/src/core/contexts/AlephaContext.ts +3 -0
  33. package/src/core/contexts/AlephaProvider.tsx +2 -1
  34. package/src/core/hooks/useAction.browser.spec.tsx +569 -0
  35. package/src/core/hooks/useAction.ts +11 -0
  36. package/src/core/index.ts +13 -102
  37. package/src/form/hooks/useForm.browser.spec.tsx +366 -0
  38. package/src/form/services/FormModel.ts +5 -0
  39. package/src/head/__tests__/expandSeo.spec.ts +203 -0
  40. package/src/head/__tests__/page-head.spec.ts +39 -0
  41. package/src/head/__tests__/seo-head.spec.ts +121 -0
  42. package/src/head/hooks/useHead.spec.tsx +288 -0
  43. package/src/head/index.ts +18 -8
  44. package/src/head/interfaces/Head.ts +3 -0
  45. package/src/head/providers/BrowserHeadProvider.browser.spec.ts +271 -0
  46. package/src/head/providers/HeadProvider.ts +6 -1
  47. package/src/head/providers/ServerHeadProvider.spec.ts +163 -0
  48. package/src/head/providers/ServerHeadProvider.ts +20 -0
  49. package/src/i18n/__tests__/integration.spec.tsx +239 -0
  50. package/src/i18n/components/Localize.spec.tsx +357 -0
  51. package/src/i18n/hooks/useI18n.browser.spec.tsx +438 -0
  52. package/src/i18n/providers/I18nProvider.spec.ts +389 -0
  53. package/src/{core → router}/components/ErrorViewer.tsx +2 -0
  54. package/src/router/components/Link.tsx +21 -0
  55. package/src/{core → router}/components/NestedView.tsx +3 -5
  56. package/src/router/components/NotFound.tsx +30 -0
  57. package/src/router/errors/Redirection.ts +28 -0
  58. package/src/{core → router}/hooks/useActive.ts +6 -2
  59. package/src/{core → router}/hooks/useQueryParams.ts +2 -2
  60. package/src/{core → router}/hooks/useRouter.ts +1 -1
  61. package/src/{core → router}/hooks/useRouterState.ts +1 -1
  62. package/src/{core → router}/index.browser.ts +14 -12
  63. package/src/{core/index.shared-router.ts → router/index.shared.ts} +6 -3
  64. package/src/router/index.ts +125 -0
  65. package/src/router/primitives/$page.browser.spec.tsx +702 -0
  66. package/src/router/primitives/$page.spec.tsx +702 -0
  67. package/src/{core → router}/primitives/$page.ts +1 -1
  68. package/src/{core → router}/providers/ReactBrowserProvider.ts +3 -13
  69. package/src/{core → router}/providers/ReactBrowserRendererProvider.ts +3 -0
  70. package/src/{core → router}/providers/ReactBrowserRouterProvider.ts +3 -0
  71. package/src/{core → router}/providers/ReactPageProvider.ts +5 -3
  72. package/src/router/providers/ReactServerProvider.spec.tsx +316 -0
  73. package/src/{core → router}/providers/ReactServerProvider.ts +12 -30
  74. package/src/{core → router}/services/ReactPageServerService.ts +3 -0
  75. package/src/{core → router}/services/ReactPageService.ts +5 -5
  76. package/src/{core → router}/services/ReactRouter.ts +26 -5
  77. package/dist/core/index.browser.js.map +0 -1
  78. package/dist/core/index.native.js +0 -403
  79. package/dist/core/index.native.js.map +0 -1
  80. package/src/core/components/Link.tsx +0 -18
  81. package/src/core/components/NotFound.tsx +0 -27
  82. package/src/core/errors/Redirection.ts +0 -13
  83. package/src/core/hooks/useSchema.ts +0 -88
  84. package/src/core/index.native.ts +0 -21
  85. package/src/core/index.shared.ts +0 -9
  86. /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
- * in any part of the React component tree.
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>,
@@ -1,4 +1,7 @@
1
1
  import type { Alepha } from "alepha";
2
2
  import { createContext } from "react";
3
3
 
4
+ /**
5
+ * React context to provide the Alepha instance throughout the component tree.
6
+ */
4
7
  export const AlephaContext = createContext<Alepha | undefined>(undefined);
@@ -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
- * This isn't recommended for apps using alepha/react/router, as Router will handle this for you.
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(), []);