@alepha/react 0.7.0 → 0.7.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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/index.browser.cjs +59 -22
  3. package/dist/index.browser.js +42 -6
  4. package/dist/index.cjs +152 -85
  5. package/dist/index.d.ts +317 -206
  6. package/dist/index.js +130 -64
  7. package/dist/{useActive-DjpZBEuB.cjs → useRouterState-C2uo0jXu.cjs} +319 -140
  8. package/dist/{useActive-BX41CqY8.js → useRouterState-D5__ZcUV.js} +321 -143
  9. package/package.json +11 -10
  10. package/src/components/ClientOnly.tsx +35 -0
  11. package/src/components/ErrorBoundary.tsx +1 -1
  12. package/src/components/ErrorViewer.tsx +161 -0
  13. package/src/components/Link.tsx +9 -3
  14. package/src/components/NestedView.tsx +18 -3
  15. package/src/components/NotFound.tsx +30 -0
  16. package/src/descriptors/$page.ts +141 -30
  17. package/src/errors/RedirectionError.ts +4 -1
  18. package/src/hooks/RouterHookApi.ts +42 -24
  19. package/src/hooks/useAlepha.ts +12 -0
  20. package/src/hooks/useClient.ts +8 -6
  21. package/src/hooks/useInject.ts +2 -2
  22. package/src/hooks/useQueryParams.ts +1 -1
  23. package/src/hooks/useRouter.ts +6 -0
  24. package/src/index.browser.ts +4 -2
  25. package/src/index.shared.ts +11 -5
  26. package/src/index.ts +3 -4
  27. package/src/providers/BrowserRouterProvider.ts +4 -3
  28. package/src/providers/PageDescriptorProvider.ts +91 -20
  29. package/src/providers/ReactBrowserProvider.ts +6 -59
  30. package/src/providers/ReactBrowserRenderer.ts +72 -0
  31. package/src/providers/ReactServerProvider.ts +200 -81
  32. package/dist/index.browser.cjs.map +0 -1
  33. package/dist/index.browser.js.map +0 -1
  34. package/dist/index.cjs.map +0 -1
  35. package/dist/index.js.map +0 -1
  36. package/dist/useActive-BX41CqY8.js.map +0 -1
  37. package/dist/useActive-DjpZBEuB.cjs.map +0 -1
@@ -1,8 +1,7 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { __descriptor, OPTIONS, NotImplementedError, KIND, $logger, $inject, Alepha, $hook, t } from '@alepha/core';
3
- import React, { createContext, useContext, useEffect, useState, createElement, useMemo } from 'react';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { __descriptor, OPTIONS, NotImplementedError, KIND, t, $logger, $inject, Alepha, $hook } from '@alepha/core';
3
+ import React, { useState, useEffect, createContext, useContext, createElement, StrictMode, useMemo } from 'react';
4
4
  import { HttpClient } from '@alepha/server';
5
- import { hydrateRoot, createRoot } from 'react-dom/client';
6
5
  import { RouterProvider } from '@alepha/router';
7
6
 
8
7
  const KEY = "PAGE";
@@ -26,27 +25,161 @@ const $page = (options) => {
26
25
  [OPTIONS]: options,
27
26
  render: () => {
28
27
  throw new NotImplementedError(KEY);
29
- },
30
- go: () => {
31
- throw new NotImplementedError(KEY);
32
- },
33
- createAnchorProps: () => {
34
- throw new NotImplementedError(KEY);
35
- },
36
- can: () => {
37
- if (options.can) {
38
- return options.can();
39
- }
40
- return true;
41
28
  }
42
29
  };
43
30
  };
44
31
  $page[KIND] = KEY;
45
32
 
33
+ const ClientOnly = (props) => {
34
+ const [mounted, setMounted] = useState(false);
35
+ useEffect(() => setMounted(true), []);
36
+ if (props.disabled) {
37
+ return props.children;
38
+ }
39
+ return mounted ? props.children : props.fallback;
40
+ };
41
+
46
42
  const RouterContext = createContext(
47
43
  void 0
48
44
  );
49
45
 
