@alepha/react 0.9.0 → 0.9.2
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 +7 -0
- package/dist/index.browser.js +104 -41
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +109 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -31
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +56 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -43
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/components/ErrorViewer.tsx +4 -3
- package/src/contexts/AlephaContext.ts +4 -0
- package/src/contexts/RouterContext.ts +0 -2
- package/src/hooks/useAlepha.ts +5 -5
- package/src/hooks/useInject.ts +5 -8
- package/src/hooks/useQueryParams.ts +6 -9
- package/src/hooks/useRouter.ts +4 -4
- package/src/hooks/useRouterEvents.ts +7 -10
- package/src/hooks/useRouterState.ts +6 -4
- package/src/hooks/useSchema.ts +93 -0
- package/src/hooks/useStore.ts +39 -0
- package/src/index.shared.ts +3 -0
- package/src/providers/PageDescriptorProvider.ts +13 -9
- package/src/providers/ReactBrowserProvider.ts +1 -1
- package/src/providers/ReactServerProvider.ts +6 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $env, $hook, $inject, $logger, $module, Alepha, Descriptor, KIND, NotImplementedError, createDescriptor, t } from "@alepha/core";
|
|
2
|
-
import { AlephaServer, ServerRouterProvider, ServerTimingProvider, apiLinksResponseSchema } from "@alepha/server";
|
|
2
|
+
import { AlephaServer, HttpClient, ServerRouterProvider, ServerTimingProvider, apiLinksResponseSchema } from "@alepha/server";
|
|
3
3
|
import { AlephaServerCache } from "@alepha/server-cache";
|
|
4
4
|
import { AlephaServerLinks, LinkProvider, ServerLinksProvider } from "@alepha/server-links";
|
|
5
5
|
import React, { StrictMode, createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
|
|
@@ -51,23 +51,11 @@ const ClientOnly = (props) => {
|
|
|
51
51
|
};
|
|
52
52
|
var ClientOnly_default = ClientOnly;
|
|
53
53
|
|
|
54
|
-
//#endregion
|
|
55
|
-
//#region src/contexts/RouterContext.ts
|
|
56
|
-
const RouterContext = createContext(void 0);
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/hooks/useAlepha.ts
|
|
60
|
-
const useAlepha = () => {
|
|
61
|
-
const routerContext = useContext(RouterContext);
|
|
62
|
-
if (!routerContext) throw new Error("useAlepha must be used within a RouterProvider");
|
|
63
|
-
return routerContext.alepha;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
54
|
//#endregion
|
|
67
55
|
//#region src/components/ErrorViewer.tsx
|
|
68
|
-
const ErrorViewer = ({ error }) => {
|
|
56
|
+
const ErrorViewer = ({ error, alepha }) => {
|
|
69
57
|
const [expanded, setExpanded] = useState(false);
|
|
70
|
-
const isProduction =
|
|
58
|
+
const isProduction = alepha.isProduction();
|
|
71
59
|
if (isProduction) return /* @__PURE__ */ jsx(ErrorViewerProduction, {});
|
|
72
60
|
const stackLines = error.stack?.split("\n") ?? [];
|
|
73
61
|
const previewLines = stackLines.slice(0, 5);
|
|
@@ -211,24 +199,39 @@ const ErrorViewerProduction = () => {
|
|
|
211
199
|
});
|
|
212
200
|
};
|
|
213
201
|
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/contexts/RouterContext.ts
|
|
204
|
+
const RouterContext = createContext(void 0);
|
|
205
|
+
|
|
214
206
|
//#endregion
|
|
215
207
|
//#region src/contexts/RouterLayerContext.ts
|
|
216
208
|
const RouterLayerContext = createContext(void 0);
|
|
217
209
|
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/contexts/AlephaContext.ts
|
|
212
|
+
const AlephaContext = createContext(void 0);
|
|
213
|
+
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/hooks/useAlepha.ts
|
|
216
|
+
const useAlepha = () => {
|
|
217
|
+
const alepha = useContext(AlephaContext);
|
|
218
|
+
if (!alepha) throw new Error("useAlepha must be used within an AlephaContext.Provider");
|
|
219
|
+
return alepha;
|
|
220
|
+
};
|
|
221
|
+
|
|
218
222
|
//#endregion
|
|
219
223
|
//#region src/hooks/useRouterEvents.ts
|
|
220
224
|
const useRouterEvents = (opts = {}, deps = []) => {
|
|
221
|
-
const
|
|
222
|
-
if (!ctx) throw new Error("useRouter must be used within a RouterProvider");
|
|
225
|
+
const alepha = useAlepha();
|
|
223
226
|
useEffect(() => {
|
|
224
|
-
if (!
|
|
227
|
+
if (!alepha.isBrowser()) return;
|
|
225
228
|
const subs = [];
|
|
226
229
|
const onBegin = opts.onBegin;
|
|
227
230
|
const onEnd = opts.onEnd;
|
|
228
231
|
const onError = opts.onError;
|
|
229
|
-
if (onBegin) subs.push(
|
|
230
|
-
if (onEnd) subs.push(
|
|
231
|
-
if (onError) subs.push(
|
|
232
|
+
if (onBegin) subs.push(alepha.on("react:transition:begin", { callback: onBegin }));
|
|
233
|
+
if (onEnd) subs.push(alepha.on("react:transition:end", { callback: onEnd }));
|
|
234
|
+
if (onError) subs.push(alepha.on("react:transition:error", { callback: onError }));
|
|
232
235
|
return () => {
|
|
233
236
|
for (const sub of subs) sub();
|
|
234
237
|
};
|
|
@@ -368,11 +371,10 @@ var PageDescriptorProvider = class {
|
|
|
368
371
|
return new URL(url.replace(/\/\/+/g, "/") || "/", options.base ?? `http://localhost`);
|
|
369
372
|
}
|
|
370
373
|
root(state, context) {
|
|
371
|
-
const root = createElement(RouterContext.Provider, { value: {
|
|
372
|
-
alepha: this.alepha,
|
|
374
|
+
const root = createElement(AlephaContext.Provider, { value: this.alepha }, createElement(RouterContext.Provider, { value: {
|
|
373
375
|
state,
|
|
374
376
|
context
|
|
375
|
-
} }, createElement(NestedView_default, {}, state.layers[0]?.element));
|
|
377
|
+
} }, createElement(NestedView_default, {}, state.layers[0]?.element)));
|
|
376
378
|
if (this.env.REACT_STRICT_MODE) return createElement(StrictMode, {}, root);
|
|
377
379
|
return root;
|
|
378
380
|
}
|
|
@@ -518,7 +520,10 @@ var PageDescriptorProvider = class {
|
|
|
518
520
|
return void 0;
|
|
519
521
|
}
|
|
520
522
|
renderError(error) {
|
|
521
|
-
return createElement(ErrorViewer_default, {
|
|
523
|
+
return createElement(ErrorViewer_default, {
|
|
524
|
+
error,
|
|
525
|
+
alepha: this.alepha
|
|
526
|
+
});
|
|
522
527
|
}
|
|
523
528
|
renderEmptyView() {
|
|
524
529
|
return createElement(NestedView_default, {});
|
|
@@ -816,7 +821,7 @@ var ReactBrowserProvider = class {
|
|
|
816
821
|
hydration
|
|
817
822
|
});
|
|
818
823
|
window.addEventListener("popstate", () => {
|
|
819
|
-
if (this.state.pathname ===
|
|
824
|
+
if (this.state.pathname === this.url) return;
|
|
820
825
|
this.render();
|
|
821
826
|
});
|
|
822
827
|
}
|
|
@@ -829,7 +834,8 @@ const envSchema = t.object({
|
|
|
829
834
|
REACT_SERVER_DIST: t.string({ default: "public" }),
|
|
830
835
|
REACT_SERVER_PREFIX: t.string({ default: "" }),
|
|
831
836
|
REACT_SSR_ENABLED: t.optional(t.boolean()),
|
|
832
|
-
REACT_ROOT_ID: t.string({ default: "root" })
|
|
837
|
+
REACT_ROOT_ID: t.string({ default: "root" }),
|
|
838
|
+
REACT_SERVER_TEMPLATE: t.optional(t.string({ size: "rich" }))
|
|
833
839
|
});
|
|
834
840
|
var ReactServerProvider = class {
|
|
835
841
|
log = $logger();
|
|
@@ -882,7 +888,7 @@ var ReactServerProvider = class {
|
|
|
882
888
|
}
|
|
883
889
|
});
|
|
884
890
|
get template() {
|
|
885
|
-
return this.alepha.
|
|
891
|
+
return this.alepha.env.REACT_SERVER_TEMPLATE ?? "<!DOCTYPE html><html lang='en'><head></head><body></body></html>";
|
|
886
892
|
}
|
|
887
893
|
async registerPages(templateLoader) {
|
|
888
894
|
for (const page of this.pageDescriptorProvider.getPages()) {
|
|
@@ -1136,13 +1142,14 @@ var RouterHookApi = class {
|
|
|
1136
1142
|
//#endregion
|
|
1137
1143
|
//#region src/hooks/useRouter.ts
|
|
1138
1144
|
const useRouter = () => {
|
|
1145
|
+
const alepha = useAlepha();
|
|
1139
1146
|
const ctx = useContext(RouterContext);
|
|
1140
1147
|
const layer = useContext(RouterLayerContext);
|
|
1141
1148
|
if (!ctx || !layer) throw new Error("useRouter must be used within a RouterProvider");
|
|
1142
1149
|
const pages = useMemo(() => {
|
|
1143
|
-
return
|
|
1150
|
+
return alepha.inject(PageDescriptorProvider).getPages();
|
|
1144
1151
|
}, []);
|
|
1145
|
-
return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer,
|
|
1152
|
+
return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer, alepha.isBrowser() ? alepha.inject(ReactBrowserProvider) : void 0), [layer]);
|
|
1146
1153
|
};
|
|
1147
1154
|
|
|
1148
1155
|
//#endregion
|
|
@@ -1203,10 +1210,9 @@ const useActive = (path) => {
|
|
|
1203
1210
|
|
|
1204
1211
|
//#endregion
|
|
1205
1212
|
//#region src/hooks/useInject.ts
|
|
1206
|
-
const useInject = (
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
return useMemo(() => ctx.alepha.inject(clazz), []);
|
|
1213
|
+
const useInject = (service) => {
|
|
1214
|
+
const alepha = useAlepha();
|
|
1215
|
+
return useMemo(() => alepha.inject(service), []);
|
|
1210
1216
|
};
|
|
1211
1217
|
|
|
1212
1218
|
//#endregion
|
|
@@ -1218,21 +1224,20 @@ const useClient = (_scope) => {
|
|
|
1218
1224
|
//#endregion
|
|
1219
1225
|
//#region src/hooks/useQueryParams.ts
|
|
1220
1226
|
const useQueryParams = (schema, options = {}) => {
|
|
1221
|
-
const
|
|
1222
|
-
if (!ctx) throw new Error("useQueryParams must be used within a RouterProvider");
|
|
1227
|
+
const alepha = useAlepha();
|
|
1223
1228
|
const key = options.key ?? "q";
|
|
1224
1229
|
const router = useRouter();
|
|
1225
1230
|
const querystring = router.query[key];
|
|
1226
|
-
const [queryParams, setQueryParams] = useState(decode(
|
|
1231
|
+
const [queryParams, setQueryParams] = useState(decode(alepha, schema, router.query[key]));
|
|
1227
1232
|
useEffect(() => {
|
|
1228
|
-
setQueryParams(decode(
|
|
1233
|
+
setQueryParams(decode(alepha, schema, querystring));
|
|
1229
1234
|
}, [querystring]);
|
|
1230
1235
|
return [queryParams, (queryParams$1) => {
|
|
1231
1236
|
setQueryParams(queryParams$1);
|
|
1232
1237
|
router.setQueryParams((data) => {
|
|
1233
1238
|
return {
|
|
1234
1239
|
...data,
|
|
1235
|
-
[key]: encode(
|
|
1240
|
+
[key]: encode(alepha, schema, queryParams$1)
|
|
1236
1241
|
};
|
|
1237
1242
|
});
|
|
1238
1243
|
}];
|
|
@@ -1251,14 +1256,73 @@ const decode = (alepha, schema, data) => {
|
|
|
1251
1256
|
//#endregion
|
|
1252
1257
|
//#region src/hooks/useRouterState.ts
|
|
1253
1258
|
const useRouterState = () => {
|
|
1254
|
-
const
|
|
1259
|
+
const router = useContext(RouterContext);
|
|
1255
1260
|
const layer = useContext(RouterLayerContext);
|
|
1256
|
-
if (!
|
|
1257
|
-
const [state, setState] = useState(
|
|
1261
|
+
if (!router || !layer) throw new Error("useRouterState must be used within a RouterContext.Provider");
|
|
1262
|
+
const [state, setState] = useState(router.state);
|
|
1258
1263
|
useRouterEvents({ onEnd: ({ state: state$1 }) => setState({ ...state$1 }) });
|
|
1259
1264
|
return state;
|
|
1260
1265
|
};
|
|
1261
1266
|
|
|
1267
|
+
//#endregion
|
|
1268
|
+
//#region src/hooks/useSchema.ts
|
|
1269
|
+
const useSchema = (action) => {
|
|
1270
|
+
const name = action.name;
|
|
1271
|
+
const alepha = useAlepha();
|
|
1272
|
+
const httpClient = useInject(HttpClient);
|
|
1273
|
+
const linkProvider = useInject(LinkProvider);
|
|
1274
|
+
const [schema, setSchema] = useState(ssrSchemaLoading(alepha, name));
|
|
1275
|
+
useEffect(() => {
|
|
1276
|
+
if (!schema.loading) return;
|
|
1277
|
+
const opts = { cache: true };
|
|
1278
|
+
httpClient.fetch(`${linkProvider.URL_LINKS}/${name}/schema`, {}, opts).then((it) => setSchema(it.data));
|
|
1279
|
+
}, [name]);
|
|
1280
|
+
return schema;
|
|
1281
|
+
};
|
|
1282
|
+
/**
|
|
1283
|
+
* Get an action schema during server-side rendering (SSR) or client-side rendering (CSR).
|
|
1284
|
+
*/
|
|
1285
|
+
const ssrSchemaLoading = (alepha, name) => {
|
|
1286
|
+
if (!alepha.isBrowser()) {
|
|
1287
|
+
const links = alepha.context.get("links")?.links ?? [];
|
|
1288
|
+
const can = links.find((it) => it.name === name);
|
|
1289
|
+
if (can) {
|
|
1290
|
+
const schema$1 = alepha.inject(LinkProvider).links?.find((it) => it.name === name)?.schema;
|
|
1291
|
+
if (schema$1) {
|
|
1292
|
+
can.schema = schema$1;
|
|
1293
|
+
return schema$1;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
return { loading: true };
|
|
1297
|
+
}
|
|
1298
|
+
const schema = alepha.inject(LinkProvider).links?.find((it) => it.name === name)?.schema;
|
|
1299
|
+
if (schema) return schema;
|
|
1300
|
+
return { loading: true };
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
//#endregion
|
|
1304
|
+
//#region src/hooks/useStore.ts
|
|
1305
|
+
/**
|
|
1306
|
+
* Hook to access and mutate the Alepha state.
|
|
1307
|
+
*/
|
|
1308
|
+
const useStore = (key) => {
|
|
1309
|
+
const alepha = useAlepha();
|
|
1310
|
+
const [state, setState] = useState(alepha.state(key));
|
|
1311
|
+
useEffect(() => {
|
|
1312
|
+
if (!alepha.isBrowser()) return;
|
|
1313
|
+
return alepha.on("state:mutate", (ev) => {
|
|
1314
|
+
if (ev.key === key) setState(ev.value);
|
|
1315
|
+
});
|
|
1316
|
+
}, []);
|
|
1317
|
+
if (!alepha.isBrowser()) {
|
|
1318
|
+
const value = alepha.context.get(key);
|
|
1319
|
+
if (value !== null) return [value, (_) => {}];
|
|
1320
|
+
}
|
|
1321
|
+
return [state, (value) => {
|
|
1322
|
+
alepha.state(key, value);
|
|
1323
|
+
}];
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1262
1326
|
//#endregion
|
|
1263
1327
|
//#region src/index.ts
|
|
1264
1328
|
/**
|
|
@@ -1283,5 +1347,5 @@ const AlephaReact = $module({
|
|
|
1283
1347
|
});
|
|
1284
1348
|
|
|
1285
1349
|
//#endregion
|
|
1286
|
-
export { $page, AlephaReact, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, PageDescriptorProvider, ReactBrowserProvider, ReactServerProvider, RedirectionError, RouterContext, RouterHookApi, RouterLayerContext, isPageRoute, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState };
|
|
1350
|
+
export { $page, AlephaContext, AlephaReact, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, PageDescriptorProvider, ReactBrowserProvider, ReactServerProvider, RedirectionError, RouterContext, RouterHookApi, RouterLayerContext, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
|
|
1287
1351
|
//# sourceMappingURL=index.js.map
|