@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.cjs
CHANGED
|
@@ -33,7 +33,6 @@ const node_path = __toESM(require("node:path"));
|
|
|
33
33
|
const __alepha_server_static = __toESM(require("@alepha/server-static"));
|
|
34
34
|
const react_dom_server = __toESM(require("react-dom/server"));
|
|
35
35
|
const __alepha_datetime = __toESM(require("@alepha/datetime"));
|
|
36
|
-
const react_dom_client = __toESM(require("react-dom/client"));
|
|
37
36
|
const __alepha_router = __toESM(require("@alepha/router"));
|
|
38
37
|
|
|
39
38
|
//#region src/descriptors/$page.ts
|
|
@@ -58,7 +57,10 @@ var PageDescriptor = class extends __alepha_core.Descriptor {
|
|
|
58
57
|
* Only valid for server-side rendering, it will throw an error if called on the client-side.
|
|
59
58
|
*/
|
|
60
59
|
async render(options) {
|
|
61
|
-
throw new
|
|
60
|
+
throw new __alepha_core.AlephaError("render() method is not implemented in this environment");
|
|
61
|
+
}
|
|
62
|
+
async fetch(options) {
|
|
63
|
+
throw new __alepha_core.AlephaError("fetch() method is not implemented in this environment");
|
|
62
64
|
}
|
|
63
65
|
match(url) {
|
|
64
66
|
return false;
|
|
@@ -87,7 +89,6 @@ const ClientOnly = (props) => {
|
|
|
87
89
|
if (props.disabled) return props.children;
|
|
88
90
|
return mounted ? props.children : props.fallback;
|
|
89
91
|
};
|
|
90
|
-
var ClientOnly_default = ClientOnly;
|
|
91
92
|
|
|
92
93
|
//#endregion
|
|
93
94
|
//#region src/components/ErrorViewer.tsx
|
|
@@ -195,7 +196,6 @@ const ErrorViewer = ({ error, alepha }) => {
|
|
|
195
196
|
})] })]
|
|
196
197
|
});
|
|
197
198
|
};
|
|
198
|
-
var ErrorViewer_default = ErrorViewer;
|
|
199
199
|
const ErrorViewerProduction = () => {
|
|
200
200
|
const styles = {
|
|
201
201
|
container: {
|
|
@@ -289,19 +289,55 @@ const useRouterEvents = (opts = {}, deps = []) => {
|
|
|
289
289
|
const alepha = useAlepha();
|
|
290
290
|
(0, react.useEffect)(() => {
|
|
291
291
|
if (!alepha.isBrowser()) return;
|
|
292
|
+
const cb = (callback) => {
|
|
293
|
+
if (typeof callback === "function") return { callback };
|
|
294
|
+
return callback;
|
|
295
|
+
};
|
|
292
296
|
const subs = [];
|
|
293
297
|
const onBegin = opts.onBegin;
|
|
294
298
|
const onEnd = opts.onEnd;
|
|
295
299
|
const onError = opts.onError;
|
|
296
|
-
|
|
297
|
-
if (
|
|
298
|
-
if (
|
|
300
|
+
const onSuccess = opts.onSuccess;
|
|
301
|
+
if (onBegin) subs.push(alepha.on("react:transition:begin", cb(onBegin)));
|
|
302
|
+
if (onEnd) subs.push(alepha.on("react:transition:end", cb(onEnd)));
|
|
303
|
+
if (onError) subs.push(alepha.on("react:transition:error", cb(onError)));
|
|
304
|
+
if (onSuccess) subs.push(alepha.on("react:transition:success", cb(onSuccess)));
|
|
299
305
|
return () => {
|
|
300
306
|
for (const sub of subs) sub();
|
|
301
307
|
};
|
|
302
308
|
}, deps);
|
|
303
309
|
};
|
|
304
310
|
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/hooks/useStore.ts
|
|
313
|
+
/**
|
|
314
|
+
* Hook to access and mutate the Alepha state.
|
|
315
|
+
*/
|
|
316
|
+
const useStore = (key, defaultValue) => {
|
|
317
|
+
const alepha = useAlepha();
|
|
318
|
+
(0, react.useMemo)(() => {
|
|
319
|
+
if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
|
|
320
|
+
}, [defaultValue]);
|
|
321
|
+
const [state, setState] = (0, react.useState)(alepha.state(key));
|
|
322
|
+
(0, react.useEffect)(() => {
|
|
323
|
+
if (!alepha.isBrowser()) return;
|
|
324
|
+
return alepha.on("state:mutate", (ev) => {
|
|
325
|
+
if (ev.key === key) setState(ev.value);
|
|
326
|
+
});
|
|
327
|
+
}, []);
|
|
328
|
+
return [state, (value) => {
|
|
329
|
+
alepha.state(key, value);
|
|
330
|
+
}];
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/hooks/useRouterState.ts
|
|
335
|
+
const useRouterState = () => {
|
|
336
|
+
const [state] = useStore("react.router.state");
|
|
337
|
+
if (!state) throw new __alepha_core.AlephaError("Missing react router state");
|
|
338
|
+
return state;
|
|
339
|
+
};
|
|
340
|
+
|
|
305
341
|
//#endregion
|
|
306
342
|
//#region src/components/ErrorBoundary.tsx
|
|
307
343
|
/**
|
|
@@ -331,7 +367,6 @@ var ErrorBoundary = class extends react.default.Component {
|
|
|
331
367
|
return this.props.children;
|
|
332
368
|
}
|
|
333
369
|
};
|
|
334
|
-
var ErrorBoundary_default = ErrorBoundary;
|
|
335
370
|
|
|
336
371
|
//#endregion
|
|
337
372
|
//#region src/components/NestedView.tsx
|
|
@@ -342,7 +377,7 @@ var ErrorBoundary_default = ErrorBoundary;
|
|
|
342
377
|
*
|
|
343
378
|
* @example
|
|
344
379
|
* ```tsx
|
|
345
|
-
* import { NestedView } from "
|
|
380
|
+
* import { NestedView } from "alepha/react";
|
|
346
381
|
*
|
|
347
382
|
* class App {
|
|
348
383
|
* parent = $page({
|
|
@@ -357,17 +392,69 @@ var ErrorBoundary_default = ErrorBoundary;
|
|
|
357
392
|
* ```
|
|
358
393
|
*/
|
|
359
394
|
const NestedView = (props) => {
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const alepha = useAlepha();
|
|
363
|
-
const state = alepha.state("react.router.state");
|
|
364
|
-
if (!state) throw new Error("<NestedView/> must be used inside a RouterLayerContext.");
|
|
395
|
+
const index = (0, react.use)(RouterLayerContext)?.index ?? 0;
|
|
396
|
+
const state = useRouterState();
|
|
365
397
|
const [view, setView] = (0, react.useState)(state.layers[index]?.element);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
398
|
+
const [animation, setAnimation] = (0, react.useState)("");
|
|
399
|
+
const animationExitDuration = (0, react.useRef)(0);
|
|
400
|
+
const animationExitNow = (0, react.useRef)(0);
|
|
401
|
+
useRouterEvents({
|
|
402
|
+
onBegin: async ({ previous, state: state$1 }) => {
|
|
403
|
+
const layer = previous.layers[index];
|
|
404
|
+
if (`${state$1.url.pathname}/`.startsWith(`${layer?.path}/`)) return;
|
|
405
|
+
const animationExit = parseAnimation(layer.route?.animation, state$1, "exit");
|
|
406
|
+
if (animationExit) {
|
|
407
|
+
const duration = animationExit.duration || 200;
|
|
408
|
+
animationExitNow.current = Date.now();
|
|
409
|
+
animationExitDuration.current = duration;
|
|
410
|
+
setAnimation(animationExit.animation);
|
|
411
|
+
} else {
|
|
412
|
+
animationExitNow.current = 0;
|
|
413
|
+
animationExitDuration.current = 0;
|
|
414
|
+
setAnimation("");
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
onEnd: async ({ state: state$1 }) => {
|
|
418
|
+
const layer = state$1.layers[index];
|
|
419
|
+
if (animationExitNow.current) {
|
|
420
|
+
const duration = animationExitDuration.current;
|
|
421
|
+
const diff = Date.now() - animationExitNow.current;
|
|
422
|
+
if (diff < duration) await new Promise((resolve) => setTimeout(resolve, duration - diff));
|
|
423
|
+
}
|
|
424
|
+
if (!layer?.cache) {
|
|
425
|
+
setView(layer?.element);
|
|
426
|
+
const animationEnter = parseAnimation(layer?.route?.animation, state$1, "enter");
|
|
427
|
+
if (animationEnter) setAnimation(animationEnter.animation);
|
|
428
|
+
else setAnimation("");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}, []);
|
|
432
|
+
let element = view ?? props.children ?? null;
|
|
433
|
+
if (animation) element = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
434
|
+
style: {
|
|
435
|
+
display: "flex",
|
|
436
|
+
flex: 1,
|
|
437
|
+
height: "100%",
|
|
438
|
+
width: "100%",
|
|
439
|
+
position: "relative",
|
|
440
|
+
overflow: "hidden"
|
|
441
|
+
},
|
|
442
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
443
|
+
style: {
|
|
444
|
+
height: "100%",
|
|
445
|
+
width: "100%",
|
|
446
|
+
display: "flex",
|
|
447
|
+
animation
|
|
448
|
+
},
|
|
449
|
+
children: element
|
|
450
|
+
})
|
|
451
|
+
});
|
|
452
|
+
if (props.errorBoundary === false) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: element });
|
|
453
|
+
if (props.errorBoundary) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBoundary, {
|
|
454
|
+
fallback: props.errorBoundary,
|
|
455
|
+
children: element
|
|
456
|
+
});
|
|
457
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBoundary, {
|
|
371
458
|
fallback: (error) => {
|
|
372
459
|
const result = state.onError(error, state);
|
|
373
460
|
if (result instanceof Redirection) return "Redirection inside ErrorBoundary is not allowed.";
|
|
@@ -376,7 +463,37 @@ const NestedView = (props) => {
|
|
|
376
463
|
children: element
|
|
377
464
|
});
|
|
378
465
|
};
|
|
379
|
-
var NestedView_default = NestedView;
|
|
466
|
+
var NestedView_default = (0, react.memo)(NestedView);
|
|
467
|
+
function parseAnimation(animationLike, state, type = "enter") {
|
|
468
|
+
if (!animationLike) return void 0;
|
|
469
|
+
const DEFAULT_DURATION = 300;
|
|
470
|
+
const animation = typeof animationLike === "function" ? animationLike(state) : animationLike;
|
|
471
|
+
if (typeof animation === "string") {
|
|
472
|
+
if (type === "exit") return;
|
|
473
|
+
return {
|
|
474
|
+
duration: DEFAULT_DURATION,
|
|
475
|
+
animation: `${DEFAULT_DURATION}ms ${animation}`
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
if (typeof animation === "object") {
|
|
479
|
+
const anim = animation[type];
|
|
480
|
+
const duration = typeof anim === "object" ? anim.duration ?? DEFAULT_DURATION : DEFAULT_DURATION;
|
|
481
|
+
const name = typeof anim === "object" ? anim.name : anim;
|
|
482
|
+
if (type === "exit") {
|
|
483
|
+
const timing$1 = typeof anim === "object" ? anim.timing ?? "" : "";
|
|
484
|
+
return {
|
|
485
|
+
duration,
|
|
486
|
+
animation: `${duration}ms ${timing$1} ${name}`
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const timing = typeof anim === "object" ? anim.timing ?? "" : "";
|
|
490
|
+
return {
|
|
491
|
+
duration,
|
|
492
|
+
animation: `${duration}ms ${timing} ${name}`
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
return void 0;
|
|
496
|
+
}
|
|
380
497
|
|
|
381
498
|
//#endregion
|
|
382
499
|
//#region src/components/NotFound.tsx
|
|
@@ -442,6 +559,14 @@ var ReactPageProvider = class {
|
|
|
442
559
|
if (this.env.REACT_STRICT_MODE) return (0, react.createElement)(react.StrictMode, {}, root);
|
|
443
560
|
return root;
|
|
444
561
|
}
|
|
562
|
+
convertStringObjectToObject = (schema, value) => {
|
|
563
|
+
if (__alepha_core.TypeGuard.IsObject(schema) && typeof value === "object") {
|
|
564
|
+
for (const key in schema.properties) if (__alepha_core.TypeGuard.IsObject(schema.properties[key]) && typeof value[key] === "string") try {
|
|
565
|
+
value[key] = this.alepha.parse(schema.properties[key], decodeURIComponent(value[key]));
|
|
566
|
+
} catch (e) {}
|
|
567
|
+
}
|
|
568
|
+
return value;
|
|
569
|
+
};
|
|
445
570
|
/**
|
|
446
571
|
* Create a new RouterState based on a given route and request.
|
|
447
572
|
* This method resolves the layers for the route, applying any query and params schemas defined in the route.
|
|
@@ -461,6 +586,7 @@ var ReactPageProvider = class {
|
|
|
461
586
|
const route$1 = it.route;
|
|
462
587
|
const config = {};
|
|
463
588
|
try {
|
|
589
|
+
this.convertStringObjectToObject(route$1.schema?.query, state.query);
|
|
464
590
|
config.query = route$1.schema?.query ? this.alepha.parse(route$1.schema.query, state.query) : {};
|
|
465
591
|
} catch (e) {
|
|
466
592
|
it.error = e;
|
|
@@ -587,6 +713,7 @@ var ReactPageProvider = class {
|
|
|
587
713
|
}
|
|
588
714
|
}
|
|
589
715
|
async createElement(page, props) {
|
|
716
|
+
if (page.lazy && page.component) this.log.warn(`Page ${page.name} has both lazy and component options, lazy will be used`);
|
|
590
717
|
if (page.lazy) {
|
|
591
718
|
const component = await page.lazy();
|
|
592
719
|
return (0, react.createElement)(component.default, props);
|
|
@@ -595,7 +722,7 @@ var ReactPageProvider = class {
|
|
|
595
722
|
return void 0;
|
|
596
723
|
}
|
|
597
724
|
renderError(error) {
|
|
598
|
-
return (0, react.createElement)(
|
|
725
|
+
return (0, react.createElement)(ErrorViewer, {
|
|
599
726
|
error,
|
|
600
727
|
alepha: this.alepha
|
|
601
728
|
});
|
|
@@ -621,7 +748,7 @@ var ReactPageProvider = class {
|
|
|
621
748
|
}
|
|
622
749
|
renderView(index, path, view, page) {
|
|
623
750
|
view ??= this.renderEmptyView();
|
|
624
|
-
const element = page.client ? (0, react.createElement)(
|
|
751
|
+
const element = page.client ? (0, react.createElement)(ClientOnly, typeof page.client === "object" ? page.client : {}, view) : view;
|
|
625
752
|
return (0, react.createElement)(RouterLayerContext.Provider, { value: {
|
|
626
753
|
index,
|
|
627
754
|
path
|
|
@@ -715,6 +842,7 @@ var ReactServerProvider = class {
|
|
|
715
842
|
log = (0, __alepha_logger.$logger)();
|
|
716
843
|
alepha = (0, __alepha_core.$inject)(__alepha_core.Alepha);
|
|
717
844
|
pageApi = (0, __alepha_core.$inject)(ReactPageProvider);
|
|
845
|
+
serverProvider = (0, __alepha_core.$inject)(__alepha_server.ServerProvider);
|
|
718
846
|
serverStaticProvider = (0, __alepha_core.$inject)(__alepha_server_static.ServerStaticProvider);
|
|
719
847
|
serverRouterProvider = (0, __alepha_core.$inject)(__alepha_server.ServerRouterProvider);
|
|
720
848
|
serverTimingProvider = (0, __alepha_core.$inject)(__alepha_server.ServerTimingProvider);
|
|
@@ -726,7 +854,23 @@ var ReactServerProvider = class {
|
|
|
726
854
|
const pages = this.alepha.descriptors($page);
|
|
727
855
|
const ssrEnabled = pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
|
|
728
856
|
this.alepha.state("react.server.ssr", ssrEnabled);
|
|
729
|
-
for (const page of pages)
|
|
857
|
+
for (const page of pages) {
|
|
858
|
+
page.render = this.createRenderFunction(page.name);
|
|
859
|
+
page.fetch = async (options) => {
|
|
860
|
+
const response = await fetch(`${this.serverProvider.hostname}/${page.pathname(options)}`);
|
|
861
|
+
const html = await response.text();
|
|
862
|
+
if (options?.html) return {
|
|
863
|
+
html,
|
|
864
|
+
response
|
|
865
|
+
};
|
|
866
|
+
const match = html.match(this.ROOT_DIV_REGEX);
|
|
867
|
+
if (match) return {
|
|
868
|
+
html: match[3],
|
|
869
|
+
response
|
|
870
|
+
};
|
|
871
|
+
throw new __alepha_core.AlephaError("Invalid HTML response");
|
|
872
|
+
};
|
|
873
|
+
}
|
|
730
874
|
if (this.alepha.isServerless() === "vite") {
|
|
731
875
|
await this.configureVite(ssrEnabled);
|
|
732
876
|
return;
|
|
@@ -806,13 +950,18 @@ var ReactServerProvider = class {
|
|
|
806
950
|
params: options.params ?? {},
|
|
807
951
|
query: options.query ?? {},
|
|
808
952
|
onError: () => null,
|
|
809
|
-
layers: []
|
|
953
|
+
layers: [],
|
|
954
|
+
meta: {}
|
|
810
955
|
};
|
|
811
956
|
const state = entry;
|
|
812
957
|
this.log.trace("Rendering", { url });
|
|
813
958
|
await this.alepha.emit("react:server:render:begin", { state });
|
|
814
959
|
const { redirect } = await this.pageApi.createLayers(page, state);
|
|
815
|
-
if (redirect)
|
|
960
|
+
if (redirect) return {
|
|
961
|
+
state,
|
|
962
|
+
html: "",
|
|
963
|
+
redirect
|
|
964
|
+
};
|
|
816
965
|
if (!withIndex && !options.html) {
|
|
817
966
|
this.alepha.state("react.router.state", state);
|
|
818
967
|
return {
|
|
@@ -821,7 +970,11 @@ var ReactServerProvider = class {
|
|
|
821
970
|
};
|
|
822
971
|
}
|
|
823
972
|
const html = this.renderToHtml(this.template ?? "", state, options.hydration);
|
|
824
|
-
if (html instanceof Redirection)
|
|
973
|
+
if (html instanceof Redirection) return {
|
|
974
|
+
state,
|
|
975
|
+
html: "",
|
|
976
|
+
redirect
|
|
977
|
+
};
|
|
825
978
|
const result = {
|
|
826
979
|
state,
|
|
827
980
|
html
|
|
@@ -958,17 +1111,21 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
958
1111
|
});
|
|
959
1112
|
}
|
|
960
1113
|
});
|
|
961
|
-
async transition(url, previous = []) {
|
|
1114
|
+
async transition(url, previous = [], meta = {}) {
|
|
962
1115
|
const { pathname, search } = url;
|
|
963
1116
|
const entry = {
|
|
964
1117
|
url,
|
|
965
1118
|
query: {},
|
|
966
1119
|
params: {},
|
|
967
1120
|
layers: [],
|
|
968
|
-
onError: () => null
|
|
1121
|
+
onError: () => null,
|
|
1122
|
+
meta
|
|
969
1123
|
};
|
|
970
1124
|
const state = entry;
|
|
971
|
-
await this.alepha.emit("react:transition:begin", {
|
|
1125
|
+
await this.alepha.emit("react:transition:begin", {
|
|
1126
|
+
previous: this.alepha.state("react.router.state"),
|
|
1127
|
+
state
|
|
1128
|
+
});
|
|
972
1129
|
try {
|
|
973
1130
|
const { route, params } = this.match(pathname);
|
|
974
1131
|
const query = {};
|
|
@@ -1003,8 +1160,8 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
1003
1160
|
const layer = previous[i];
|
|
1004
1161
|
if (state.layers[i]?.name !== layer.name) this.pageApi.page(layer.name)?.onLeave?.();
|
|
1005
1162
|
}
|
|
1006
|
-
await this.alepha.emit("react:transition:end", { state });
|
|
1007
1163
|
this.alepha.state("react.router.state", state);
|
|
1164
|
+
await this.alepha.emit("react:transition:end", { state });
|
|
1008
1165
|
}
|
|
1009
1166
|
root(state) {
|
|
1010
1167
|
return this.pageApi.root(state);
|
|
@@ -1021,7 +1178,6 @@ var ReactBrowserProvider = class {
|
|
|
1021
1178
|
alepha = (0, __alepha_core.$inject)(__alepha_core.Alepha);
|
|
1022
1179
|
router = (0, __alepha_core.$inject)(ReactBrowserRouterProvider);
|
|
1023
1180
|
dateTimeProvider = (0, __alepha_core.$inject)(__alepha_datetime.DateTimeProvider);
|
|
1024
|
-
root;
|
|
1025
1181
|
options = { scrollRestoration: "top" };
|
|
1026
1182
|
getRootElement() {
|
|
1027
1183
|
const root = this.document.getElementById(this.env.REACT_ROOT_ID);
|
|
@@ -1097,7 +1253,8 @@ var ReactBrowserProvider = class {
|
|
|
1097
1253
|
});
|
|
1098
1254
|
await this.render({
|
|
1099
1255
|
url,
|
|
1100
|
-
previous: options.force ? [] : this.state.layers
|
|
1256
|
+
previous: options.force ? [] : this.state.layers,
|
|
1257
|
+
meta: options.meta
|
|
1101
1258
|
});
|
|
1102
1259
|
if (this.state.url.pathname + this.state.url.search !== url) {
|
|
1103
1260
|
this.pushState(this.state.url.pathname + this.state.url.search);
|
|
@@ -1114,7 +1271,7 @@ var ReactBrowserProvider = class {
|
|
|
1114
1271
|
from: this.state?.url.pathname
|
|
1115
1272
|
};
|
|
1116
1273
|
this.log.debug("Transitioning...", { to: url });
|
|
1117
|
-
const redirect = await this.router.transition(new URL(`http://localhost${url}`), previous);
|
|
1274
|
+
const redirect = await this.router.transition(new URL(`http://localhost${url}`), previous, options.meta);
|
|
1118
1275
|
if (redirect) {
|
|
1119
1276
|
this.log.info("Redirecting to", { redirect });
|
|
1120
1277
|
return await this.render({ url: redirect });
|
|
@@ -1136,7 +1293,7 @@ var ReactBrowserProvider = class {
|
|
|
1136
1293
|
onTransitionEnd = (0, __alepha_core.$hook)({
|
|
1137
1294
|
on: "react:transition:end",
|
|
1138
1295
|
handler: () => {
|
|
1139
|
-
if (this.options.scrollRestoration === "top" && typeof window !== "undefined") {
|
|
1296
|
+
if (this.options.scrollRestoration === "top" && typeof window !== "undefined" && !this.alepha.isTest()) {
|
|
1140
1297
|
this.log.trace("Restoring scroll position to top");
|
|
1141
1298
|
window.scrollTo(0, 0);
|
|
1142
1299
|
}
|
|
@@ -1152,14 +1309,12 @@ var ReactBrowserProvider = class {
|
|
|
1152
1309
|
}
|
|
1153
1310
|
await this.render({ previous });
|
|
1154
1311
|
const element = this.router.root(this.state);
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
this.
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
this.log.info("Created root element");
|
|
1162
|
-
}
|
|
1312
|
+
await this.alepha.emit("react:browser:render", {
|
|
1313
|
+
element,
|
|
1314
|
+
root: this.getRootElement(),
|
|
1315
|
+
hydration,
|
|
1316
|
+
state: this.state
|
|
1317
|
+
});
|
|
1163
1318
|
window.addEventListener("popstate", () => {
|
|
1164
1319
|
if (this.base + this.state.url.pathname === this.location.pathname) return;
|
|
1165
1320
|
this.log.debug("Popstate event triggered - rendering new state", { url: this.location.pathname + this.location.search });
|
|
@@ -1298,44 +1453,12 @@ const useRouter = () => {
|
|
|
1298
1453
|
//#region src/components/Link.tsx
|
|
1299
1454
|
const Link = (props) => {
|
|
1300
1455
|
const router = useRouter();
|
|
1301
|
-
const { to,...anchorProps } = props;
|
|
1302
1456
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1303
|
-
...
|
|
1304
|
-
...
|
|
1457
|
+
...props,
|
|
1458
|
+
...router.anchor(props.href),
|
|
1305
1459
|
children: props.children
|
|
1306
1460
|
});
|
|
1307
1461
|
};
|
|
1308
|
-
var Link_default = Link;
|
|
1309
|
-
|
|
1310
|
-
//#endregion
|
|
1311
|
-
//#region src/hooks/useStore.ts
|
|
1312
|
-
/**
|
|
1313
|
-
* Hook to access and mutate the Alepha state.
|
|
1314
|
-
*/
|
|
1315
|
-
const useStore = (key, defaultValue) => {
|
|
1316
|
-
const alepha = useAlepha();
|
|
1317
|
-
(0, react.useMemo)(() => {
|
|
1318
|
-
if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
|
|
1319
|
-
}, [defaultValue]);
|
|
1320
|
-
const [state, setState] = (0, react.useState)(alepha.state(key));
|
|
1321
|
-
(0, react.useEffect)(() => {
|
|
1322
|
-
if (!alepha.isBrowser()) return;
|
|
1323
|
-
return alepha.on("state:mutate", (ev) => {
|
|
1324
|
-
if (ev.key === key) setState(ev.value);
|
|
1325
|
-
});
|
|
1326
|
-
}, []);
|
|
1327
|
-
return [state, (value) => {
|
|
1328
|
-
alepha.state(key, value);
|
|
1329
|
-
}];
|
|
1330
|
-
};
|
|
1331
|
-
|
|
1332
|
-
//#endregion
|
|
1333
|
-
//#region src/hooks/useRouterState.ts
|
|
1334
|
-
const useRouterState = () => {
|
|
1335
|
-
const [state] = useStore("react.router.state");
|
|
1336
|
-
if (!state) throw new __alepha_core.AlephaError("Missing react router state");
|
|
1337
|
-
return state;
|
|
1338
|
-
};
|
|
1339
1462
|
|
|
1340
1463
|
//#endregion
|
|
1341
1464
|
//#region src/hooks/useActive.ts
|
|
@@ -1480,10 +1603,10 @@ const AlephaReact = (0, __alepha_core.$module)({
|
|
|
1480
1603
|
exports.$page = $page;
|
|
1481
1604
|
exports.AlephaContext = AlephaContext;
|
|
1482
1605
|
exports.AlephaReact = AlephaReact;
|
|
1483
|
-
exports.ClientOnly =
|
|
1484
|
-
exports.ErrorBoundary =
|
|
1485
|
-
exports.ErrorViewer =
|
|
1486
|
-
exports.Link =
|
|
1606
|
+
exports.ClientOnly = ClientOnly;
|
|
1607
|
+
exports.ErrorBoundary = ErrorBoundary;
|
|
1608
|
+
exports.ErrorViewer = ErrorViewer;
|
|
1609
|
+
exports.Link = Link;
|
|
1487
1610
|
exports.NestedView = NestedView_default;
|
|
1488
1611
|
exports.NotFound = NotFoundPage;
|
|
1489
1612
|
exports.PageDescriptor = PageDescriptor;
|