revojs 0.0.28 → 0.0.30

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/dist/index.js CHANGED
@@ -252,14 +252,15 @@ const renderToString = async (scope, slot) => {
252
252
  if (typeof slot === "object") {
253
253
  if (Array.isArray(slot)) return await Promise.all(slot.map((slot$1) => renderToString(scope, slot$1))).then((chunks) => chunks.join(""));
254
254
  if (isTemplate(slot)) {
255
- const customElement = components.get(slot.tag);
255
+ const CustomElement = components.get(slot.tag);
256
256
  const prefix = Object.entries(slot.attributes).reduce((chunks, [name, value]) => {
257
257
  if (!name.startsWith("on")) chunks.push(`${name}='${toString(value)}'`);
258
258
  return chunks;
259
259
  }, [slot.tag]).join(" ");
260
260
  const children = await renderToString(scope, slot.children);
261
- if (customElement) {
262
- const element = new customElement(slot.attributes, scope);
261
+ if (CustomElement) {
262
+ const element = new CustomElement(slot.attributes, scope);
263
+ scope.onStop(() => element.scope.stop());
263
264
  const template = await renderToString(element.scope, await element.setup());
264
265
  if (element.shadowRoot) {
265
266
  const shadow = await renderToString(element.scope, {
@@ -556,7 +557,7 @@ var Radix = class Radix {
556
557
  children;
557
558
  constructor(input) {
558
559
  this.input = input;
559
- this.children = new Map();
560
+ this.children = {};
560
561
  }
561
562
  insert = (path, value) => {
562
563
  let node = this;
@@ -566,10 +567,10 @@ var Radix = class Radix {
566
567
  input = segment.substring(1);
567
568
  segment = ":";
568
569
  }
569
- let childNode = node.children.get(segment);
570
+ let childNode = node.children[segment];
570
571
  if (childNode === void 0) {
571
572
  childNode = new Radix(input);
572
- node.children.set(segment, childNode);
573
+ node.children[segment] = childNode;
573
574
  }
574
575
  node = childNode;
575
576
  }
@@ -580,7 +581,7 @@ var Radix = class Radix {
580
581
  let node = this;
581
582
  const match = { inputs: {} };
582
583
  for (const segment of path.split("/")) {
583
- node = node?.children.get(segment) ?? node?.children.get(":");
584
+ node = node?.children[segment] ?? node?.children[":"];
584
585
  if (node?.input) match.inputs[node.input] = segment;
585
586
  }
586
587
  match.value = node?.value;
@@ -597,7 +598,7 @@ const fileName = (path) => {
597
598
  return path.split("/").pop()?.split(".").slice(0, -1).join(".");
598
599
  };
599
600
  const toPath = (value) => {
600
- const path = (value.startsWith("/") ? value : "/" + value).replaceAll(/\/index/g, "").replaceAll(/\[(.*)\]/g, (_, name) => ":" + name);
601
+ const path = (value.startsWith("/") ? value : "/" + value).replaceAll(/\/index/g, "").replaceAll(/\[(.*?)\]/g, (_, name) => ":" + name);
601
602
  const route = path.startsWith("/") ? path : "/" + path;
602
603
  const split = route.split(".");
603
604
  return split.length === 3 ? [split.at(0), split.at(1)] : [split.at(0)];
@@ -629,8 +630,12 @@ const createRuntime = async () => {
629
630
  if (typeof route === "object") return route.fetch(event);
630
631
  if (route) {
631
632
  const scope = new Scope();
632
- scope.setContext(RUNTIME_CONTEXT, { event });
633
- return sendHtml(event, await renderToString(scope, await import("#virtual/client").then((module) => module.index)));
633
+ try {
634
+ scope.setContext(RUNTIME_CONTEXT, { event });
635
+ return sendHtml(event, await renderToString(scope, await import("#virtual/client").then((module) => module.index)));
636
+ } finally {
637
+ scope.stop();
638
+ }
634
639
  }
635
640
  } }));
636
641
  }
@@ -658,9 +663,9 @@ const createRuntime = async () => {
658
663
  if (response) return response;
659
664
  }
660
665
  return sendText(event, "Not found");
661
- } catch (response) {
662
- if (response instanceof Response) return response;
663
- throw response;
666
+ } catch (exception) {
667
+ if (exception instanceof Response) return exception;
668
+ throw exception;
664
669
  }
665
670
  }
666
671
  };
@@ -669,73 +674,128 @@ const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
669
674
 
670
675
  //#endregion
671
676
  //#region src/router/index.tsx
672
- const ROUTE_CONTEXT = defineContext("ROUTE_CONTEXT");
673
- const navigate = (url) => {
674
- if (isClient()) {
675
- const state = window.history.state;
676
- window.history.pushState(state, "", url);
677
- window.dispatchEvent(new PopStateEvent("popstate", { state }));
677
+ var NavigateEvent = class extends Event {
678
+ constructor() {
679
+ super("navigate");
678
680
  }
679
681
  };
680
- const anchorNavigate = (event) => {
681
- event.preventDefault();
682
- navigate(event.currentTarget?.getAttribute("href") ?? "/");
683
- };
684
- const Outlet = defineComponent({
685
- name: "x-outlet",
686
- shadowRoot: false,
687
- setup: async ({ scope }) => {
688
- const { event } = scope.getContext(RUNTIME_CONTEXT);
689
- const radix = new Radix();
690
- const routes = await getRoutes();
691
- for (const path in routes) {
692
- const [name] = toPath(path);
693
- if (name) radix.insert(name, routes[path]);
682
+ const ROUTER_CONTEXT = defineContext("ROUTER_CONTEXT");
683
+ const createRouter = async (input) => {
684
+ const routes = await import("#virtual/routes").then((module) => module.index);
685
+ const navigator = new EventTarget();
686
+ const radix = new Radix();
687
+ const route = createState();
688
+ const inputs = createState();
689
+ const options = defu(input, { routes });
690
+ for (const path in options.routes) {
691
+ const [name] = toPath(path);
692
+ if (name) {
693
+ const value = options.routes[path];
694
+ if (value) radix.insert(name, value);
694
695
  }
695
- const url = createState(new URL(event ? event.request.url : window.location.href));
696
- if (isClient()) useEvent(scope, window, "popstate", () => url.value = new URL(window.location.href));
697
- return async () => {
698
- const { value, inputs } = radix.match(url.value.pathname);
699
- const Page = await value?.();
700
- if (Page) {
701
- scope.setContext(ROUTE_CONTEXT, { inputs });
702
- return /* @__PURE__ */ h(Page, inputs);
703
- }
696
+ }
697
+ const registerRouterContext = async (scope) => {
698
+ const { event } = scope.getContext(RUNTIME_CONTEXT);
699
+ const fetch$1 = async () => {
700
+ const url = new URL(event ? event.request.url : window.location.href);
701
+ const match = radix.match(url.pathname);
702
+ inputs.value = match.inputs;
703
+ const Page$1 = await match.value?.();
704
+ if (Page$1) route.value = /* @__PURE__ */ h(Page$1, inputs.value);
704
705
  };
706
+ if (isClient()) useEvent(scope, window, "popstate", () => navigator.dispatchEvent(new NavigateEvent()));
707
+ if (event) inputs.value = event.context.inputs;
708
+ await fetch$1().then(() => useEvent(scope, navigator, "navigate", fetch$1));
709
+ scope.setContext(ROUTER_CONTEXT, {
710
+ options,
711
+ navigator,
712
+ radix,
713
+ route,
714
+ inputs
715
+ });
716
+ return useRouter(scope);
717
+ };
718
+ return {
719
+ ROUTER_CONTEXT,
720
+ registerRouterContext
721
+ };
722
+ };
723
+ const useRouter = (scope, context) => {
724
+ const { route, inputs, navigator } = scope.getContext(context ?? ROUTER_CONTEXT);
725
+ const navigate = (path) => {
726
+ if (isClient()) window.history.pushState(window.history.state, "", path);
727
+ navigator.dispatchEvent(new NavigateEvent());
728
+ };
729
+ const anchorNavigate = (event) => {
730
+ event.preventDefault();
731
+ navigate(event.currentTarget?.getAttribute("href") ?? "/");
732
+ };
733
+ return {
734
+ route,
735
+ inputs,
736
+ navigator,
737
+ navigate,
738
+ anchorNavigate
739
+ };
740
+ };
741
+ const Page = defineComponent({
742
+ name: "x-page",
743
+ shadowRoot: false,
744
+ setup: ({ scope }) => {
745
+ const { route } = scope.getContext(ROUTER_CONTEXT);
746
+ if (route === void 0) return;
747
+ return () => route.value;
705
748
  }
706
749
  });
707
750
 
708
751
  //#endregion
709
752
  //#region src/locale/index.ts
710
- const createLocaleContext = (options) => {
711
- const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
712
- const registerLocaleContext = (scope) => {
713
- scope.setContext(LOCALE_CONTEXT, options);
753
+ const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
754
+ const createLocale = async (input) => {
755
+ const locales = await import("#virtual/locales").then((module) => module.index);
756
+ const locale = createState();
757
+ const messages = createState();
758
+ const options = defu(input, { locales });
759
+ const registerLocaleContext = async (scope) => {
760
+ const { inputs, navigator, navigate } = useRouter(scope);
761
+ const fetch$1 = async () => {
762
+ if (options.input) {
763
+ locale.value = inputs.value?.[options.input];
764
+ if (locale.value !== void 0 && !(locale.value in locales)) navigate("/" + (options.defaultLocale ?? ""));
765
+ }
766
+ locale.value ??= options.defaultLocale;
767
+ if (locale.value) {
768
+ const target = locales[locale.value];
769
+ messages.value = typeof target === "function" ? await target() : target;
770
+ }
771
+ };
772
+ await fetch$1().then(() => useEvent(scope, navigator, "navigate", fetch$1));
773
+ scope.setContext(LOCALE_CONTEXT, {
774
+ locale,
775
+ messages,
776
+ options
777
+ });
778
+ return useLocale(scope);
714
779
  };
715
780
  return {
716
781
  LOCALE_CONTEXT,
717
782
  registerLocaleContext
718
783
  };
719
784
  };
720
- const useLocaleContext = async (scope, context) => {
721
- const { event } = scope.getContext(RUNTIME_CONTEXT);
722
- const { inputs } = scope.getContext(ROUTE_CONTEXT);
723
- const { locales, defaultLocale, cookie, input } = scope.getContext(context);
724
- const entries = await import("#virtual/locales").then((module) => module.index);
725
- let locale = defaultLocale;
726
- let set;
727
- if (cookie) {
728
- if (event) set = getCookies(event)[cookie];
729
- }
730
- if (input) if (event) set = event.context.variables[input];
731
- else set = inputs[input];
732
- if (set) locale = set;
733
- if (locale) locales[locale] = await entries[locale]?.() ?? {};
785
+ const useLocale = (scope, context) => {
786
+ const { locale, messages } = scope.getContext(context ?? LOCALE_CONTEXT);
734
787
  const $ = (key) => {
735
- if (locale) return locales[locale]?.[key] ?? key;
736
- return key;
788
+ return () => messages.value?.[key] ?? key;
789
+ };
790
+ const prefix = (input) => {
791
+ return () => `/${locale.value}` + (input ?? "");
792
+ };
793
+ return {
794
+ locale,
795
+ messages,
796
+ prefix,
797
+ $
737
798
  };
738
- return { $ };
739
799
  };
740
800
 
741
801
  //#endregion
@@ -832,4 +892,4 @@ const markdownToSlot = (input, options) => {
832
892
  };
833
893
 
834
894
  //#endregion
835
- export { $fetch, Compute, Handler, MountedEvent, Outlet, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, Scope, StopEvent, activeCompute, anchorNavigate, components, createApp, createCompute, createElement, createEvent, createLocaleContext, createMemo, createRuntime, createState, defineComponent, defineContext, defineRoute, fileName, fromValue, getAssets, getCookies, getCustomElement, getGlobalStyles, getMimeType, getRequestUrl, getRoutes, getSetCookies, getVariables, isClient, isServer, isTemplate, markdownToSlot, navigate, preventDefault, registerComponent, renderToNode, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, stopImmediatePropagation, stopPropagation, targets, toCustomElement, toFragment, toPath, toString, useEvent, useLocaleContext };
895
+ export { $fetch, Compute, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, RUNTIME_CONTEXT, Radix, Scope, StopEvent, activeCompute, components, createApp, createCompute, createElement, createEvent, createLocale, createMemo, createRouter, createRuntime, createState, defineComponent, defineContext, defineRoute, fileName, fromValue, getAssets, getCookies, getCustomElement, getGlobalStyles, getMimeType, getRequestUrl, getRoutes, getSetCookies, getVariables, isClient, isServer, isTemplate, markdownToSlot, preventDefault, registerComponent, renderToNode, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, stopImmediatePropagation, stopPropagation, targets, toCustomElement, toFragment, toPath, toString, useEvent, useLocale, useRouter };
@@ -1,15 +1,28 @@
1
- import { type Descriptor, Scope } from "../signals";
2
- export type Locales = Record<string, Record<string, string>>;
3
- export type LocaleOptions<T extends Locales> = {
1
+ import { type Descriptor, Scope, type State } from "../signals";
2
+ export type Locales = Record<string, Record<string, string> | (() => Promise<Record<string, string>>)>;
3
+ export type LocaleOptions<T extends Locales = Locales> = {
4
4
  locales: T;
5
5
  defaultLocale?: keyof T;
6
- cookie?: string;
7
6
  input?: string;
8
7
  };
9
- export declare const createLocaleContext: <T extends LocaleOptions<Locales>>(options: T) => {
10
- LOCALE_CONTEXT: Descriptor<T>;
11
- registerLocaleContext: (scope: Scope) => void;
8
+ export type LocaleContext<T extends LocaleOptions = LocaleOptions> = {
9
+ locale: State<string>;
10
+ messages: State<Record<string, string>>;
11
+ options: T;
12
12
  };
13
- export declare const useLocaleContext: <T extends LocaleOptions<Locales>>(scope: Scope, context: Descriptor<T>) => Promise<{
14
- $: (key: keyof T["locales"][keyof T["locales"]]) => string | number | symbol | keyof T["locales"][keyof T["locales"]];
13
+ export declare const LOCALE_CONTEXT: Descriptor<LocaleContext<LocaleOptions<Locales>>>;
14
+ export declare const createLocale: <T extends LocaleOptions>(input?: Partial<T>) => Promise<{
15
+ LOCALE_CONTEXT: Descriptor<LocaleContext<T>>;
16
+ registerLocaleContext: (scope: Scope) => Promise<{
17
+ locale: State<string>;
18
+ messages: State<Record<string, string>>;
19
+ prefix: (input?: string) => () => string;
20
+ $: (key: never) => () => string | number | symbol;
21
+ }>;
15
22
  }>;
23
+ export declare const useLocale: <T extends LocaleContext>(scope: Scope, context?: Descriptor<T>) => {
24
+ locale: State<string>;
25
+ messages: State<Record<string, string>>;
26
+ prefix: (input?: string) => () => string;
27
+ $: (key: keyof T["options"]["locales"][keyof T["options"]["locales"]]) => () => string | number | symbol;
28
+ };
@@ -5,7 +5,7 @@ export type Match<T> = {
5
5
  export declare class Radix<T> {
6
6
  value?: T;
7
7
  input?: string;
8
- children: Map<string, Radix<T>>;
8
+ children: Record<string, Radix<T>>;
9
9
  constructor(input?: string);
10
10
  insert: (path: string, value: T) => this;
11
11
  match: (path: string) => Match<T>;
@@ -1,7 +1,41 @@
1
- import { type ComponentConstructor } from "../html";
2
- export declare const ROUTE_CONTEXT: import("..").Descriptor<{
3
- inputs: Record<string, string>;
1
+ import { type Attributes, type ComponentConstructor, type Events, type Slot } from "../html";
2
+ import { Radix } from "../radix";
3
+ import { type Descriptor, Scope, type State } from "../signals";
4
+ export type Routes = Record<string, () => Promise<ComponentConstructor<Events, Attributes>>>;
5
+ export type RouterOptions<T extends Routes = Routes> = {
6
+ routes: T;
7
+ };
8
+ export type RouterContext<T extends RouterOptions = RouterOptions> = {
9
+ options: T;
10
+ navigator: EventTarget;
11
+ radix: Radix<() => Promise<ComponentConstructor<Events, Attributes>>>;
12
+ route: State<Slot | undefined>;
13
+ inputs: State<Record<string, string> | undefined>;
14
+ };
15
+ export declare class NavigateEvent extends Event {
16
+ constructor();
17
+ }
18
+ export declare const ROUTER_CONTEXT: Descriptor<RouterContext<RouterOptions<Routes>>>;
19
+ export declare const createRouter: <T extends RouterOptions>(input?: Partial<T>) => Promise<{
20
+ ROUTER_CONTEXT: Descriptor<RouterContext<T>>;
21
+ registerRouterContext: (scope: Scope) => Promise<{
22
+ route: State<unknown>;
23
+ inputs: State<Record<string, string> | undefined>;
24
+ navigator: EventTarget;
25
+ navigate: (path: string) => void;
26
+ anchorNavigate: (event: Event) => void;
27
+ }>;
4
28
  }>;
5
- export declare const navigate: (url: string) => void;
6
- export declare const anchorNavigate: (event: Event) => void;
7
- export declare const Outlet: ComponentConstructor<{}, {}>;
29
+ export declare const useRouter: <T extends RouterContext>(scope: Scope, context?: Descriptor<T>) => {
30
+ route: State<unknown>;
31
+ inputs: State<Record<string, string> | undefined>;
32
+ navigator: EventTarget;
33
+ navigate: (path: string) => void;
34
+ anchorNavigate: (event: Event) => void;
35
+ };
36
+ export declare const Page: ComponentConstructor<{}, {}>;
37
+ declare global {
38
+ interface ElementEventMap {
39
+ navigate: NavigateEvent;
40
+ }
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "revojs",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "type": "module",
5
5
  "repository": "coverbase/revojs",
6
6
  "license": "MIT",