@alepha/react 0.9.4 → 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 +18 -6
- package/dist/index.browser.js +196 -77
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +203 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +240 -195
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +219 -174
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +204 -81
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
- package/src/components/Link.tsx +2 -5
- package/src/components/NestedView.tsx +159 -16
- package/src/descriptors/$page.ts +84 -1
- package/src/hooks/useActive.ts +0 -1
- package/src/hooks/useRouterEvents.ts +27 -19
- package/src/index.browser.ts +3 -0
- package/src/index.ts +6 -1
- package/src/providers/ReactBrowserProvider.ts +19 -14
- package/src/providers/ReactBrowserRendererProvider.ts +22 -0
- package/src/providers/ReactBrowserRouterProvider.ts +8 -3
- package/src/providers/ReactPageProvider.ts +46 -1
- package/src/providers/ReactServerProvider.ts +22 -3
- package/src/services/ReactRouter.ts +5 -8
package/dist/index.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { $env, $hook, $inject, $module, Alepha, AlephaError, Descriptor, KIND, createDescriptor, t } from "@alepha/core";
|
|
2
|
-
import { AlephaServer, HttpClient, ServerRouterProvider, ServerTimingProvider } from "@alepha/server";
|
|
1
|
+
import { $env, $hook, $inject, $module, Alepha, AlephaError, Descriptor, KIND, TypeGuard, createDescriptor, t } from "@alepha/core";
|
|
2
|
+
import { AlephaServer, HttpClient, ServerProvider, ServerRouterProvider, ServerTimingProvider } from "@alepha/server";
|
|
3
3
|
import { AlephaServerCache } from "@alepha/server-cache";
|
|
4
4
|
import { AlephaServerLinks, LinkProvider, ServerLinksProvider } from "@alepha/server-links";
|
|
5
5
|
import { $logger } from "@alepha/logger";
|
|
6
|
-
import React, { StrictMode, createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import React, { StrictMode, createContext, createElement, memo, use, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { existsSync } from "node:fs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { ServerStaticProvider } from "@alepha/server-static";
|
|
11
11
|
import { renderToString } from "react-dom/server";
|
|
12
12
|
import { DateTimeProvider } from "@alepha/datetime";
|
|
13
|
-
import { createRoot, hydrateRoot } from "react-dom/client";
|
|
14
13
|
import { RouterProvider } from "@alepha/router";
|
|
15
14
|
|
|
16
15
|
//#region src/descriptors/$page.ts
|
|
@@ -35,7 +34,10 @@ var PageDescriptor = class extends Descriptor {
|
|
|
35
34
|
* Only valid for server-side rendering, it will throw an error if called on the client-side.
|
|
36
35
|
*/
|
|
37
36
|
async render(options) {
|
|
38
|
-
throw new
|
|
37
|
+
throw new AlephaError("render() method is not implemented in this environment");
|
|
38
|
+
}
|
|
39
|
+
async fetch(options) {
|
|
40
|
+
throw new AlephaError("fetch() method is not implemented in this environment");
|
|
39
41
|
}
|
|
40
42
|
match(url) {
|
|
41
43
|
return false;
|
|
@@ -64,7 +66,6 @@ const ClientOnly = (props) => {
|
|
|
64
66
|
if (props.disabled) return props.children;
|
|
65
67
|
return mounted ? props.children : props.fallback;
|
|
66
68
|
};
|
|
67
|
-
var ClientOnly_default = ClientOnly;
|
|
68
69
|
|
|
69
70
|
//#endregion
|
|
70
71
|
//#region src/components/ErrorViewer.tsx
|
|
@@ -172,7 +173,6 @@ const ErrorViewer = ({ error, alepha }) => {
|
|
|
172
173
|
})] })]
|
|
173
174
|
});
|
|
174
175
|
};
|
|
175
|
-
var ErrorViewer_default = ErrorViewer;
|
|
176
176
|
const ErrorViewerProduction = () => {
|
|
177
177
|
const styles = {
|
|
178
178
|
container: {
|
|
@@ -266,19 +266,55 @@ const useRouterEvents = (opts = {}, deps = []) => {
|
|
|
266
266
|
const alepha = useAlepha();
|
|
267
267
|
useEffect(() => {
|
|
268
268
|
if (!alepha.isBrowser()) return;
|
|
269
|
+
const cb = (callback) => {
|
|
270
|
+
if (typeof callback === "function") return { callback };
|
|
271
|
+
return callback;
|
|
272
|
+
};
|
|
269
273
|
const subs = [];
|
|
270
274
|
const onBegin = opts.onBegin;
|
|
271
275
|
const onEnd = opts.onEnd;
|
|
272
276
|
const onError = opts.onError;
|
|
273
|
-
|
|
274
|
-
if (
|
|
275
|
-
if (
|
|
277
|
+
const onSuccess = opts.onSuccess;
|
|
278
|
+
if (onBegin) subs.push(alepha.on("react:transition:begin", cb(onBegin)));
|
|
279
|
+
if (onEnd) subs.push(alepha.on("react:transition:end", cb(onEnd)));
|
|
280
|
+
if (onError) subs.push(alepha.on("react:transition:error", cb(onError)));
|
|
281
|
+
if (onSuccess) subs.push(alepha.on("react:transition:success", cb(onSuccess)));
|
|
276
282
|
return () => {
|
|
277
283
|
for (const sub of subs) sub();
|
|
278
284
|
};
|
|
279
285
|
}, deps);
|
|
280
286
|
};
|
|
281
287
|
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/hooks/useStore.ts
|
|
290
|
+
/**
|
|
291
|
+
* Hook to access and mutate the Alepha state.
|
|
292
|
+
*/
|
|
293
|
+
const useStore = (key, defaultValue) => {
|
|
294
|
+
const alepha = useAlepha();
|
|
295
|
+
useMemo(() => {
|
|
296
|
+
if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
|
|
297
|
+
}, [defaultValue]);
|
|
298
|
+
const [state, setState] = useState(alepha.state(key));
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (!alepha.isBrowser()) return;
|
|
301
|
+
return alepha.on("state:mutate", (ev) => {
|
|
302
|
+
if (ev.key === key) setState(ev.value);
|
|
303
|
+
});
|
|
304
|
+
}, []);
|
|
305
|
+
return [state, (value) => {
|
|
306
|
+
alepha.state(key, value);
|
|
307
|
+
}];
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/hooks/useRouterState.ts
|
|
312
|
+
const useRouterState = () => {
|
|
313
|
+
const [state] = useStore("react.router.state");
|
|
314
|
+
if (!state) throw new AlephaError("Missing react router state");
|
|
315
|
+
return state;
|
|
316
|
+
};
|
|
317
|
+
|
|
282
318
|
//#endregion
|
|
283
319
|
//#region src/components/ErrorBoundary.tsx
|
|
284
320
|
/**
|
|
@@ -308,7 +344,6 @@ var ErrorBoundary = class extends React.Component {
|
|
|
308
344
|
return this.props.children;
|
|
309
345
|
}
|
|
310
346
|
};
|
|
311
|
-
var ErrorBoundary_default = ErrorBoundary;
|
|
312
347
|
|
|
313
348
|
//#endregion
|
|
314
349
|
//#region src/components/NestedView.tsx
|
|
@@ -319,7 +354,7 @@ var ErrorBoundary_default = ErrorBoundary;
|
|
|
319
354
|
*
|
|
320
355
|
* @example
|
|
321
356
|
* ```tsx
|
|
322
|
-
* import { NestedView } from "
|
|
357
|
+
* import { NestedView } from "alepha/react";
|
|
323
358
|
*
|
|
324
359
|
* class App {
|
|
325
360
|
* parent = $page({
|
|
@@ -334,17 +369,69 @@ var ErrorBoundary_default = ErrorBoundary;
|
|
|
334
369
|
* ```
|
|
335
370
|
*/
|
|
336
371
|
const NestedView = (props) => {
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
const alepha = useAlepha();
|
|
340
|
-
const state = alepha.state("react.router.state");
|
|
341
|
-
if (!state) throw new Error("<NestedView/> must be used inside a RouterLayerContext.");
|
|
372
|
+
const index = use(RouterLayerContext)?.index ?? 0;
|
|
373
|
+
const state = useRouterState();
|
|
342
374
|
const [view, setView] = useState(state.layers[index]?.element);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
375
|
+
const [animation, setAnimation] = useState("");
|
|
376
|
+
const animationExitDuration = useRef(0);
|
|
377
|
+
const animationExitNow = useRef(0);
|
|
378
|
+
useRouterEvents({
|
|
379
|
+
onBegin: async ({ previous, state: state$1 }) => {
|
|
380
|
+
const layer = previous.layers[index];
|
|
381
|
+
if (`${state$1.url.pathname}/`.startsWith(`${layer?.path}/`)) return;
|
|
382
|
+
const animationExit = parseAnimation(layer.route?.animation, state$1, "exit");
|
|
383
|
+
if (animationExit) {
|
|
384
|
+
const duration = animationExit.duration || 200;
|
|
385
|
+
animationExitNow.current = Date.now();
|
|
386
|
+
animationExitDuration.current = duration;
|
|
387
|
+
setAnimation(animationExit.animation);
|
|
388
|
+
} else {
|
|
389
|
+
animationExitNow.current = 0;
|
|
390
|
+
animationExitDuration.current = 0;
|
|
391
|
+
setAnimation("");
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
onEnd: async ({ state: state$1 }) => {
|
|
395
|
+
const layer = state$1.layers[index];
|
|
396
|
+
if (animationExitNow.current) {
|
|
397
|
+
const duration = animationExitDuration.current;
|
|
398
|
+
const diff = Date.now() - animationExitNow.current;
|
|
399
|
+
if (diff < duration) await new Promise((resolve) => setTimeout(resolve, duration - diff));
|
|
400
|
+
}
|
|
401
|
+
if (!layer?.cache) {
|
|
402
|
+
setView(layer?.element);
|
|
403
|
+
const animationEnter = parseAnimation(layer?.route?.animation, state$1, "enter");
|
|
404
|
+
if (animationEnter) setAnimation(animationEnter.animation);
|
|
405
|
+
else setAnimation("");
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}, []);
|
|
409
|
+
let element = view ?? props.children ?? null;
|
|
410
|
+
if (animation) element = /* @__PURE__ */ jsx("div", {
|
|
411
|
+
style: {
|
|
412
|
+
display: "flex",
|
|
413
|
+
flex: 1,
|
|
414
|
+
height: "100%",
|
|
415
|
+
width: "100%",
|
|
416
|
+
position: "relative",
|
|
417
|
+
overflow: "hidden"
|
|
418
|
+
},
|
|
419
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
420
|
+
style: {
|
|
421
|
+
height: "100%",
|
|
422
|
+
width: "100%",
|
|
423
|
+
display: "flex",
|
|
424
|
+
animation
|
|
425
|
+
},
|
|
426
|
+
children: element
|
|
427
|
+
})
|
|
428
|
+
});
|
|
429
|
+
if (props.errorBoundary === false) return /* @__PURE__ */ jsx(Fragment, { children: element });
|
|
430
|
+
if (props.errorBoundary) return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
431
|
+
fallback: props.errorBoundary,
|
|
432
|
+
children: element
|
|
433
|
+
});
|
|
434
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
348
435
|
fallback: (error) => {
|
|
349
436
|
const result = state.onError(error, state);
|
|
350
437
|
if (result instanceof Redirection) return "Redirection inside ErrorBoundary is not allowed.";
|
|
@@ -353,7 +440,37 @@ const NestedView = (props) => {
|
|
|
353
440
|
children: element
|
|
354
441
|
});
|
|
355
442
|
};
|
|
356
|
-
var NestedView_default = NestedView;
|
|
443
|
+
var NestedView_default = memo(NestedView);
|
|
444
|
+
function parseAnimation(animationLike, state, type = "enter") {
|
|
445
|
+
if (!animationLike) return void 0;
|
|
446
|
+
const DEFAULT_DURATION = 300;
|
|
447
|
+
const animation = typeof animationLike === "function" ? animationLike(state) : animationLike;
|
|
448
|
+
if (typeof animation === "string") {
|
|
449
|
+
if (type === "exit") return;
|
|
450
|
+
return {
|
|
451
|
+
duration: DEFAULT_DURATION,
|
|
452
|
+
animation: `${DEFAULT_DURATION}ms ${animation}`
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
if (typeof animation === "object") {
|
|
456
|
+
const anim = animation[type];
|
|
457
|
+
const duration = typeof anim === "object" ? anim.duration ?? DEFAULT_DURATION : DEFAULT_DURATION;
|
|
458
|
+
const name = typeof anim === "object" ? anim.name : anim;
|
|
459
|
+
if (type === "exit") {
|
|
460
|
+
const timing$1 = typeof anim === "object" ? anim.timing ?? "" : "";
|
|
461
|
+
return {
|
|
462
|
+
duration,
|
|
463
|
+
animation: `${duration}ms ${timing$1} ${name}`
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const timing = typeof anim === "object" ? anim.timing ?? "" : "";
|
|
467
|
+
return {
|
|
468
|
+
duration,
|
|
469
|
+
animation: `${duration}ms ${timing} ${name}`
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
return void 0;
|
|
473
|
+
}
|
|
357
474
|
|
|
358
475
|
//#endregion
|
|
359
476
|
//#region src/components/NotFound.tsx
|
|
@@ -419,6 +536,14 @@ var ReactPageProvider = class {
|
|
|
419
536
|
if (this.env.REACT_STRICT_MODE) return createElement(StrictMode, {}, root);
|
|
420
537
|
return root;
|
|
421
538
|
}
|
|
539
|
+
convertStringObjectToObject = (schema, value) => {
|
|
540
|
+
if (TypeGuard.IsObject(schema) && typeof value === "object") {
|
|
541
|
+
for (const key in schema.properties) if (TypeGuard.IsObject(schema.properties[key]) && typeof value[key] === "string") try {
|
|
542
|
+
value[key] = this.alepha.parse(schema.properties[key], decodeURIComponent(value[key]));
|
|
543
|
+
} catch (e) {}
|
|
544
|
+
}
|
|
545
|
+
return value;
|
|
546
|
+
};
|
|
422
547
|
/**
|
|
423
548
|
* Create a new RouterState based on a given route and request.
|
|
424
549
|
* This method resolves the layers for the route, applying any query and params schemas defined in the route.
|
|
@@ -438,6 +563,7 @@ var ReactPageProvider = class {
|
|
|
438
563
|
const route$1 = it.route;
|
|
439
564
|
const config = {};
|
|
440
565
|
try {
|
|
566
|
+
this.convertStringObjectToObject(route$1.schema?.query, state.query);
|
|
441
567
|
config.query = route$1.schema?.query ? this.alepha.parse(route$1.schema.query, state.query) : {};
|
|
442
568
|
} catch (e) {
|
|
443
569
|
it.error = e;
|
|
@@ -564,6 +690,7 @@ var ReactPageProvider = class {
|
|
|
564
690
|
}
|
|
565
691
|
}
|
|
566
692
|
async createElement(page, props) {
|
|
693
|
+
if (page.lazy && page.component) this.log.warn(`Page ${page.name} has both lazy and component options, lazy will be used`);
|
|
567
694
|
if (page.lazy) {
|
|
568
695
|
const component = await page.lazy();
|
|
569
696
|
return createElement(component.default, props);
|
|
@@ -572,7 +699,7 @@ var ReactPageProvider = class {
|
|
|
572
699
|
return void 0;
|
|
573
700
|
}
|
|
574
701
|
renderError(error) {
|
|
575
|
-
return createElement(
|
|
702
|
+
return createElement(ErrorViewer, {
|
|
576
703
|
error,
|
|
577
704
|
alepha: this.alepha
|
|
578
705
|
});
|
|
@@ -598,7 +725,7 @@ var ReactPageProvider = class {
|
|
|
598
725
|
}
|
|
599
726
|
renderView(index, path, view, page) {
|
|
600
727
|
view ??= this.renderEmptyView();
|
|
601
|
-
const element = page.client ? createElement(
|
|
728
|
+
const element = page.client ? createElement(ClientOnly, typeof page.client === "object" ? page.client : {}, view) : view;
|
|
602
729
|
return createElement(RouterLayerContext.Provider, { value: {
|
|
603
730
|
index,
|
|
604
731
|
path
|
|
@@ -692,6 +819,7 @@ var ReactServerProvider = class {
|
|
|
692
819
|
log = $logger();
|
|
693
820
|
alepha = $inject(Alepha);
|
|
694
821
|
pageApi = $inject(ReactPageProvider);
|
|
822
|
+
serverProvider = $inject(ServerProvider);
|
|
695
823
|
serverStaticProvider = $inject(ServerStaticProvider);
|
|
696
824
|
serverRouterProvider = $inject(ServerRouterProvider);
|
|
697
825
|
serverTimingProvider = $inject(ServerTimingProvider);
|
|
@@ -703,7 +831,23 @@ var ReactServerProvider = class {
|
|
|
703
831
|
const pages = this.alepha.descriptors($page);
|
|
704
832
|
const ssrEnabled = pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
|
|
705
833
|
this.alepha.state("react.server.ssr", ssrEnabled);
|
|
706
|
-
for (const page of pages)
|
|
834
|
+
for (const page of pages) {
|
|
835
|
+
page.render = this.createRenderFunction(page.name);
|
|
836
|
+
page.fetch = async (options) => {
|
|
837
|
+
const response = await fetch(`${this.serverProvider.hostname}/${page.pathname(options)}`);
|
|
838
|
+
const html = await response.text();
|
|
839
|
+
if (options?.html) return {
|
|
840
|
+
html,
|
|
841
|
+
response
|
|
842
|
+
};
|
|
843
|
+
const match = html.match(this.ROOT_DIV_REGEX);
|
|
844
|
+
if (match) return {
|
|
845
|
+
html: match[3],
|
|
846
|
+
response
|
|
847
|
+
};
|
|
848
|
+
throw new AlephaError("Invalid HTML response");
|
|
849
|
+
};
|
|
850
|
+
}
|
|
707
851
|
if (this.alepha.isServerless() === "vite") {
|
|
708
852
|
await this.configureVite(ssrEnabled);
|
|
709
853
|
return;
|
|
@@ -783,13 +927,18 @@ var ReactServerProvider = class {
|
|
|
783
927
|
params: options.params ?? {},
|
|
784
928
|
query: options.query ?? {},
|
|
785
929
|
onError: () => null,
|
|
786
|
-
layers: []
|
|
930
|
+
layers: [],
|
|
931
|
+
meta: {}
|
|
787
932
|
};
|
|
788
933
|
const state = entry;
|
|
789
934
|
this.log.trace("Rendering", { url });
|
|
790
935
|
await this.alepha.emit("react:server:render:begin", { state });
|
|
791
936
|
const { redirect } = await this.pageApi.createLayers(page, state);
|
|
792
|
-
if (redirect)
|
|
937
|
+
if (redirect) return {
|
|
938
|
+
state,
|
|
939
|
+
html: "",
|
|
940
|
+
redirect
|
|
941
|
+
};
|
|
793
942
|
if (!withIndex && !options.html) {
|
|
794
943
|
this.alepha.state("react.router.state", state);
|
|
795
944
|
return {
|
|
@@ -798,7 +947,11 @@ var ReactServerProvider = class {
|
|
|
798
947
|
};
|
|
799
948
|
}
|
|
800
949
|
const html = this.renderToHtml(this.template ?? "", state, options.hydration);
|
|
801
|
-
if (html instanceof Redirection)
|
|
950
|
+
if (html instanceof Redirection) return {
|
|
951
|
+
state,
|
|
952
|
+
html: "",
|
|
953
|
+
redirect
|
|
954
|
+
};
|
|
802
955
|
const result = {
|
|
803
956
|
state,
|
|
804
957
|
html
|
|
@@ -935,17 +1088,21 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
|
|
|
935
1088
|
});
|
|
936
1089
|
}
|
|
937
1090
|
});
|
|
938
|
-
async transition(url, previous = []) {
|
|
1091
|
+
async transition(url, previous = [], meta = {}) {
|
|
939
1092
|
const { pathname, search } = url;
|
|
940
1093
|
const entry = {
|
|
941
1094
|
url,
|
|
942
1095
|
query: {},
|
|
943
1096
|
params: {},
|
|
944
1097
|
layers: [],
|
|
945
|
-
onError: () => null
|
|
1098
|
+
onError: () => null,
|
|
1099
|
+
meta
|
|
946
1100
|
};
|
|
947
1101
|
const state = entry;
|
|
948
|
-
await this.alepha.emit("react:transition:begin", {
|
|
1102
|
+
await this.alepha.emit("react:transition:begin", {
|
|
1103
|
+
previous: this.alepha.state("react.router.state"),
|
|
1104
|
+
state
|
|
1105
|
+
});
|
|
949
1106
|
try {
|
|
950
1107
|
const { route, params } = this.match(pathname);
|
|
951
1108
|
const query = {};
|
|
@@ -980,8 +1137,8 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
|
|
|
980
1137
|
const layer = previous[i];
|
|
981
1138
|
if (state.layers[i]?.name !== layer.name) this.pageApi.page(layer.name)?.onLeave?.();
|
|
982
1139
|
}
|
|
983
|
-
await this.alepha.emit("react:transition:end", { state });
|
|
984
1140
|
this.alepha.state("react.router.state", state);
|
|
1141
|
+
await this.alepha.emit("react:transition:end", { state });
|
|
985
1142
|
}
|
|
986
1143
|
root(state) {
|
|
987
1144
|
return this.pageApi.root(state);
|
|
@@ -998,7 +1155,6 @@ var ReactBrowserProvider = class {
|
|
|
998
1155
|
alepha = $inject(Alepha);
|
|
999
1156
|
router = $inject(ReactBrowserRouterProvider);
|
|
1000
1157
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1001
|
-
root;
|
|
1002
1158
|
options = { scrollRestoration: "top" };
|
|
1003
1159
|
getRootElement() {
|
|
1004
1160
|
const root = this.document.getElementById(this.env.REACT_ROOT_ID);
|
|
@@ -1074,7 +1230,8 @@ var ReactBrowserProvider = class {
|
|
|
1074
1230
|
});
|
|
1075
1231
|
await this.render({
|
|
1076
1232
|
url,
|
|
1077
|
-
previous: options.force ? [] : this.state.layers
|
|
1233
|
+
previous: options.force ? [] : this.state.layers,
|
|
1234
|
+
meta: options.meta
|
|
1078
1235
|
});
|
|
1079
1236
|
if (this.state.url.pathname + this.state.url.search !== url) {
|
|
1080
1237
|
this.pushState(this.state.url.pathname + this.state.url.search);
|
|
@@ -1091,7 +1248,7 @@ var ReactBrowserProvider = class {
|
|
|
1091
1248
|
from: this.state?.url.pathname
|
|
1092
1249
|
};
|
|
1093
1250
|
this.log.debug("Transitioning...", { to: url });
|
|
1094
|
-
const redirect = await this.router.transition(new URL(`http://localhost${url}`), previous);
|
|
1251
|
+
const redirect = await this.router.transition(new URL(`http://localhost${url}`), previous, options.meta);
|
|
1095
1252
|
if (redirect) {
|
|
1096
1253
|
this.log.info("Redirecting to", { redirect });
|
|
1097
1254
|
return await this.render({ url: redirect });
|
|
@@ -1113,7 +1270,7 @@ var ReactBrowserProvider = class {
|
|
|
1113
1270
|
onTransitionEnd = $hook({
|
|
1114
1271
|
on: "react:transition:end",
|
|
1115
1272
|
handler: () => {
|
|
1116
|
-
if (this.options.scrollRestoration === "top" && typeof window !== "undefined") {
|
|
1273
|
+
if (this.options.scrollRestoration === "top" && typeof window !== "undefined" && !this.alepha.isTest()) {
|
|
1117
1274
|
this.log.trace("Restoring scroll position to top");
|
|
1118
1275
|
window.scrollTo(0, 0);
|
|
1119
1276
|
}
|
|
@@ -1129,14 +1286,12 @@ var ReactBrowserProvider = class {
|
|
|
1129
1286
|
}
|
|
1130
1287
|
await this.render({ previous });
|
|
1131
1288
|
const element = this.router.root(this.state);
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
this.
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
this.log.info("Created root element");
|
|
1139
|
-
}
|
|
1289
|
+
await this.alepha.emit("react:browser:render", {
|
|
1290
|
+
element,
|
|
1291
|
+
root: this.getRootElement(),
|
|
1292
|
+
hydration,
|
|
1293
|
+
state: this.state
|
|
1294
|
+
});
|
|
1140
1295
|
window.addEventListener("popstate", () => {
|
|
1141
1296
|
if (this.base + this.state.url.pathname === this.location.pathname) return;
|
|
1142
1297
|
this.log.debug("Popstate event triggered - rendering new state", { url: this.location.pathname + this.location.search });
|
|
@@ -1275,44 +1430,12 @@ const useRouter = () => {
|
|
|
1275
1430
|
//#region src/components/Link.tsx
|
|
1276
1431
|
const Link = (props) => {
|
|
1277
1432
|
const router = useRouter();
|
|
1278
|
-
const { to,...anchorProps } = props;
|
|
1279
1433
|
return /* @__PURE__ */ jsx("a", {
|
|
1280
|
-
...
|
|
1281
|
-
...
|
|
1434
|
+
...props,
|
|
1435
|
+
...router.anchor(props.href),
|
|
1282
1436
|
children: props.children
|
|
1283
1437
|
});
|
|
1284
1438
|
};
|
|
1285
|
-
var Link_default = Link;
|
|
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
|
-
return [state, (value) => {
|
|
1305
|
-
alepha.state(key, value);
|
|
1306
|
-
}];
|
|
1307
|
-
};
|
|
1308
|
-
|
|
1309
|
-
//#endregion
|
|
1310
|
-
//#region src/hooks/useRouterState.ts
|
|
1311
|
-
const useRouterState = () => {
|
|
1312
|
-
const [state] = useStore("react.router.state");
|
|
1313
|
-
if (!state) throw new AlephaError("Missing react router state");
|
|
1314
|
-
return state;
|
|
1315
|
-
};
|
|
1316
1439
|
|
|
1317
1440
|
//#endregion
|
|
1318
1441
|
//#region src/hooks/useActive.ts
|
|
@@ -1454,5 +1577,5 @@ const AlephaReact = $module({
|
|
|
1454
1577
|
});
|
|
1455
1578
|
|
|
1456
1579
|
//#endregion
|
|
1457
|
-
export { $page, AlephaContext, AlephaReact,
|
|
1580
|
+
export { $page, AlephaContext, AlephaReact, ClientOnly, ErrorBoundary, ErrorViewer, Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, ReactBrowserProvider, ReactPageProvider, ReactRouter, ReactServerProvider, Redirection, RouterLayerContext, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
|
|
1458
1581
|
//# sourceMappingURL=index.js.map
|