46
+ const useAlepha = () => {
47
+ const routerContext = useContext(RouterContext);
48
+ if (!routerContext) {
49
+ throw new Error("useAlepha must be used within a RouterProvider");
50
+ }
51
+ return routerContext.alepha;
52
+ };
53
+
54
+ const ErrorViewer = ({ error }) => {
55
+ const [expanded, setExpanded] = useState(false);
56
+ const isProduction = useAlepha().isProduction();
57
+ if (isProduction) {
58
+ return /* @__PURE__ */ jsx(ErrorViewerProduction, {});
59
+ }
60
+ const stackLines = error.stack?.split("\n") ?? [];
61
+ const previewLines = stackLines.slice(0, 5);
62
+ const hiddenLineCount = stackLines.length - previewLines.length;
63
+ const copyToClipboard = (text) => {
64
+ navigator.clipboard.writeText(text).catch((err) => {
65
+ console.error("Clipboard error:", err);
66
+ });
67
+ };
68
+ const styles = {
69
+ container: {
70
+ padding: "24px",
71
+ backgroundColor: "#FEF2F2",
72
+ color: "#7F1D1D",
73
+ border: "1px solid #FECACA",
74
+ borderRadius: "16px",
75
+ boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
76
+ fontFamily: "monospace",
77
+ maxWidth: "768px",
78
+ margin: "40px auto"
79
+ },
80
+ heading: {
81
+ fontSize: "20px",
82
+ fontWeight: "bold",
83
+ marginBottom: "4px"
84
+ },
85
+ name: {
86
+ fontSize: "16px",
87
+ fontWeight: 600
88
+ },
89
+ message: {
90
+ fontSize: "14px",
91
+ marginBottom: "16px"
92
+ },
93
+ sectionHeader: {
94
+ display: "flex",
95
+ justifyContent: "space-between",
96
+ alignItems: "center",
97
+ fontSize: "12px",
98
+ marginBottom: "4px",
99
+ color: "#991B1B"
100
+ },
101
+ copyButton: {
102
+ fontSize: "12px",
103
+ color: "#DC2626",
104
+ background: "none",
105
+ border: "none",
106
+ cursor: "pointer",
107
+ textDecoration: "underline"
108
+ },
109
+ stackContainer: {
110
+ backgroundColor: "#FEE2E2",
111
+ padding: "12px",
112
+ borderRadius: "8px",
113
+ fontSize: "13px",
114
+ lineHeight: "1.4",
115
+ overflowX: "auto",
116
+ whiteSpace: "pre-wrap"
117
+ },
118
+ expandLine: {
119
+ color: "#F87171",
120
+ cursor: "pointer",
121
+ marginTop: "8px"
122
+ }
123
+ };
124
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, children: [
125
+ /* @__PURE__ */ jsxs("div", { children: [
126
+ /* @__PURE__ */ jsx("div", { style: styles.heading, children: "\u{1F525} Error" }),
127
+ /* @__PURE__ */ jsx("div", { style: styles.name, children: error.name }),
128
+ /* @__PURE__ */ jsx("div", { style: styles.message, children: error.message })
129
+ ] }),
130
+ stackLines.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
131
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
132
+ /* @__PURE__ */ jsx("span", { children: "Stack trace" }),
133
+ /* @__PURE__ */ jsx(
134
+ "button",
135
+ {
136
+ onClick: () => copyToClipboard(error.stack),
137
+ style: styles.copyButton,
138
+ children: "Copy all"
139
+ }
140
+ )
141
+ ] }),
142
+ /* @__PURE__ */ jsxs("pre", { style: styles.stackContainer, children: [
143
+ (expanded ? stackLines : previewLines).map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i)),
144
+ !expanded && hiddenLineCount > 0 && /* @__PURE__ */ jsxs("div", { style: styles.expandLine, onClick: () => setExpanded(true), children: [
145
+ "+ ",
146
+ hiddenLineCount,
147
+ " more lines..."
148
+ ] })
149
+ ] })
150
+ ] })
151
+ ] });
152
+ };
153
+ const ErrorViewerProduction = () => {
154
+ const styles = {
155
+ container: {
156
+ padding: "24px",
157
+ backgroundColor: "#FEF2F2",
158
+ color: "#7F1D1D",
159
+ border: "1px solid #FECACA",
160
+ borderRadius: "16px",
161
+ boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
162
+ fontFamily: "monospace",
163
+ maxWidth: "768px",
164
+ margin: "40px auto",
165
+ textAlign: "center"
166
+ },
167
+ heading: {
168
+ fontSize: "20px",
169
+ fontWeight: "bold",
170
+ marginBottom: "8px"
171
+ },
172
+ message: {
173
+ fontSize: "14px",
174
+ opacity: 0.85
175
+ }
176
+ };
177
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, children: [
178
+ /* @__PURE__ */ jsx("div", { style: styles.heading, children: "\u{1F6A8} An error occurred" }),
179
+ /* @__PURE__ */ jsx("div", { style: styles.message, children: "Something went wrong. Please try again later." })
180
+ ] });
181
+ };
182
+
50
183
  const RouterLayerContext = createContext(void 0);
