@alepha/react 0.9.2 → 0.9.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/index.browser.js +136 -78
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +159 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +232 -158
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +230 -156
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -87
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/components/ErrorViewer.tsx +1 -1
- package/src/components/Link.tsx +4 -24
- package/src/components/NestedView.tsx +11 -2
- package/src/components/NotFound.tsx +4 -1
- package/src/descriptors/$page.ts +71 -9
- package/src/errors/{RedirectionError.ts → Redirection.ts} +1 -1
- package/src/hooks/RouterHookApi.ts +35 -11
- package/src/hooks/useActive.ts +22 -15
- package/src/hooks/useClient.ts +2 -0
- package/src/hooks/useRouter.ts +2 -1
- package/src/hooks/useRouterEvents.ts +5 -2
- package/src/hooks/useStore.ts +9 -1
- package/src/index.shared.ts +2 -2
- package/src/providers/BrowserRouterProvider.ts +9 -0
- package/src/providers/PageDescriptorProvider.ts +111 -31
- package/src/providers/ReactBrowserProvider.ts +17 -11
- package/src/providers/ReactServerProvider.ts +47 -10
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $env, $hook, $inject, $logger, $module, Alepha, Descriptor, KIND,
|
|
1
|
+
import { $env, $hook, $inject, $logger, $module, Alepha, Descriptor, KIND, createDescriptor, t } from "@alepha/core";
|
|
2
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";
|
|
@@ -18,6 +18,12 @@ const $page = (options) => {
|
|
|
18
18
|
return createDescriptor(PageDescriptor, options);
|
|
19
19
|
};
|
|
20
20
|
var PageDescriptor = class extends Descriptor {
|
|
21
|
+
onInit() {
|
|
22
|
+
if (this.options.static) this.options.cache ??= {
|
|
23
|
+
provider: "memory",
|
|
24
|
+
ttl: [1, "week"]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
21
27
|
get name() {
|
|
22
28
|
return this.options.name ?? this.config.propertyKey;
|
|
23
29
|
}
|
|
@@ -26,7 +32,7 @@ var PageDescriptor = class extends Descriptor {
|
|
|
26
32
|
* Only valid for server-side rendering, it will throw an error if called on the client-side.
|
|
27
33
|
*/
|
|
28
34
|
async render(options) {
|
|
29
|
-
throw new
|
|
35
|
+
throw new Error("render method is not implemented in this environment");
|
|
30
36
|
}
|
|
31
37
|
};
|
|
32
38
|
$page[KIND] = PageDescriptor;
|
|
@@ -80,7 +86,7 @@ const ErrorViewer = ({ error, alepha }) => {
|
|
|
80
86
|
heading: {
|
|
81
87
|
fontSize: "20px",
|
|
82
88
|
fontWeight: "bold",
|
|
83
|
-
marginBottom: "
|
|
89
|
+
marginBottom: "10px"
|
|
84
90
|
},
|
|
85
91
|
name: {
|
|
86
92
|
fontSize: "16px",
|
|
@@ -297,13 +303,16 @@ const NestedView = (props) => {
|
|
|
297
303
|
const layer = useContext(RouterLayerContext);
|
|
298
304
|
const index = layer?.index ?? 0;
|
|
299
305
|
const [view, setView] = useState(app?.state.layers[index]?.element);
|
|
300
|
-
useRouterEvents({ onEnd: ({ state }) => {
|
|
306
|
+
useRouterEvents({ onEnd: ({ state, context }) => {
|
|
307
|
+
if (app) app.context = context;
|
|
301
308
|
if (!state.layers[index]?.cache) setView(state.layers[index]?.element);
|
|
302
309
|
} }, [app]);
|
|
303
310
|
if (!app) throw new Error("NestedView must be used within a RouterContext.");
|
|
304
311
|
const element = view ?? props.children ?? null;
|
|
305
312
|
return /* @__PURE__ */ jsx(ErrorBoundary_default, {
|
|
306
|
-
fallback:
|
|
313
|
+
fallback: (error) => {
|
|
314
|
+
return app.context.onError?.(error, app.context);
|
|
315
|
+
},
|
|
307
316
|
children: element
|
|
308
317
|
});
|
|
309
318
|
};
|
|
@@ -311,7 +320,7 @@ var NestedView_default = NestedView;
|
|
|
311
320
|
|
|
312
321
|
//#endregion
|
|
313
322
|
//#region src/components/NotFound.tsx
|
|
314
|
-
function NotFoundPage() {
|
|
323
|
+
function NotFoundPage(props) {
|
|
315
324
|
return /* @__PURE__ */ jsx("div", {
|
|
316
325
|
style: {
|
|
317
326
|
height: "100vh",
|
|
@@ -321,7 +330,8 @@ function NotFoundPage() {
|
|
|
321
330
|
alignItems: "center",
|
|
322
331
|
textAlign: "center",
|
|
323
332
|
fontFamily: "sans-serif",
|
|
324
|
-
padding: "1rem"
|
|
333
|
+
padding: "1rem",
|
|
334
|
+
...props.style
|
|
325
335
|
},
|
|
326
336
|
children: /* @__PURE__ */ jsx("h1", {
|
|
327
337
|
style: {
|
|
@@ -334,8 +344,8 @@ function NotFoundPage() {
|
|
|
334
344
|
}
|
|
335
345
|
|
|
336
346
|
//#endregion
|
|
337
|
-
//#region src/errors/
|
|
338
|
-
var
|
|
347
|
+
//#region src/errors/Redirection.ts
|
|
348
|
+
var Redirection = class extends Error {
|
|
339
349
|
page;
|
|
340
350
|
constructor(page) {
|
|
341
351
|
super("Redirection");
|
|
@@ -358,7 +368,7 @@ var PageDescriptorProvider = class {
|
|
|
358
368
|
for (const page of this.pages) if (page.name === name) return page;
|
|
359
369
|
throw new Error(`Page ${name} not found`);
|
|
360
370
|
}
|
|
361
|
-
|
|
371
|
+
pathname(name, options = {}) {
|
|
362
372
|
const page = this.page(name);
|
|
363
373
|
if (!page) throw new Error(`Page ${name} not found`);
|
|
364
374
|
let url = page.path ?? "";
|
|
@@ -368,7 +378,14 @@ var PageDescriptorProvider = class {
|
|
|
368
378
|
parent = parent.parent;
|
|
369
379
|
}
|
|
370
380
|
url = this.compile(url, options.params ?? {});
|
|
371
|
-
|
|
381
|
+
if (options.query) {
|
|
382
|
+
const query = new URLSearchParams(options.query);
|
|
383
|
+
if (query.toString()) url += `?${query.toString()}`;
|
|
384
|
+
}
|
|
385
|
+
return url.replace(/\/\/+/g, "/") || "/";
|
|
386
|
+
}
|
|
387
|
+
url(name, options = {}) {
|
|
388
|
+
return new URL(this.pathname(name, options), options.base ?? `http://localhost`);
|
|
372
389
|
}
|
|
373
390
|
root(state, context) {
|
|
374
391
|
const root = createElement(AlephaContext.Provider, { value: this.alepha }, createElement(RouterContext.Provider, { value: {
|
|
@@ -443,12 +460,10 @@ var PageDescriptorProvider = class {
|
|
|
443
460
|
...props
|
|
444
461
|
};
|
|
445
462
|
} catch (e) {
|
|
446
|
-
if (e instanceof
|
|
447
|
-
layers: [],
|
|
448
|
-
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
463
|
+
if (e instanceof Redirection) return this.createRedirectionLayer(e.page, {
|
|
449
464
|
pathname,
|
|
450
465
|
search
|
|
451
|
-
};
|
|
466
|
+
});
|
|
452
467
|
this.log.error(e);
|
|
453
468
|
it.error = e;
|
|
454
469
|
break;
|
|
@@ -464,9 +479,21 @@ var PageDescriptorProvider = class {
|
|
|
464
479
|
acc += it.route.path ? this.compile(it.route.path, params) : "";
|
|
465
480
|
const path = acc.replace(/\/+/, "/");
|
|
466
481
|
const localErrorHandler = this.getErrorHandler(it.route);
|
|
467
|
-
if (localErrorHandler)
|
|
468
|
-
|
|
469
|
-
|
|
482
|
+
if (localErrorHandler) {
|
|
483
|
+
const onErrorParent = request.onError;
|
|
484
|
+
request.onError = (error, context$1) => {
|
|
485
|
+
const result = localErrorHandler(error, context$1);
|
|
486
|
+
if (result === void 0) return onErrorParent(error, context$1);
|
|
487
|
+
return result;
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
if (it.error) try {
|
|
491
|
+
let element$1 = await request.onError(it.error, request);
|
|
492
|
+
if (element$1 === void 0) throw it.error;
|
|
493
|
+
if (element$1 instanceof Redirection) return this.createRedirectionLayer(element$1.page, {
|
|
494
|
+
pathname,
|
|
495
|
+
search
|
|
496
|
+
});
|
|
470
497
|
if (element$1 === null) element$1 = this.renderError(it.error);
|
|
471
498
|
layers.push({
|
|
472
499
|
props,
|
|
@@ -480,6 +507,12 @@ var PageDescriptorProvider = class {
|
|
|
480
507
|
route: it.route
|
|
481
508
|
});
|
|
482
509
|
break;
|
|
510
|
+
} catch (e) {
|
|
511
|
+
if (e instanceof Redirection) return this.createRedirectionLayer(e.page, {
|
|
512
|
+
pathname,
|
|
513
|
+
search
|
|
514
|
+
});
|
|
515
|
+
throw e;
|
|
483
516
|
}
|
|
484
517
|
const element = await this.createElement(it.route, {
|
|
485
518
|
...props,
|
|
@@ -503,6 +536,14 @@ var PageDescriptorProvider = class {
|
|
|
503
536
|
search
|
|
504
537
|
};
|
|
505
538
|
}
|
|
539
|
+
createRedirectionLayer(href, context) {
|
|
540
|
+
return {
|
|
541
|
+
layers: [],
|
|
542
|
+
redirect: typeof href === "string" ? href : this.href(href),
|
|
543
|
+
pathname: context.pathname,
|
|
544
|
+
search: context.search
|
|
545
|
+
};
|
|
546
|
+
}
|
|
506
547
|
getErrorHandler(route) {
|
|
507
548
|
if (route.errorHandler) return route.errorHandler;
|
|
508
549
|
let parent = route.parent;
|
|
@@ -558,6 +599,7 @@ var PageDescriptorProvider = class {
|
|
|
558
599
|
let hasNotFoundHandler = false;
|
|
559
600
|
const pages = this.alepha.descriptors($page);
|
|
560
601
|
const hasParent = (it) => {
|
|
602
|
+
if (it.options.parent) return true;
|
|
561
603
|
for (const page of pages) {
|
|
562
604
|
const children = page.options.children ? Array.isArray(page.options.children) ? page.options.children : page.options.children() : [];
|
|
563
605
|
if (children.includes(it)) return true;
|
|
@@ -573,7 +615,7 @@ var PageDescriptorProvider = class {
|
|
|
573
615
|
name: "notFound",
|
|
574
616
|
cache: true,
|
|
575
617
|
component: NotFoundPage,
|
|
576
|
-
|
|
618
|
+
onServerResponse: ({ reply }) => {
|
|
577
619
|
reply.status = 404;
|
|
578
620
|
}
|
|
579
621
|
});
|
|
@@ -581,6 +623,12 @@ var PageDescriptorProvider = class {
|
|
|
581
623
|
});
|
|
582
624
|
map(pages, target) {
|
|
583
625
|
const children = target.options.children ? Array.isArray(target.options.children) ? target.options.children : target.options.children() : [];
|
|
626
|
+
const getChildrenFromParent = (it) => {
|
|
627
|
+
const children$1 = [];
|
|
628
|
+
for (const page of pages) if (page.options.parent === it) children$1.push(page);
|
|
629
|
+
return children$1;
|
|
630
|
+
};
|
|
631
|
+
children.push(...getChildrenFromParent(target));
|
|
584
632
|
return {
|
|
585
633
|
...target.options,
|
|
586
634
|
name: target.name,
|
|
@@ -702,6 +750,10 @@ var BrowserRouterProvider = class extends RouterProvider {
|
|
|
702
750
|
options.state.pathname = state.pathname;
|
|
703
751
|
options.state.search = state.search;
|
|
704
752
|
}
|
|
753
|
+
if (options.previous) for (let i = 0; i < options.previous.length; i++) {
|
|
754
|
+
const layer = options.previous[i];
|
|
755
|
+
if (state.layers[i]?.name !== layer.name) this.pageDescriptorProvider.page(layer.name)?.onLeave?.();
|
|
756
|
+
}
|
|
705
757
|
await this.alepha.emit("react:transition:end", {
|
|
706
758
|
state: options.state,
|
|
707
759
|
context
|
|
@@ -776,15 +828,11 @@ var ReactBrowserProvider = class {
|
|
|
776
828
|
}
|
|
777
829
|
async go(url, options = {}) {
|
|
778
830
|
const result = await this.render({ url });
|
|
779
|
-
if (result.context.url.pathname !== url) {
|
|
780
|
-
this.pushState(result.context.url.pathname);
|
|
831
|
+
if (result.context.url.pathname + result.context.url.search !== url) {
|
|
832
|
+
this.pushState(result.context.url.pathname + result.context.url.search);
|
|
781
833
|
return;
|
|
782
834
|
}
|
|
783
|
-
|
|
784
|
-
this.pushState(url);
|
|
785
|
-
return;
|
|
786
|
-
}
|
|
787
|
-
this.pushState(url);
|
|
835
|
+
this.pushState(url, options.replace);
|
|
788
836
|
}
|
|
789
837
|
async render(options = {}) {
|
|
790
838
|
const previous = options.previous ?? this.state.layers;
|
|
@@ -813,7 +861,13 @@ var ReactBrowserProvider = class {
|
|
|
813
861
|
handler: async () => {
|
|
814
862
|
const hydration = this.getHydrationState();
|
|
815
863
|
const previous = hydration?.layers ?? [];
|
|
816
|
-
if (hydration
|
|
864
|
+
if (hydration) {
|
|
865
|
+
for (const [key, value] of Object.entries(hydration)) if (key !== "layers" && key !== "links") this.alepha.state(key, value);
|
|
866
|
+
}
|
|
867
|
+
if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink({
|
|
868
|
+
...link,
|
|
869
|
+
prefix: hydration.links.prefix
|
|
870
|
+
});
|
|
817
871
|
const { context } = await this.render({ previous });
|
|
818
872
|
await this.alepha.emit("react:browser:render", {
|
|
819
873
|
state: this.state,
|
|
@@ -941,6 +995,7 @@ var ReactServerProvider = class {
|
|
|
941
995
|
html: renderToString(this.pageDescriptorProvider.root(state, context))
|
|
942
996
|
};
|
|
943
997
|
const html = this.renderToHtml(this.template ?? "", state, context, options.hydration);
|
|
998
|
+
if (html instanceof Redirection) throw new Error("Redirection is not supported in this context");
|
|
944
999
|
const result = {
|
|
945
1000
|
context,
|
|
946
1001
|
state,
|
|
@@ -955,6 +1010,7 @@ var ReactServerProvider = class {
|
|
|
955
1010
|
const { url, reply, query, params } = serverRequest;
|
|
956
1011
|
const template = await templateLoader();
|
|
957
1012
|
if (!template) throw new Error("Template not found");
|
|
1013
|
+
this.log.trace("Rendering page", { name: page.name });
|
|
958
1014
|
const context = {
|
|
959
1015
|
url,
|
|
960
1016
|
params,
|
|
@@ -980,6 +1036,10 @@ var ReactServerProvider = class {
|
|
|
980
1036
|
}
|
|
981
1037
|
target = target.parent;
|
|
982
1038
|
}
|
|
1039
|
+
await this.alepha.emit("react:transition:begin", {
|
|
1040
|
+
request: serverRequest,
|
|
1041
|
+
context
|
|
1042
|
+
});
|
|
983
1043
|
await this.alepha.emit("react:server:render:begin", {
|
|
984
1044
|
request: serverRequest,
|
|
985
1045
|
context
|
|
@@ -994,14 +1054,20 @@ var ReactServerProvider = class {
|
|
|
994
1054
|
reply.headers.expires = "0";
|
|
995
1055
|
if (page.cache && serverRequest.user) delete context.links;
|
|
996
1056
|
const html = this.renderToHtml(template, state, context);
|
|
997
|
-
|
|
1057
|
+
if (html instanceof Redirection) {
|
|
1058
|
+
reply.redirect(typeof html.page === "string" ? html.page : this.pageDescriptorProvider.href(html.page));
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
const event = {
|
|
998
1062
|
request: serverRequest,
|
|
999
1063
|
context,
|
|
1000
1064
|
state,
|
|
1001
1065
|
html
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1066
|
+
};
|
|
1067
|
+
await this.alepha.emit("react:server:render:end", event);
|
|
1068
|
+
page.onServerResponse?.(serverRequest);
|
|
1069
|
+
this.log.trace("Page rendered", { name: page.name });
|
|
1070
|
+
return event.html;
|
|
1005
1071
|
};
|
|
1006
1072
|
}
|
|
1007
1073
|
renderToHtml(template, state, context, hydration = true) {
|
|
@@ -1012,20 +1078,23 @@ var ReactServerProvider = class {
|
|
|
1012
1078
|
app = renderToString(element);
|
|
1013
1079
|
} catch (error) {
|
|
1014
1080
|
this.log.error("Error during SSR", error);
|
|
1015
|
-
|
|
1081
|
+
const element$1 = context.onError(error, context);
|
|
1082
|
+
if (element$1 instanceof Redirection) return element$1;
|
|
1083
|
+
app = renderToString(element$1);
|
|
1016
1084
|
}
|
|
1017
1085
|
this.serverTimingProvider.endTiming("renderToString");
|
|
1018
1086
|
const response = { html: template };
|
|
1019
1087
|
if (hydration) {
|
|
1088
|
+
const { request, context: context$1,...rest } = this.alepha.context.als?.getStore() ?? {};
|
|
1020
1089
|
const hydrationData = {
|
|
1021
|
-
|
|
1090
|
+
...rest,
|
|
1022
1091
|
layers: state.layers.map((it) => ({
|
|
1023
1092
|
...it,
|
|
1024
1093
|
error: it.error ? {
|
|
1025
1094
|
...it.error,
|
|
1026
1095
|
name: it.error.name,
|
|
1027
1096
|
message: it.error.message,
|
|
1028
|
-
stack: it.error.stack
|
|
1097
|
+
stack: !this.alepha.isProduction() ? it.error.stack : void 0
|
|
1029
1098
|
} : void 0,
|
|
1030
1099
|
index: void 0,
|
|
1031
1100
|
path: void 0,
|
|
@@ -1045,24 +1114,34 @@ var ReactServerProvider = class {
|
|
|
1045
1114
|
else {
|
|
1046
1115
|
const bodyOpenTag = /<body([^>]*)>/i;
|
|
1047
1116
|
if (bodyOpenTag.test(response.html)) response.html = response.html.replace(bodyOpenTag, (match) => {
|
|
1048
|
-
return `${match}
|
|
1117
|
+
return `${match}<div id="${this.env.REACT_ROOT_ID}">${app}</div>`;
|
|
1049
1118
|
});
|
|
1050
1119
|
}
|
|
1051
1120
|
const bodyCloseTagRegex = /<\/body>/i;
|
|
1052
|
-
if (bodyCloseTagRegex.test(response.html)) response.html = response.html.replace(bodyCloseTagRegex, `${script}
|
|
1121
|
+
if (bodyCloseTagRegex.test(response.html)) response.html = response.html.replace(bodyCloseTagRegex, `${script}</body>`);
|
|
1053
1122
|
}
|
|
1054
1123
|
};
|
|
1055
1124
|
|
|
1056
1125
|
//#endregion
|
|
1057
1126
|
//#region src/hooks/RouterHookApi.ts
|
|
1058
1127
|
var RouterHookApi = class {
|
|
1059
|
-
constructor(pages, context, state, layer, browser) {
|
|
1128
|
+
constructor(pages, context, state, layer, pageApi, browser) {
|
|
1060
1129
|
this.pages = pages;
|
|
1061
1130
|
this.context = context;
|
|
1062
1131
|
this.state = state;
|
|
1063
1132
|
this.layer = layer;
|
|
1133
|
+
this.pageApi = pageApi;
|
|
1064
1134
|
this.browser = browser;
|
|
1065
1135
|
}
|
|
1136
|
+
path(name, config = {}) {
|
|
1137
|
+
return this.pageApi.pathname(name, {
|
|
1138
|
+
params: {
|
|
1139
|
+
...this.context.params,
|
|
1140
|
+
...config.params
|
|
1141
|
+
},
|
|
1142
|
+
query: config.query
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1066
1145
|
getURL() {
|
|
1067
1146
|
if (!this.browser) return this.context.url;
|
|
1068
1147
|
return new URL(this.location.href);
|
|
@@ -1104,23 +1183,23 @@ var RouterHookApi = class {
|
|
|
1104
1183
|
}
|
|
1105
1184
|
async go(path, options) {
|
|
1106
1185
|
for (const page of this.pages) if (page.name === path) {
|
|
1107
|
-
|
|
1108
|
-
|
|
1186
|
+
await this.browser?.go(this.path(path, options), options);
|
|
1187
|
+
return;
|
|
1109
1188
|
}
|
|
1110
|
-
await this.browser?.go(
|
|
1189
|
+
await this.browser?.go(path, options);
|
|
1111
1190
|
}
|
|
1112
1191
|
anchor(path, options = {}) {
|
|
1192
|
+
let href = path;
|
|
1113
1193
|
for (const page of this.pages) if (page.name === path) {
|
|
1114
|
-
|
|
1194
|
+
href = this.path(path, options);
|
|
1115
1195
|
break;
|
|
1116
1196
|
}
|
|
1117
|
-
const href = this.createHref(path, this.layer, options);
|
|
1118
1197
|
return {
|
|
1119
1198
|
href,
|
|
1120
1199
|
onClick: (ev) => {
|
|
1121
1200
|
ev.stopPropagation();
|
|
1122
1201
|
ev.preventDefault();
|
|
1123
|
-
this.go(
|
|
1202
|
+
this.go(href, options).catch(console.error);
|
|
1124
1203
|
}
|
|
1125
1204
|
};
|
|
1126
1205
|
}
|
|
@@ -1149,27 +1228,18 @@ const useRouter = () => {
|
|
|
1149
1228
|
const pages = useMemo(() => {
|
|
1150
1229
|
return alepha.inject(PageDescriptorProvider).getPages();
|
|
1151
1230
|
}, []);
|
|
1152
|
-
return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer, alepha.isBrowser() ? alepha.inject(ReactBrowserProvider) : void 0), [layer]);
|
|
1231
|
+
return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer, alepha.inject(PageDescriptorProvider), alepha.isBrowser() ? alepha.inject(ReactBrowserProvider) : void 0), [layer]);
|
|
1153
1232
|
};
|
|
1154
1233
|
|
|
1155
1234
|
//#endregion
|
|
1156
1235
|
//#region src/components/Link.tsx
|
|
1157
1236
|
const Link = (props) => {
|
|
1158
|
-
React.useContext(RouterContext);
|
|
1159
1237
|
const router = useRouter();
|
|
1160
|
-
const
|
|
1161
|
-
if (!to) return null;
|
|
1162
|
-
const can = typeof props.to === "string" ? void 0 : props.to.options.can;
|
|
1163
|
-
if (can && !can()) return null;
|
|
1164
|
-
const name = typeof props.to === "string" ? void 0 : props.to.options.name;
|
|
1165
|
-
const anchorProps = {
|
|
1166
|
-
...props,
|
|
1167
|
-
to: void 0
|
|
1168
|
-
};
|
|
1238
|
+
const { to,...anchorProps } = props;
|
|
1169
1239
|
return /* @__PURE__ */ jsx("a", {
|
|
1170
1240
|
...router.anchor(to),
|
|
1171
1241
|
...anchorProps,
|
|
1172
|
-
children: props.children
|
|
1242
|
+
children: props.children
|
|
1173
1243
|
});
|
|
1174
1244
|
};
|
|
1175
1245
|
var Link_default = Link;
|
|
@@ -1181,22 +1251,21 @@ const useActive = (path) => {
|
|
|
1181
1251
|
const ctx = useContext(RouterContext);
|
|
1182
1252
|
const layer = useContext(RouterLayerContext);
|
|
1183
1253
|
if (!ctx || !layer) throw new Error("useRouter must be used within a RouterProvider");
|
|
1184
|
-
let name;
|
|
1185
|
-
if (typeof path === "object" && path.options.name) name = path.options.name;
|
|
1186
1254
|
const [current, setCurrent] = useState(ctx.state.pathname);
|
|
1187
|
-
const href = useMemo(() => router.createHref(path, layer), [path, layer]);
|
|
1255
|
+
const href = useMemo(() => router.createHref(path ?? "", layer), [path, layer]);
|
|
1188
1256
|
const [isPending, setPending] = useState(false);
|
|
1189
|
-
const isActive = current === href;
|
|
1190
|
-
useRouterEvents({ onEnd: ({ state }) =>
|
|
1257
|
+
const isActive = current === href || current === `${href}/` || `${current}/` === href;
|
|
1258
|
+
useRouterEvents({ onEnd: ({ state }) => {
|
|
1259
|
+
path && setCurrent(state.pathname);
|
|
1260
|
+
} }, [path]);
|
|
1191
1261
|
return {
|
|
1192
|
-
name,
|
|
1193
1262
|
isPending,
|
|
1194
1263
|
isActive,
|
|
1195
1264
|
anchorProps: {
|
|
1196
1265
|
href,
|
|
1197
1266
|
onClick: (ev) => {
|
|
1198
|
-
ev
|
|
1199
|
-
ev
|
|
1267
|
+
ev?.stopPropagation();
|
|
1268
|
+
ev?.preventDefault();
|
|
1200
1269
|
if (isActive) return;
|
|
1201
1270
|
if (isPending) return;
|
|
1202
1271
|
setPending(true);
|
|
@@ -1215,9 +1284,36 @@ const useInject = (service) => {
|
|
|
1215
1284
|
return useMemo(() => alepha.inject(service), []);
|
|
1216
1285
|
};
|
|
1217
1286
|
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region src/hooks/useStore.ts
|
|
1289
|
+
/**
|
|
1290
|
+
* Hook to access and mutate the Alepha state.
|
|
1291
|
+
*/
|
|
1292
|
+
const useStore = (key, defaultValue) => {
|
|
1293
|
+
const alepha = useAlepha();
|
|
1294
|
+
useMemo(() => {
|
|
1295
|
+
if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
|
|
1296
|
+
}, [defaultValue]);
|
|
1297
|
+
const [state, setState] = useState(alepha.state(key));
|
|
1298
|
+
useEffect(() => {
|
|
1299
|
+
if (!alepha.isBrowser()) return;
|
|
1300
|
+
return alepha.on("state:mutate", (ev) => {
|
|
1301
|
+
if (ev.key === key) setState(ev.value);
|
|
1302
|
+
});
|
|
1303
|
+
}, []);
|
|
1304
|
+
if (!alepha.isBrowser()) {
|
|
1305
|
+
const value = alepha.context.get(key);
|
|
1306
|
+
if (value !== null) return [value, (_) => {}];
|
|
1307
|
+
}
|
|
1308
|
+
return [state, (value) => {
|
|
1309
|
+
alepha.state(key, value);
|
|
1310
|
+
}];
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1218
1313
|
//#endregion
|
|
1219
1314
|
//#region src/hooks/useClient.ts
|
|
1220
1315
|
const useClient = (_scope) => {
|
|
1316
|
+
useStore("user");
|
|
1221
1317
|
return useInject(LinkProvider).client();
|
|
1222
1318
|
};
|
|
1223
1319
|
|
|
@@ -1300,29 +1396,6 @@ const ssrSchemaLoading = (alepha, name) => {
|
|
|
1300
1396
|
return { loading: true };
|
|
1301
1397
|
};
|
|
1302
1398
|
|
|
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
|
-
|
|
1326
1399
|
//#endregion
|
|
1327
1400
|
//#region src/index.ts
|
|
1328
1401
|
/**
|
|
@@ -1347,5 +1420,5 @@ const AlephaReact = $module({
|
|
|
1347
1420
|
});
|
|
1348
1421
|
|
|
1349
1422
|
//#endregion
|
|
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,
|
|
1423
|
+
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, Redirection, RouterContext, RouterHookApi, RouterLayerContext, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
|
|
1351
1424
|
//# sourceMappingURL=index.js.map
|