@alepha/react 0.6.0 → 0.6.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.
@@ -12,7 +12,10 @@ const $auth = (options) => {
12
12
  core.__descriptor(KEY);
13
13
  return {
14
14
  [core.KIND]: KEY,
15
- options
15
+ options,
16
+ jwks: () => {
17
+ return options.oidc?.issuer ?? "";
18
+ }
16
19
  };
17
20
  };
18
21
  $auth[core.KIND] = KEY;
@@ -95,10 +98,7 @@ class Router extends core.EventEmitter {
95
98
  state,
96
99
  router: this,
97
100
  alepha: this.alepha,
98
- args: {
99
- user: context.user,
100
- cookies: context.cookies
101
- }
101
+ args: context
102
102
  }
103
103
  },
104
104
  state.layers[0]?.element
@@ -265,6 +265,7 @@ class Router extends core.EventEmitter {
265
265
  });
266
266
  if (prev === curr) {
267
267
  it.props = previous[i].props;
268
+ it.error = previous[i].error;
268
269
  context = {
269
270
  ...context,
270
271
  ...it.props
@@ -307,7 +308,7 @@ class Router extends core.EventEmitter {
307
308
  for (const key of Object.keys(params2)) {
308
309
  params2[key] = String(params2[key]);
309
310
  }
310
- if (it.route.helmet && renderContext) {
311
+ if (it.route.head && renderContext && !it.error) {
311
312
  this.mergeRenderContext(it.route, renderContext, {
312
313
  ...props,
313
314
  ...context
@@ -318,13 +319,14 @@ class Router extends core.EventEmitter {
318
319
  const path = acc.replace(/\/+/, "/");
319
320
  if (it.error) {
320
321
  const errorHandler = this.getErrorHandler(it.route);
321
- const element = errorHandler ? errorHandler({
322
+ const element = await (errorHandler ? errorHandler({
322
323
  ...it.config,
323
324
  error: it.error,
324
325
  url
325
- }) : this.renderError(it.error);
326
+ }) : this.renderError(it.error));
326
327
  layers.push({
327
328
  props,
329
+ error: it.error,
328
330
  name: it.route.name,
329
331
  part: it.route.path,
330
332
  config: it.config,
@@ -388,15 +390,32 @@ class Router extends core.EventEmitter {
388
390
  * @protected
389
391
  */
390
392
  mergeRenderContext(page, ctx, props) {
391
- if (page.helmet) {
392
- const helmet = typeof page.helmet === "function" ? page.helmet(props) : page.helmet;
393
- if (helmet.title) {
394
- ctx.helmet ??= {};
395
- if (ctx.helmet?.title) {
396
- ctx.helmet.title = `${helmet.title} - ${ctx.helmet.title}`;
393
+ if (page.head) {
394
+ ctx.head ??= {};
395
+ const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
396
+ if (head.title) {
397
+ ctx.head ??= {};
398
+ if (ctx.head.titleSeparator) {
399
+ ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
397
400
  } else {
398
- ctx.helmet.title = helmet.title;
401
+ ctx.head.title = head.title;
399
402
  }
403
+ ctx.head.titleSeparator = head.titleSeparator;
404
+ }
405
+ if (head.htmlAttributes) {
406
+ ctx.head.htmlAttributes = {
407
+ ...ctx.head.htmlAttributes,
408
+ ...head.htmlAttributes
409
+ };
410
+ }
411
+ if (head.bodyAttributes) {
412
+ ctx.head.bodyAttributes = {
413
+ ...ctx.head.bodyAttributes,
414
+ ...head.bodyAttributes
415
+ };
416
+ }
417
+ if (head.meta) {
418
+ ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
400
419
  }
401
420
  }
402
421
  }
@@ -565,10 +584,14 @@ class PageDescriptorProvider {
565
584
  }
566
585
  }
567
586
 
587
+ const envSchema = core.t.object({
588
+ REACT_ROOT_ID: core.t.string({ default: "root" })
589
+ });
568
590
  class ReactBrowserProvider {
569
591
  log = core.$logger();
570
592
  client = core.$inject(server.HttpClient);
571
593
  router = core.$inject(Router);
594
+ env = core.$inject(envSchema);
572
595
  root;
573
596
  transitioning;
574
597
  state = {
@@ -656,12 +679,49 @@ class ReactBrowserProvider {
656
679
  return await this.render({ url: result.redirect });
657
680
  }
658
681
  this.transitioning = void 0;
659
- return { url };
682
+ return { url, context: result.context };
660
683
  }
661
- renderHelmetContext(ctx) {
684
+ /**
685
+ * Render the helmet context.
686
+ *
687
+ * @param ctx
688
+ * @protected
689
+ */
690
+ renderHeadContext(ctx) {
662
691
  if (ctx.title) {
663
692
  this.document.title = ctx.title;
664
693
  }
694
+ if (ctx.bodyAttributes) {
695
+ for (const [key, value] of Object.entries(ctx.bodyAttributes)) {
696
+ if (value) {
697
+ this.document.body.setAttribute(key, value);
698
+ } else {
699
+ this.document.body.removeAttribute(key);
700
+ }
701
+ }
702
+ }
703
+ if (ctx.htmlAttributes) {
704
+ for (const [key, value] of Object.entries(ctx.htmlAttributes)) {
705
+ if (value) {
706
+ this.document.documentElement.setAttribute(key, value);
707
+ } else {
708
+ this.document.documentElement.removeAttribute(key);
709
+ }
710
+ }
711
+ }
712
+ if (ctx.meta) {
713
+ for (const [key, value] of Object.entries(ctx.meta)) {
714
+ const meta = this.document.querySelector(`meta[name="${key}"]`);
715
+ if (meta) {
716
+ meta.setAttribute("content", value.content);
717
+ } else {
718
+ const newMeta = this.document.createElement("meta");
719
+ newMeta.setAttribute("name", key);
720
+ newMeta.setAttribute("content", value.content);
721
+ this.document.head.appendChild(newMeta);
722
+ }
723
+ }
724
+ }
665
725
  }
666
726
  /**
667
727
  * Get embedded layers from the server.
@@ -682,13 +742,13 @@ class ReactBrowserProvider {
682
742
  * @protected
683
743
  */
684
744
  getRootElement() {
685
- const root = this.document.getElementById("root");
745
+ const root = this.document.getElementById(this.env.REACT_ROOT_ID);
686
746
  if (root) {
687
747
  return root;
688
748
  }
689
749
  const div = this.document.createElement("div");
690
- div.id = "root";
691
- this.document.body.appendChild(div);
750
+ div.id = this.env.REACT_ROOT_ID;
751
+ this.document.body.prepend(div);
692
752
  return div;
693
753
  }
694
754
  getUserFromCookies() {
@@ -713,7 +773,13 @@ class ReactBrowserProvider {
713
773
  handler: async () => {
714
774
  const cache = this.getHydrationState();
715
775
  const previous = cache?.layers ?? [];
716
- await this.render({ previous });
776
+ if (cache?.links) {
777
+ this.client.links = cache.links;
778
+ }
779
+ const { context } = await this.render({ previous });
780
+ if (context.head) {
781
+ this.renderHeadContext(context.head);
782
+ }
717
783
  const element = this.router.root(this.state, {
718
784
  user: cache?.user ?? this.getUserFromCookies()
719
785
  });
@@ -721,40 +787,30 @@ class ReactBrowserProvider {
721
787
  this.root = client.hydrateRoot(this.getRootElement(), element);
722
788
  this.log.info("Hydrated root element");
723
789
  } else {
724
- this.root = client.createRoot(this.getRootElement());
790
+ this.root ??= client.createRoot(this.getRootElement());
725
791
  this.root.render(element);
726
792
  this.log.info("Created root element");
727
793
  }
728
794
  window.addEventListener("popstate", () => {
729
795
  this.render();
730
796
  });
731
- this.router.on("end", ({ context }) => {
732
- if (context.helmet) {
733
- this.renderHelmetContext(context.helmet);
797
+ this.router.on("end", ({ context: context2 }) => {
798
+ if (context2.head) {
799
+ this.renderHeadContext(context2.head);
734
800
  }
735
801
  });
736
802
  }
737
803
  });
738
- /**
739
- *
740
- * @protected
741
- */
742
- stop = core.$hook({
743
- name: "stop",
744
- handler: async () => {
745
- if (this.root) {
746
- this.root.unmount();
747
- this.log.info("Unmounted root element");
748
- }
749
- }
750
- });
751
804
  }
752
805
 
753
806
  class Auth {
754
807
  alepha = core.$inject(core.Alepha);
755
808
  log = core.$logger();
756
809
  client = core.$inject(server.HttpClient);
757
- api = "/api/_oauth/login";
810
+ slugs = {
811
+ login: "/api/_oauth/login",
812
+ logout: "/api/_oauth/logout"
813
+ };
758
814
  start = core.$hook({
759
815
  name: "start",
760
816
  handler: async () => {
@@ -769,16 +825,16 @@ class Auth {
769
825
  if (this.alepha.isBrowser()) {
770
826
  const browser = this.alepha.get(ReactBrowserProvider);
771
827
  const redirect = browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href;
772
- window.location.href = `${this.api}?redirect=${redirect}`;
828
+ window.location.href = `${this.slugs.login}?redirect=${redirect}`;
773
829
  if (browser.transitioning) {
774
830
  throw new RedirectionError(browser.state.pathname);
775
831
  }
776
832
  return;
777
833
  }
778
- throw new RedirectionError(this.api);
834
+ throw new RedirectionError(this.slugs.login);
779
835
  };
780
836
  logout = () => {
781
- window.location.href = `/api/_oauth/logout?redirect=${encodeURIComponent(window.location.origin)}`;
837
+ window.location.href = `${this.slugs.logout}?redirect=${encodeURIComponent(window.location.origin)}`;
782
838
  };
783
839
  }
784
840
 
@@ -908,8 +964,18 @@ const useRouter = () => {
908
964
 
909
965
  const Link = (props) => {
910
966
  React.useContext(RouterContext);
967
+ const to = typeof props.to === "string" ? props.to : props.to.options.path;
968
+ if (!to) {
969
+ return null;
970
+ }
971
+ const can = typeof props.to === "string" ? void 0 : props.to.options.can;
972
+ if (can && !can()) {
973
+ console.log("I cannot go to", to);
974
+ return null;
975
+ }
976
+ const name = typeof props.to === "string" ? void 0 : props.to.options.name;
911
977
  const router = useRouter();
912
- return /* @__PURE__ */ jsxRuntime.jsx("a", { ...router.createAnchorProps(props.to), ...props, children: props.children });
978
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { ...router.createAnchorProps(to), ...props, children: props.children ?? name });
913
979
  };
914
980
 
915
981
  const useInject = (clazz) => {
@@ -917,7 +983,9 @@ const useInject = (clazz) => {
917
983
  if (!ctx) {
918
984
  throw new Error("useRouter must be used within a <RouterProvider>");
919
985
  }
920
- return ctx.alepha.get(clazz);
986
+ return ctx.alepha.get(clazz, {
987
+ skipRegistration: true
988
+ });
921
989
  };
922
990
 
923
991
  const useClient = () => {
@@ -1,4 +1,4 @@
1
- import { __descriptor, KIND, NotImplementedError, EventEmitter, $logger, $inject, Alepha, $hook } from '@alepha/core';
1
+ import { __descriptor, KIND, NotImplementedError, EventEmitter, $logger, $inject, Alepha, $hook, t } from '@alepha/core';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import React, { createContext, useContext, useState, useEffect, createElement, useMemo } from 'react';
4
4
  import { HttpClient } from '@alepha/server';
@@ -10,7 +10,10 @@ const $auth = (options) => {
10
10
  __descriptor(KEY);
11
11
  return {
12
12
  [KIND]: KEY,
13
- options
13
+ options,
14
+ jwks: () => {
15
+ return options.oidc?.issuer ?? "";
16
+ }
14
17
  };
15
18
  };
16
19
  $auth[KIND] = KEY;
@@ -93,10 +96,7 @@ class Router extends EventEmitter {
93
96
  state,
94
97
  router: this,
95
98
  alepha: this.alepha,
96
- args: {
97
- user: context.user,
98
- cookies: context.cookies
99
- }
99
+ args: context
100
100
  }
101
101
  },
102
102
  state.layers[0]?.element
@@ -263,6 +263,7 @@ class Router extends EventEmitter {
263
263
  });
264
264
  if (prev === curr) {
265
265
  it.props = previous[i].props;
266
+ it.error = previous[i].error;
266
267
  context = {
267
268
  ...context,
268
269
  ...it.props
@@ -305,7 +306,7 @@ class Router extends EventEmitter {
305
306
  for (const key of Object.keys(params2)) {
306
307
  params2[key] = String(params2[key]);
307
308
  }
308
- if (it.route.helmet && renderContext) {
309
+ if (it.route.head && renderContext && !it.error) {
309
310
  this.mergeRenderContext(it.route, renderContext, {
310
311
  ...props,
311
312
  ...context
@@ -316,13 +317,14 @@ class Router extends EventEmitter {
316
317
  const path = acc.replace(/\/+/, "/");
317
318
  if (it.error) {
318
319
  const errorHandler = this.getErrorHandler(it.route);
319
- const element = errorHandler ? errorHandler({
320
+ const element = await (errorHandler ? errorHandler({
320
321
  ...it.config,
321
322
  error: it.error,
322
323
  url
323
- }) : this.renderError(it.error);
324
+ }) : this.renderError(it.error));
324
325
  layers.push({
325
326
  props,
327
+ error: it.error,
326
328
  name: it.route.name,
327
329
  part: it.route.path,
328
330
  config: it.config,
@@ -386,15 +388,32 @@ class Router extends EventEmitter {
386
388
  * @protected
387
389
  */
388
390
  mergeRenderContext(page, ctx, props) {
389
- if (page.helmet) {
390
- const helmet = typeof page.helmet === "function" ? page.helmet(props) : page.helmet;
391
- if (helmet.title) {
392
- ctx.helmet ??= {};
393
- if (ctx.helmet?.title) {
394
- ctx.helmet.title = `${helmet.title} - ${ctx.helmet.title}`;
391
+ if (page.head) {
392
+ ctx.head ??= {};
393
+ const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
394
+ if (head.title) {
395
+ ctx.head ??= {};
396
+ if (ctx.head.titleSeparator) {
397
+ ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
395
398
  } else {
396
- ctx.helmet.title = helmet.title;
399
+ ctx.head.title = head.title;
397
400
  }
401
+ ctx.head.titleSeparator = head.titleSeparator;
402
+ }
403
+ if (head.htmlAttributes) {
404
+ ctx.head.htmlAttributes = {
405
+ ...ctx.head.htmlAttributes,
406
+ ...head.htmlAttributes
407
+ };
408
+ }
409
+ if (head.bodyAttributes) {
410
+ ctx.head.bodyAttributes = {
411
+ ...ctx.head.bodyAttributes,
412
+ ...head.bodyAttributes
413
+ };
414
+ }
415
+ if (head.meta) {
416
+ ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
398
417
  }
399
418
  }
400
419
  }
@@ -563,10 +582,14 @@ class PageDescriptorProvider {
563
582
  }
564
583
  }
565
584
 
585
+ const envSchema = t.object({
586
+ REACT_ROOT_ID: t.string({ default: "root" })
587
+ });
566
588
  class ReactBrowserProvider {
567
589
  log = $logger();
568
590
  client = $inject(HttpClient);
569
591
  router = $inject(Router);
592
+ env = $inject(envSchema);
570
593
  root;
571
594
  transitioning;
572
595
  state = {
@@ -654,12 +677,49 @@ class ReactBrowserProvider {
654
677
  return await this.render({ url: result.redirect });
655
678
  }
656
679
  this.transitioning = void 0;
657
- return { url };
680
+ return { url, context: result.context };
658
681
  }
659
- renderHelmetContext(ctx) {
682
+ /**
683
+ * Render the helmet context.
684
+ *
685
+ * @param ctx
686
+ * @protected
687
+ */
688
+ renderHeadContext(ctx) {
660
689
  if (ctx.title) {
661
690
  this.document.title = ctx.title;
662
691
  }
692
+ if (ctx.bodyAttributes) {
693
+ for (const [key, value] of Object.entries(ctx.bodyAttributes)) {
694
+ if (value) {
695
+ this.document.body.setAttribute(key, value);
696
+ } else {
697
+ this.document.body.removeAttribute(key);
698
+ }
699
+ }
700
+ }
701
+ if (ctx.htmlAttributes) {
702
+ for (const [key, value] of Object.entries(ctx.htmlAttributes)) {
703
+ if (value) {
704
+ this.document.documentElement.setAttribute(key, value);
705
+ } else {
706
+ this.document.documentElement.removeAttribute(key);
707
+ }
708
+ }
709
+ }
710
+ if (ctx.meta) {
711
+ for (const [key, value] of Object.entries(ctx.meta)) {
712
+ const meta = this.document.querySelector(`meta[name="${key}"]`);
713
+ if (meta) {
714
+ meta.setAttribute("content", value.content);
715
+ } else {
716
+ const newMeta = this.document.createElement("meta");
717
+ newMeta.setAttribute("name", key);
718
+ newMeta.setAttribute("content", value.content);
719
+ this.document.head.appendChild(newMeta);
720
+ }
721
+ }
722
+ }
663
723
  }
664
724
  /**
665
725
  * Get embedded layers from the server.
@@ -680,13 +740,13 @@ class ReactBrowserProvider {
680
740
  * @protected
681
741
  */
682
742
  getRootElement() {
683
- const root = this.document.getElementById("root");
743
+ const root = this.document.getElementById(this.env.REACT_ROOT_ID);
684
744
  if (root) {
685
745
  return root;
686
746
  }
687
747
  const div = this.document.createElement("div");
688
- div.id = "root";
689
- this.document.body.appendChild(div);
748
+ div.id = this.env.REACT_ROOT_ID;
749
+ this.document.body.prepend(div);
690
750
  return div;
691
751
  }
692
752
  getUserFromCookies() {
@@ -711,7 +771,13 @@ class ReactBrowserProvider {
711
771
  handler: async () => {
712
772
  const cache = this.getHydrationState();
713
773
  const previous = cache?.layers ?? [];
714
- await this.render({ previous });
774
+ if (cache?.links) {
775
+ this.client.links = cache.links;
776
+ }
777
+ const { context } = await this.render({ previous });
778
+ if (context.head) {
779
+ this.renderHeadContext(context.head);
780
+ }
715
781
  const element = this.router.root(this.state, {
716
782
  user: cache?.user ?? this.getUserFromCookies()
717
783
  });
@@ -719,40 +785,30 @@ class ReactBrowserProvider {
719
785
  this.root = hydrateRoot(this.getRootElement(), element);
720
786
  this.log.info("Hydrated root element");
721
787
  } else {
722
- this.root = createRoot(this.getRootElement());
788
+ this.root ??= createRoot(this.getRootElement());
723
789
  this.root.render(element);
724
790
  this.log.info("Created root element");
725
791
  }
726
792
  window.addEventListener("popstate", () => {
727
793
  this.render();
728
794
  });
729
- this.router.on("end", ({ context }) => {
730
- if (context.helmet) {
731
- this.renderHelmetContext(context.helmet);
795
+ this.router.on("end", ({ context: context2 }) => {
796
+ if (context2.head) {
797
+ this.renderHeadContext(context2.head);
732
798
  }
733
799
  });
734
800
  }
735
801
  });
736
- /**
737
- *
738
- * @protected
739
- */
740
- stop = $hook({
741
- name: "stop",
742
- handler: async () => {
743
- if (this.root) {
744
- this.root.unmount();
745
- this.log.info("Unmounted root element");
746
- }
747
- }
748
- });
749
802
  }
750
803
 
751
804
  class Auth {
752
805
  alepha = $inject(Alepha);
753
806
  log = $logger();
754
807
  client = $inject(HttpClient);
755
- api = "/api/_oauth/login";
808
+ slugs = {
809
+ login: "/api/_oauth/login",
810
+ logout: "/api/_oauth/logout"
811
+ };
756
812
  start = $hook({
757
813
  name: "start",
758
814
  handler: async () => {
@@ -767,16 +823,16 @@ class Auth {
767
823
  if (this.alepha.isBrowser()) {
768
824
  const browser = this.alepha.get(ReactBrowserProvider);
769
825
  const redirect = browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href;
770
- window.location.href = `${this.api}?redirect=${redirect}`;
826
+ window.location.href = `${this.slugs.login}?redirect=${redirect}`;
771
827
  if (browser.transitioning) {
772
828
  throw new RedirectionError(browser.state.pathname);
773
829
  }
774
830
  return;
775
831
  }
776
- throw new RedirectionError(this.api);
832
+ throw new RedirectionError(this.slugs.login);
777
833
  };
778
834
  logout = () => {
779
- window.location.href = `/api/_oauth/logout?redirect=${encodeURIComponent(window.location.origin)}`;
835
+ window.location.href = `${this.slugs.logout}?redirect=${encodeURIComponent(window.location.origin)}`;
780
836
  };
781
837
  }
782
838
 
@@ -906,8 +962,18 @@ const useRouter = () => {
906
962
 
907
963
  const Link = (props) => {
908
964
  React.useContext(RouterContext);
965
+ const to = typeof props.to === "string" ? props.to : props.to.options.path;
966
+ if (!to) {
967
+ return null;
968
+ }
969
+ const can = typeof props.to === "string" ? void 0 : props.to.options.can;
970
+ if (can && !can()) {
971
+ console.log("I cannot go to", to);
972
+ return null;
973
+ }
974
+ const name = typeof props.to === "string" ? void 0 : props.to.options.name;
909
975
  const router = useRouter();
910
- return /* @__PURE__ */ jsx("a", { ...router.createAnchorProps(props.to), ...props, children: props.children });
976
+ return /* @__PURE__ */ jsx("a", { ...router.createAnchorProps(to), ...props, children: props.children ?? name });
911
977
  };
912
978
 
913
979
  const useInject = (clazz) => {
@@ -915,7 +981,9 @@ const useInject = (clazz) => {
915
981
  if (!ctx) {
916
982
  throw new Error("useRouter must be used within a <RouterProvider>");
917
983
  }
918
- return ctx.alepha.get(clazz);
984
+ return ctx.alepha.get(clazz, {
985
+ skipRegistration: true
986
+ });
919
987
  };
920
988
 
921
989
  const useClient = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alepha/react",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -9,23 +9,24 @@
9
9
  "./dist/index.js": "./dist/index.browser.js"
10
10
  },
11
11
  "dependencies": {
12
- "@alepha/core": "0.6.0",
13
- "@alepha/security": "0.6.0",
14
- "@alepha/server": "0.6.0",
12
+ "@alepha/core": "0.6.2",
13
+ "@alepha/security": "0.6.2",
14
+ "@alepha/server": "0.6.2",
15
+ "cheerio": "^1.0.0",
15
16
  "openid-client": "^6.4.2",
16
17
  "path-to-regexp": "^8.2.0",
17
- "react-dom": "^18.3.1"
18
+ "react-dom": "^19.1.0"
18
19
  },
19
20
  "devDependencies": {
20
- "@types/react": "^18.3.20",
21
- "@types/react-dom": "^18.3.6",
22
- "pkgroll": "^2.12.1",
23
- "react": "^18.3.1",
24
- "vitest": "^3.1.1"
21
+ "@types/react": "^19.1.2",
22
+ "@types/react-dom": "^19.1.3",
23
+ "pkgroll": "^2.12.2",
24
+ "react": "^19.1.0",
25
+ "vitest": "^3.1.2"
25
26
  },
26
27
  "peerDependencies": {
27
- "@types/react": "^18",
28
- "react": "^18"
28
+ "@types/react": "^19",
29
+ "react": "^19"
29
30
  },
30
31
  "scripts": {
31
32
  "build": "pkgroll --clean-dist"
@@ -1,22 +0,0 @@
1
- import React from "react";
2
- import type { AnchorHTMLAttributes } from "react";
3
- import { RouterContext } from "../contexts/RouterContext";
4
- import { useRouter } from "../hooks/useRouter";
5
-
6
- export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
7
- to: string;
8
- children?: React.ReactNode;
9
- }
10
-
11
- const Link = (props: LinkProps) => {
12
- React.useContext(RouterContext);
13
-
14
- const router = useRouter();
15
- return (
16
- <a {...router.createAnchorProps(props.to)} {...props}>
17
- {props.children}
18
- </a>
19
- );
20
- };
21
-
22
- export default Link;
@@ -1,36 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import { useContext, useEffect, useState } from "react";
3
- import { RouterContext } from "../contexts/RouterContext";
4
- import { RouterLayerContext } from "../contexts/RouterLayerContext";
5
-
6
- export interface NestedViewProps {
7
- children?: ReactNode;
8
- }
9
-
10
- /**
11
- * Nested view component
12
- *
13
- * @param props
14
- * @constructor
15
- */
16
- const NestedView = (props: NestedViewProps) => {
17
- const app = useContext(RouterContext);
18
- const layer = useContext(RouterLayerContext);
19
- const index = layer?.index ?? 0;
20
-
21
- const [view, setView] = useState<ReactNode | undefined>(
22
- app?.state.layers[index]?.element,
23
- );
24
-
25
- useEffect(() => {
26
- if (app?.alepha.isBrowser()) {
27
- return app?.router.on("end", (state) => {
28
- setView(state.layers[index]?.element);
29
- });
30
- }
31
- }, [app]);
32
-
33
- return view ?? props.children ?? null;
34
- };
35
-
36
- export default NestedView;
@@ -1 +0,0 @@
1
- export const SSID = "ssid";