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