51
184
 
52
185
  const useRouterEvents = (opts = {}, deps = []) => {
@@ -143,15 +276,53 @@ const NestedView = (props) => {
143
276
  return /* @__PURE__ */ jsx(ErrorBoundary, { fallback: app.context.onError, children: element });
144
277
  };
145
278
 
279
+ function NotFoundPage() {
280
+ return /* @__PURE__ */ jsxs(
281
+ "div",
282
+ {
283
+ style: {
284
+ height: "100vh",
285
+ display: "flex",
286
+ flexDirection: "column",
287
+ justifyContent: "center",
288
+ alignItems: "center",
289
+ textAlign: "center",
290
+ fontFamily: "sans-serif",
291
+ padding: "1rem"
292
+ },
293
+ children: [
294
+ /* @__PURE__ */ jsx("h1", { style: { fontSize: "1rem", marginBottom: "0.5rem" }, children: "This page does not exist" }),
295
+ /* @__PURE__ */ jsx(
296
+ "a",
297
+ {
298
+ href: "/",
299
+ style: {
300
+ fontSize: "0.7rem",
301
+ color: "#007bff",
302
+ textDecoration: "none"
303
+ },
304
+ children: "\u2190 Back to home"
305
+ }
306
+ )
307
+ ]
308
+ }
309
+ );
310
+ }
311
+
146
312
  class RedirectionError extends Error {
313
+ page;
147
314
  constructor(page) {
148
315
  super("Redirection");
149
316
  this.page = page;
150
317
  }
151
318
  }
152
319
 
320
+ const envSchema = t.object({
321
+ REACT_STRICT_MODE: t.boolean({ default: true })
322
+ });
153
323
  class PageDescriptorProvider {
154
324
  log = $logger();
325
+ env = $inject(envSchema);
155
326
  alepha = $inject(Alepha);
156
327
  pages = [];
157
328
  getPages() {
@@ -165,8 +336,25 @@ class PageDescriptorProvider {
165
336
  }
166
337
  throw new Error(`Page ${name} not found`);
167
338
  }
339
+ url(name, options = {}) {
340
+ const page = this.page(name);
341
+ if (!page) {
342
+ throw new Error(`Page ${name} not found`);
343
+ }
344
+ let url = page.path ?? "";
345
+ let parent = page.parent;
346
+ while (parent) {
347
+ url = `${parent.path ?? ""}/${url}`;
348
+ parent = parent.parent;
349
+ }
350
+ url = this.compile(url, options.params ?? {});
351
+ return new URL(
352
+ url.replace(/\/\/+/g, "/") || "/",
353
+ options.base ?? `http://localhost`
354
+ );
355
+ }
168
356
  root(state, context) {
169
- return createElement(
357
+ const root = createElement(
170
358
  RouterContext.Provider,
171
359
  {
172
360
  value: {
@@ -177,13 +365,17 @@ class PageDescriptorProvider {
177
365
  },
178
366
  createElement(NestedView, {}, state.layers[0]?.element)
179
367
  );
368
+ if (this.env.REACT_STRICT_MODE) {
369
+ return createElement(StrictMode, {}, root);
370
+ }
371
+ return root;
180
372
  }
181
373
  async createLayers(route, request) {
182
374
  const { pathname, search } = request.url;
183
375
  const layers = [];
184
376
  let context = {};
185
377
  const stack = [{ route }];
186
- let onError = this.renderError;
378
+ request.onError = (error) => this.renderError(error);
187
379
  let parent = route.parent;
188
380
  while (parent) {
189
381
  stack.unshift({ route: parent });
@@ -283,23 +475,26 @@ class PageDescriptorProvider {
283
475
  const path = acc.replace(/\/+/, "/");
284
476
  const localErrorHandler = this.getErrorHandler(it.route);
285
477
  if (localErrorHandler) {
286
- onError = localErrorHandler;
478
+ request.onError = localErrorHandler;
287
479
  }
288
480
  if (it.error) {
289
- const element = await onError(it.error);
481
+ let element2 = await request.onError(it.error);
482
+ if (element2 === null) {
483
+ element2 = this.renderError(it.error);
484
+ }
290
485
  layers.push({
291
486
  props,
292
487
  error: it.error,
293
488
  name: it.route.name,
294
489
  part: it.route.path,
295
490
  config: it.config,
296
- element: this.renderView(i + 1, path, element),
491
+ element: this.renderView(i + 1, path, element2, it.route),
297
492
  index: i + 1,
298
493
  path
299
494
  });
300
495
  break;
301
496
  }
302
- const layer = await this.createElement(it.route, {
497
+ const element = await this.createElement(it.route, {
303
498
  ...props,
304
499
  ...context
305
500
  });
@@ -308,7 +503,7 @@ class PageDescriptorProvider {
308
503
  props,
309
504
  part: it.route.path,
310
505
  config: it.config,
311
- element: this.renderView(i + 1, path, layer),
506
+ element: this.renderView(i + 1, path, element, it.route),
312
507
  index: i + 1,
313
508
  path
314
509
  });
@@ -364,8 +559,8 @@ class PageDescriptorProvider {
364
559
  ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
365
560
  }
366
561
  }
367
- renderError(e) {
368
- return createElement("pre", { style: { overflow: "auto" } }, `${e.stack}`);
562
+ renderError(error) {
563
+ return createElement(ErrorViewer, { error });
369
564
  }
370
565
  renderEmptyView() {
371
566
  return createElement(NestedView, {});
@@ -390,7 +585,13 @@ class PageDescriptorProvider {
390
585
  }
391
586
  return path;
392
587
  }
393
- renderView(index, path, view = this.renderEmptyView()) {
588
+ renderView(index, path, view, page) {
589
+ view ??= this.renderEmptyView();
590
+ const element = page.client ? createElement(
591
+ ClientOnly,
592
+ typeof page.client === "object" ? page.client : {},
593
+ view
594
+ ) : view;
394
595
  return createElement(
395
596
  RouterLayerContext.Provider,
396
597
  {
@@ -399,29 +600,41 @@ class PageDescriptorProvider {
399
600
  path
400
601
  }
401
602
  },
402
- view
603
+ element
403
604
  );
404
605
  }
405
606
  configure = $hook({
406
607
  name: "configure",
407
608
  handler: () => {
609
+ let hasNotFoundHandler = false;
408
610
  const pages = this.alepha.getDescriptorValues($page);
409
611
  for (const { value, key } of pages) {
410
612
  value[OPTIONS].name ??= key;
613
+ }
614
+ for (const { value } of pages) {
411
615
  if (value[OPTIONS].parent) {
412
616
  continue;
413
617
  }
618
+ if (value[OPTIONS].path === "/*") {
619
+ hasNotFoundHandler = true;
620
+ }
414
621
  this.add(this.map(pages, value));
415
622
  }
623
+ if (!hasNotFoundHandler && pages.length > 0) {
624
+ this.add({
625
+ path: "/*",
626
+ name: "notFound",
627
+ cache: true,
628
+ component: NotFoundPage,
629
+ afterHandler: ({ reply }) => {
630
+ reply.status = 404;
631
+ }
632
+ });
633
+ }
416
634
  }
417
635
  });
418
636
  map(pages, target) {
419
637
  const children = target[OPTIONS].children ?? [];
420
- for (const it of pages) {
421
- if (it.value[OPTIONS].parent === target) {
422
- children.push(it.value);
423
- }
424
- }
425
638
  return {
426
639
  ...target[OPTIONS],
427
640
  parent: void 0,
@@ -570,7 +783,7 @@ class BrowserRouterProvider extends RouterProvider {
570
783
  if (state.layers.length === 0) {
571
784
  state.layers.push({
572
785
  name: "not-found",
573
- element: "Not Found",
786
+ element: createElement(NotFoundPage),
574
787
  index: 0,
575
788
  path: "/"
576
789
  });
@@ -611,16 +824,12 @@ class BrowserRouterProvider extends RouterProvider {
611
824
  }
612
825
  }
613
826
 
614
- const envSchema = t.object({
615
- REACT_ROOT_ID: t.string({ default: "root" })
616
- });
617
827
  class ReactBrowserProvider {
618
828
  log = $logger();
619
829
  client = $inject(HttpClient);
620
830
  alepha = $inject(Alepha);
621
831
  router = $inject(BrowserRouterProvider);
622
832
  headProvider = $inject(BrowserHeadProvider);
623
- env = $inject(envSchema);
624
833
  root;
625
834
  transitioning;
626
835
  state = {
@@ -658,11 +867,6 @@ class ReactBrowserProvider {
658
867
  }
659
868
  await this.render({ previous });
660
869
  }
661
- /**
662
- *
663
- * @param url
664
- * @param options
665
- */
666
870
  async go(url, options = {}) {
667
871
  const result = await this.render({
668
872
  url
@@ -696,8 +900,6 @@ class ReactBrowserProvider {
696
900
  }
697
901
  /**
698
902
  * Get embedded layers from the server.
699
- *
700
- * @protected
701
903
  */
702
904
  getHydrationState() {
703
905
  try {
@@ -708,32 +910,14 @@ class ReactBrowserProvider {
708
910
  console.error(error);
709
911
  }
710
912
  }
711
- /**
712
- *
713
- * @protected
714
- */
715
- getRootElement() {
716
- const root = this.document.getElementById(this.env.REACT_ROOT_ID);
717
- if (root) {
718
- return root;
719
- }
720
- const div = this.document.createElement("div");
721
- div.id = this.env.REACT_ROOT_ID;
722
- this.document.body.prepend(div);
723
- return div;
724
- }
725
913
  // -------------------------------------------------------------------------------------------------------------------
726
- /**
727
- *
728
- * @protected
729
- */
730
914
  ready = $hook({
731
915
  name: "ready",
732
916
  handler: async () => {
733
917
  const hydration = this.getHydrationState();
734
918
  const previous = hydration?.layers ?? [];
735
919
  if (hydration?.links) {
736
- for (const link of hydration.links) {
920
+ for (const link of hydration.links.links) {
737
921
  this.client.pushLink(link);
738
922
  }
739
923
  }
@@ -746,15 +930,6 @@ class ReactBrowserProvider {
746
930
  context,
747
931
  hydration
748
932
  });
749
- const element = this.router.root(this.state, context);
750
- if (previous.length > 0) {
751
- this.root = hydrateRoot(this.getRootElement(), element);
752
- this.log.info("Hydrated root element");
753
- } else {
754
- this.root ??= createRoot(this.getRootElement());
755
- this.root.render(element);
756
- this.log.info("Created root element");
757
- }
758
933
  window.addEventListener("popstate", () => {
759
934
  this.render();
760
935
  });
@@ -769,26 +944,18 @@ class ReactBrowserProvider {
769
944
  }
770
945
 
771
946
  class RouterHookApi {
772
- constructor(state, layer, browser) {
947
+ constructor(pages, state, layer, browser) {
948
+ this.pages = pages;
773
949
  this.state = state;
774
950
  this.layer = layer;
775
951
  this.browser = browser;
776
952
  }
777
- /**
778
- *
779
- */
780
953
  get current() {
781
954
  return this.state;
782
955
  }
783
- /**
784
- *
785
- */
786
956
  get pathname() {
787
957
  return this.state.pathname;
788
958
  }
789
- /**
790
- *
791
- */
792
959
  get query() {
793
960
  const query = {};
794
961
  for (const [key, value] of new URLSearchParams(
@@ -798,22 +965,12 @@ class RouterHookApi {
798
965
  }
799
966
  return query;
800
967
  }
801
- /**
802
- *
803
- */
804
968
  async back() {
805
969
  this.browser?.history.back();
806
970
  }
807
- /**
808
- *
809
- */
810
971
  async forward() {
811
972
  this.browser?.history.forward();
812
973
  }
813
- /**
814
- *
815
- * @param props
816
- */
817
974
  async invalidate(props) {
818
975
  await this.browser?.invalidate(props);
819
976
  }
@@ -823,23 +980,40 @@ class RouterHookApi {
823
980
  * @param pathname
824
981
  * @param layer
825
982
  */
826
- createHref(pathname, layer = this.layer) {
983
+ createHref(pathname, layer = this.layer, options = {}) {
827
984
  if (typeof pathname === "object") {
828
985
  pathname = pathname.options.path ?? "";
829
986
  }
987
+ if (options.params) {
988
+ for (const [key, value] of Object.entries(options.params)) {
989
+ pathname = pathname.replace(`:${key}`, String(value));
990
+ }
991
+ }
830
992
  return pathname.startsWith("/") ? pathname : `${layer.path}/${pathname}`.replace(/\/\/+/g, "/");
831
993
  }
832
994
  async go(path, options) {
833
- await this.browser?.go(this.createHref(path, this.layer), options);
995
+ for (const page of this.pages) {
996
+ if (page.name === path) {
997
+ path = page.path ?? "";
998
+ break;
999
+ }
1000
+ }
1001
+ await this.browser?.go(this.createHref(path, this.layer, options), options);
834
1002
  }
835
- anchor(path) {
836
- const href = this.createHref(path, this.layer);
1003
+ anchor(path, options = {}) {
1004
+ for (const page of this.pages) {
1005
+ if (page.name === path) {
1006
+ path = page.path ?? "";
1007
+ break;
1008
+ }
1009
+ }
1010
+ const href = this.createHref(path, this.layer, options);
837
1011
  return {
838
1012
  href,
839
1013
  onClick: (ev) => {
840
1014
  ev.stopPropagation();
841
1015
  ev.preventDefault();
842
- this.go(path).catch(console.error);
1016
+ this.go(path, options).catch(console.error);
843
1017
  }
844
1018
  };
845
1019
  }
@@ -867,8 +1041,12 @@ const useRouter = () => {
867
1041
  if (!ctx || !layer) {
868
1042
  throw new Error("useRouter must be used within a RouterProvider");
869
1043
  }
1044
+ const pages = useMemo(() => {
1045
+ return ctx.alepha.get(PageDescriptorProvider).getPages();
1046
+ }, []);
870
1047
  return useMemo(
871
1048
  () => new RouterHookApi(
1049
+ pages,
872
1050
  ctx.state,
873
1051
  layer,
874
1052
  ctx.alepha.isBrowser() ? ctx.alepha.get(ReactBrowserProvider) : void 0
@@ -879,6 +1057,7 @@ const useRouter = () => {
879
1057
 
880
1058
  const Link = (props) => {
881
1059
  React.useContext(RouterContext);
1060
+ const router = useRouter();
882
1061
  const to = typeof props.to === "string" ? props.to : props.to[OPTIONS].path;
883
1062
  if (!to) {
884
1063
  return null;
@@ -888,8 +1067,49 @@ const Link = (props) => {
888
1067
  return null;
889
1068
  }
890
1069
  const name = typeof props.to === "string" ? void 0 : props.to[OPTIONS].name;
1070
+ const anchorProps = {
1071
+ ...props,
1072
+ to: void 0
1073
+ };
1074
+ return /* @__PURE__ */ jsx("a", { ...router.anchor(to), ...anchorProps, children: props.children ?? name });
1075
+ };
1076
+
1077
+ const useActive = (path) => {
891
1078
  const router = useRouter();
892
- return /* @__PURE__ */ jsx("a", { ...router.anchor(to), ...props, children: props.children ?? name });
1079
+ const ctx = useContext(RouterContext);
1080
+ const layer = useContext(RouterLayerContext);
1081
+ if (!ctx || !layer) {
1082
+ throw new Error("useRouter must be used within a RouterProvider");
1083
+ }
1084
+ let name;
1085
+ if (typeof path === "object" && path.options.name) {
1086
+ name = path.options.name;
1087
+ }
1088
+ const [current, setCurrent] = useState(ctx.state.pathname);
1089
+ const href = useMemo(() => router.createHref(path, layer), [path, layer]);
1090
+ const [isPending, setPending] = useState(false);
1091
+ const isActive = current === href;
1092
+ useRouterEvents({
1093
+ onEnd: ({ state }) => setCurrent(state.pathname)
1094
+ });
1095
+ return {
1096
+ name,
1097
+ isPending,
1098
+ isActive,
1099
+ anchorProps: {
1100
+ href,
1101
+ onClick: (ev) => {
1102
+ ev.stopPropagation();
1103
+ ev.preventDefault();
1104
+ if (isActive) return;
1105
+ if (isPending) return;
1106
+ setPending(true);
1107
+ router.go(href).then(() => {
1108
+ setPending(false);
1109
+ });
1110
+ }
1111
+ }
1112
+ };
893
1113
  };
894
1114
 
895
1115
  const useInject = (clazz) => {
@@ -900,10 +1120,7 @@ const useInject = (clazz) => {
900
1120
  return useMemo(() => ctx.alepha.get(clazz), []);
901
1121
  };
902
1122
 
903
- const useClient = () => {
904
- return useInject(HttpClient);
905
- };
906
- const useApi = () => {
1123
+ const useClient = (_scope) => {
907
1124
  return useInject(HttpClient).of();
908
1125
  };
909
1126
 
@@ -937,7 +1154,7 @@ const encode = (alepha, schema, data) => {
937
1154
  const decode = (alepha, schema, data) => {
938
1155
  try {
939
1156
  return alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));
940
- } catch (error) {
1157
+ } catch (_error) {
941
1158
  return {};
942
1159
  }
943
1160
  };
@@ -955,43 +1172,4 @@ const useRouterState = () => {
955
1172
  return state;
956
1173
  };
957
1174
 
958
- const useActive = (path) => {
959
- const router = useRouter();
960
- const ctx = useContext(RouterContext);
961
- const layer = useContext(RouterLayerContext);
962
- if (!ctx || !layer) {
963
- throw new Error("useRouter must be used within a RouterProvider");
964
- }
965
- let name;
966
- if (typeof path === "object" && path.options.name) {
967
- name = path.options.name;
968
- }
969
- const [current, setCurrent] = useState(ctx.state.pathname);
970
- const href = useMemo(() => router.createHref(path, layer), [path, layer]);
971
- const [isPending, setPending] = useState(false);
972
- const isActive = current === href;
973
- useRouterEvents({
974
- onEnd: ({ state }) => setCurrent(state.pathname)
975
- });
976
- return {
977
- name,
978
- isPending,
979
- isActive,
980
- anchorProps: {
981
- href,
982
- onClick: (ev) => {
983
- ev.stopPropagation();
984
- ev.preventDefault();
985
- if (isActive) return;
986
- if (isPending) return;
987
- setPending(true);
988
- router.go(href).then(() => {
989
- setPending(false);
990
- });
991
- }
992
- }
993
- };
994
- };
995
-
996
- export { $page as $, BrowserRouterProvider as B, ErrorBoundary as E, Link as L, NestedView as N, PageDescriptorProvider as P, RouterContext as R, RouterLayerContext as a, RouterHookApi as b, useClient as c, useApi as d, useQueryParams as e, useRouter as f, useRouterEvents as g, useRouterState as h, useActive as i, RedirectionError as j, isPageRoute as k, ReactBrowserProvider as l, useInject as u };
997
- //# sourceMappingURL=useActive-BX41CqY8.js.map
1175
+ export { $page as $, BrowserRouterProvider as B, ClientOnly as C, ErrorBoundary as E, Link as L, NestedView as N, PageDescriptorProvider as P, RedirectionError as R, RouterContext as a, RouterLayerContext as b, RouterHookApi as c, useAlepha as d, useClient as e, useInject as f, useQueryParams as g, useRouter as h, useRouterEvents as i, useRouterState as j, isPageRoute as k, ReactBrowserProvider as l, useActive as u };