revojs 0.0.82 → 0.0.84

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.
@@ -5,7 +5,7 @@ export type Mergeable<T> = {
5
5
  export type Environment = typeof CLIENT | typeof SERVER;
6
6
  export type Virtual = (environment: Environment) => void | string;
7
7
  export type ClientEntry = "index.html" | (string & {});
8
- export type ServerEntry = "@revojs/bun/runtime" | "revojs/cloudflare/runtime" | (string & {});
8
+ export type ServerEntry = "@revojs/bun/runtime" | "@revojs/cloudflare/runtime" | (string & {});
9
9
  export type Module = {
10
10
  setup: (app: App) => void | Promise<void>;
11
11
  };
@@ -1,3 +1,4 @@
1
+ import { type Mergeable } from "../app";
1
2
  import { type HtmlAttributes } from "../jsx";
2
3
  import { Scope, type State, type Value } from "../signals";
3
4
  export type TypeOf<T> = {
@@ -16,6 +17,10 @@ export type Template = {
16
17
  attributes: Record<string, unknown>;
17
18
  children: Array<Slot>;
18
19
  };
20
+ export type ActiveViewTransition = {
21
+ name: string;
22
+ update: Promise<void>;
23
+ };
19
24
  export type EventInput<T extends Events> = {
20
25
  [K in keyof T]?: EventListener<Infer<T[K]["type"]> extends Event ? Infer<T[K]["type"]> : CustomEvent<Infer<T[K]["type"]>>>;
21
26
  };
@@ -76,11 +81,11 @@ export declare function isComponent<T>(value?: T): value is ComponentConstructor
76
81
  export declare function useHost(scope: Scope): HostContext;
77
82
  export declare function createElement<TEvents extends Events, TAttributes extends Attributes>(input: string | ((attributes: AttributeInput<Attributes>) => Slot) | ComponentConstructor<TEvents, TAttributes>, attributes?: AttributeInput<TAttributes>, ...children: Array<Slot>): Slot;
78
83
  export declare function toString(slot: Slot): string;
79
- export declare function toArray(hydration: Hydration): Array<Node>;
84
+ export declare function toArray(hydration: Hydration): Array<Comment | Text | Element>;
80
85
  export declare function toRange(hydration: Hydration): Range;
81
86
  export declare function toFragment(hydration: Hydration): DocumentFragment;
82
87
  export declare function hydrate(scope: Scope, parentNode: Node, slot: Slot, index: number, previous?: Hydration): Hydration;
83
- export declare function renderToString(scope: Scope, slot: Slot): Promise<string>;
88
+ export declare function renderToString(scope: Scope, slot: Slot, defaults?: Record<string, Mergeable<Template>>): Promise<string>;
84
89
  export declare function defineComponent<TEvents extends Events, TAttributes extends Attributes>(options: ComponentOptions<TEvents, TAttributes>): ComponentConstructor<TEvents, TAttributes>;
85
90
  export declare function toCustomElement<TEvents extends Events, TAttributes extends Attributes>(Component: ComponentConstructor<TEvents, TAttributes>): CustomElementConstructor<TEvents, TAttributes>;
86
91
  export declare function registerComponent<TEvents extends Events, TAttributes extends Attributes>(component: ComponentConstructor<TEvents, TAttributes>): ComponentConstructor<TEvents, TAttributes>;
@@ -89,13 +94,13 @@ export declare function useEvent<T extends keyof WindowEventMap>(scope: Scope, t
89
94
  export declare function useEvent<T extends keyof HTMLElementEventMap>(scope: Scope, target: Document | HTMLElement | undefined | null, event: T, input: EventListener<HTMLElementEventMap[T]>, options?: AddEventListenerOptions): void;
90
95
  export declare function onMounted(scope: Scope, event: EventListener<MountedEvent>): void;
91
96
  export declare function startViewTransition(name: string, invoke: ViewTransitionUpdateCallback): Promise<void>;
92
- export declare function onViewTransition<T>(name: string, value: T): () => T | undefined;
97
+ export declare function onViewTransition<T>(name: string, value: T | ((name: string) => T)): () => T | undefined;
93
98
  export declare function isClient(): boolean;
94
99
  export declare function isServer(): boolean;
95
100
  export declare function preventDefault(event: Event): void;
96
101
  export declare function stopPropagation(event: Event): void;
97
102
  export declare function stopImmediatePropagation(event: Event): void;
98
- export declare const activeViewTransition: State<string | undefined>;
103
+ export declare const activeViewTransition: State<ActiveViewTransition | undefined>;
99
104
  export declare const components: Map<string, ComponentConstructor<Events, Attributes>>;
100
105
  export declare const HOST_CONTEXT: import("..").Descriptor<HostContext>;
101
106
  declare global {
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  //#region src/app/index.ts
2
2
  function mergeObjects(base, input) {
3
+ if (input === null || input === void 0) return mergeObjects(base, {});
3
4
  const object = structuredClone(input);
4
5
  for (const key in base) {
5
6
  if (key === "__proto__" || key === "constructor") continue;
6
7
  const value = base[key];
7
8
  if (value === null || value === void 0) continue;
8
- if (typeof value === "object" && typeof object[key] === "object") object[key] = mergeObjects(value, object[key]);
9
+ if (Array.isArray(value) && Array.isArray(object[key])) object[key] = [...value, ...object[key]];
10
+ else if (typeof value === "object" && typeof object[key] === "object") object[key] = mergeObjects(value, object[key]);
9
11
  else object[key] = value;
10
12
  }
11
13
  return object;
@@ -240,7 +242,7 @@ var Radix = class Radix {
240
242
  this.input = input;
241
243
  this.children = {};
242
244
  }
243
- insert = (path, value) => {
245
+ insert(path, value) {
244
246
  let node = this;
245
247
  for (let segment of path.split("/")) {
246
248
  let input;
@@ -257,8 +259,8 @@ var Radix = class Radix {
257
259
  }
258
260
  node.value = value;
259
261
  return this;
260
- };
261
- match = (path) => {
262
+ }
263
+ match(path) {
262
264
  let node = this;
263
265
  const match = { inputs: {} };
264
266
  for (const segment of path.split("/")) {
@@ -267,7 +269,7 @@ var Radix = class Radix {
267
269
  }
268
270
  match.value = node?.value;
269
271
  return match;
270
- };
272
+ }
271
273
  };
272
274
 
273
275
  //#endregion
@@ -419,7 +421,8 @@ async function $fetch(scope, input, options) {
419
421
  const next = new Scope();
420
422
  const url = new URL(input.toString(), request.url);
421
423
  next.setContext(RUNTIME_CONTEXT, {
422
- tasks: new Array(),
424
+ tasks: [],
425
+ states: {},
423
426
  request: new Request(url, options),
424
427
  response: { headers: new Headers() },
425
428
  variables
@@ -435,9 +438,21 @@ async function $fetch(scope, input, options) {
435
438
  default: return response;
436
439
  }
437
440
  }
438
- function useAsync(scope, invoke, options) {
441
+ function useState(scope, name, value) {
442
+ const state = createState(value);
443
+ if (isClient()) {
444
+ const element = document.querySelector(`#data-${name}`);
445
+ if (element?.textContent) state.value = JSON.parse(element.textContent);
446
+ }
447
+ if (isServer()) {
448
+ const { states } = useRuntime(scope);
449
+ states[name] = state;
450
+ }
451
+ return state;
452
+ }
453
+ function useAsync(scope, name, invoke, options) {
439
454
  const { tasks } = useRuntime(scope);
440
- const state = createState();
455
+ const state = useState(scope, name);
441
456
  const isLoading = createState(false);
442
457
  const execute = async () => {
443
458
  isLoading.value = true;
@@ -461,7 +476,7 @@ function useAsync(scope, invoke, options) {
461
476
  };
462
477
  }
463
478
  function useFetch(scope, input, options) {
464
- return useAsync(scope, async () => await $fetch(scope, input, options), options);
479
+ return useAsync(scope, input.toString(), () => $fetch(scope, input, options), options);
465
480
  }
466
481
  async function createRuntime() {
467
482
  const radix = new Radix();
@@ -469,10 +484,12 @@ async function createRuntime() {
469
484
  const routes = await import("#virtual/routes").then((module) => module.default);
470
485
  for (const path in routes) {
471
486
  const [name, method] = toPath(path);
472
- radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (event) => {
487
+ radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (scope) => {
473
488
  const route = routes[path];
474
- if (isRoute(route)) return route.fetch(event);
475
- return sendHtml(event, await renderToString(event, await import("#virtual/client").then((module) => module.client)));
489
+ if (isRoute(route)) return route.fetch(scope);
490
+ const { states } = useRuntime(scope);
491
+ const content = await renderToString(scope, await import("#virtual/client").then((module) => module.client), { head: { children: ["<!--DATA-->"] } });
492
+ return sendHtml(scope, content.replace("<!--DATA-->", Object.entries(states).reduce((data, [name$1, state]) => `${data} <script id="data-${name$1}" type="application/json"> ${JSON.stringify(state.value)} <\/script>`, "")));
476
493
  } }));
477
494
  }
478
495
  const assets = await import("#virtual/assets").then((module) => module.default);
@@ -566,7 +583,7 @@ function toString(slot) {
566
583
  }
567
584
  }
568
585
  function toArray(hydration) {
569
- if (Array.isArray(hydration)) return hydration.reduce((items, child) => items.concat(toArray(child)), new Array());
586
+ if (Array.isArray(hydration)) return hydration.reduce((items, child) => items.concat(toArray(child)), []);
570
587
  return [hydration];
571
588
  }
572
589
  function toRange(hydration) {
@@ -646,43 +663,44 @@ function hydrate(scope, parentNode, slot, index, previous) {
646
663
  if (parentNode.childNodes.item(index) === null) parentNode.appendChild(toFragment(hydration));
647
664
  return hydration;
648
665
  }
649
- async function renderToString(scope, slot) {
666
+ async function renderToString(scope, slot, defaults) {
650
667
  const { tasks } = useRuntime(scope);
651
668
  if (typeof slot === "number" || typeof slot === "bigint" || typeof slot === "boolean" || typeof slot === "string" || typeof slot === "symbol") return slot.toString();
652
669
  if (typeof slot === "function") {
653
670
  let input = slot;
654
671
  while (typeof input === "function") input = await input();
655
- return await renderToString(scope, input);
672
+ return await renderToString(scope, input, defaults);
656
673
  }
657
674
  if (Array.isArray(slot)) {
658
675
  let items = "";
659
- for (const childSlot of slot) items += await renderToString(scope, childSlot);
676
+ for (const childSlot of slot) items += await renderToString(scope, childSlot, defaults);
660
677
  if (items === "") return "<!---->";
661
678
  return items;
662
679
  }
663
680
  if (isTemplate(slot)) {
664
- const CustomElement = components.get(slot.tag);
665
- const prefix = Object.entries(slot.attributes).reduce((chunks, [name, value]) => {
681
+ const merge = mergeObjects(slot, defaults?.[slot.tag]);
682
+ const CustomElement = components.get(merge.tag);
683
+ const prefix = Object.entries(merge.attributes).reduce((chunks, [name, value]) => {
666
684
  if (value && !name.startsWith("on")) chunks.push(`${name}='${toString(value)}'`);
667
685
  return chunks;
668
- }, [slot.tag]).join(" ");
686
+ }, [merge.tag]).join(" ");
669
687
  let content = `<${prefix}>`;
670
688
  if (CustomElement) {
671
- const element = new CustomElement(slot.attributes, scope);
689
+ const element = new CustomElement(merge.attributes, scope);
672
690
  const result = element.setup();
673
691
  while (tasks.length) await tasks.shift();
674
- const template = await renderToString(element.scope, result);
692
+ const template = await renderToString(element.scope, result, defaults);
675
693
  if (element.shadowRoot) {
676
694
  const shadow = {
677
695
  tag: "template",
678
696
  attributes: { shadowRootMode: element.shadowRoot.mode },
679
697
  children: [template]
680
698
  };
681
- content += await renderToString(element.scope, shadow);
699
+ content += await renderToString(element.scope, shadow, defaults);
682
700
  } else content += template;
683
701
  }
684
- for (const childSlot of slot.children) content += await renderToString(scope, childSlot);
685
- content += `</${slot.tag}>`;
702
+ for (const childSlot of merge.children) content += await renderToString(scope, childSlot, defaults);
703
+ content += `</${merge.tag}>`;
686
704
  return content;
687
705
  }
688
706
  return "<!---->";
@@ -802,14 +820,19 @@ function onMounted(scope, event) {
802
820
  }
803
821
  async function startViewTransition(name, invoke) {
804
822
  if (isClient() && document.startViewTransition !== void 0) {
805
- activeViewTransition.value = name;
806
- return document.startViewTransition(invoke).finished.finally(() => activeViewTransition.value = void 0);
823
+ await activeViewTransition.value?.update;
824
+ const update = document.startViewTransition(invoke).finished.finally(() => activeViewTransition.value = void 0);
825
+ activeViewTransition.value = {
826
+ name,
827
+ update
828
+ };
829
+ return update;
807
830
  }
808
831
  return invoke();
809
832
  }
810
833
  function onViewTransition(name, value) {
811
834
  return () => {
812
- if (activeViewTransition.value === name && isClient()) return value;
835
+ if (activeViewTransition.value?.name === name && isClient()) return value instanceof Function ? value(name) : value;
813
836
  };
814
837
  }
815
838
  function isClient() {
@@ -954,4 +977,4 @@ function useLocale(scope, context) {
954
977
  const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
955
978
 
956
979
  //#endregion
957
- export { $fetch, AfterNavigateEvent, CLIENT, Compute, HOST_CONTEXT, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, SERVER, Scope, StopEvent, activeCompute, activeViewTransition, components, createApp, createCompute, createElement, createMemo, createRuntime, createState, defineComponent, defineContext, defineMiddleware, defineRoute, fileName, fromValue, hydrate, isClient, isComponent, isCustomElement, isRoute, isServer, isTemplate, mergeObjects, mimeType, onMounted, onViewTransition, preventDefault, provideLocaleContext, provideRouterContext, registerComponent, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, startViewTransition, stopImmediatePropagation, stopPropagation, targets, toArray, toCustomElement, toFragment, toPath, toRange, toString, untrack, useAsync, useCookies, useEvent, useFetch, useHost, useLocale, useQuery, useRoute, useRouter, useRuntime, useSetCookies, useUrl };
980
+ export { $fetch, AfterNavigateEvent, CLIENT, Compute, HOST_CONTEXT, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, SERVER, Scope, StopEvent, activeCompute, activeViewTransition, components, createApp, createCompute, createElement, createMemo, createRuntime, createState, defineComponent, defineContext, defineMiddleware, defineRoute, fileName, fromValue, hydrate, isClient, isComponent, isCustomElement, isRoute, isServer, isTemplate, mergeObjects, mimeType, onMounted, onViewTransition, preventDefault, provideLocaleContext, provideRouterContext, registerComponent, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, startViewTransition, stopImmediatePropagation, stopPropagation, targets, toArray, toCustomElement, toFragment, toPath, toRange, toString, untrack, useAsync, useCookies, useEvent, useFetch, useHost, useLocale, useQuery, useRoute, useRouter, useRuntime, useSetCookies, useState, useUrl };
@@ -7,6 +7,6 @@ export declare class Radix<T> {
7
7
  input?: string;
8
8
  children: Record<string, Radix<T>>;
9
9
  constructor(input?: string);
10
- insert: (path: string, value: T) => this;
11
- match: (path: string) => Match<T>;
10
+ insert(path: string, value: T): this;
11
+ match(path: string): Match<T>;
12
12
  }
@@ -14,6 +14,7 @@ export type Runtime = {
14
14
  };
15
15
  export type RuntimeContext<T = Record<string, unknown>> = {
16
16
  tasks: Array<Promise<unknown>>;
17
+ states: Record<string, State<unknown>>;
17
18
  request: Request;
18
19
  response: ResponseOptions;
19
20
  variables: T;
@@ -21,9 +22,9 @@ export type RuntimeContext<T = Record<string, unknown>> = {
21
22
  export type RouteContext = {
22
23
  inputs: State<Record<string, string>>;
23
24
  };
24
- export type AsyncOptions = {
25
+ export type AsyncOptions<T> = {
25
26
  viewTransition?: string;
26
- catch?: (error: unknown) => void | Promise<void>;
27
+ catch?: (error: T) => void | Promise<void>;
27
28
  };
28
29
  export declare function isRoute<T>(value?: T): value is Route & T;
29
30
  export declare function useRuntime<T = Record<string, unknown>>(scope: Scope): RuntimeContext<T>;
@@ -33,12 +34,14 @@ export declare function defineMiddleware(middleware: Middleware): Middleware;
33
34
  export declare function fileName(path: string): string | undefined;
34
35
  export declare function toPath(value: string): (string | undefined)[];
35
36
  export declare function $fetch<T>(scope: Scope, input: string | URL, options?: RequestInit): Promise<T>;
36
- export declare function useAsync<T>(scope: Scope, invoke: () => Promise<T>, options?: AsyncOptions): {
37
+ export declare function useState<T>(scope: Scope, name: string): State<T | undefined>;
38
+ export declare function useState<T>(scope: Scope, name: string, value: T): State<T>;
39
+ export declare function useAsync<T, TError = Error>(scope: Scope, name: string, invoke: () => Promise<T>, options?: AsyncOptions<TError>): {
37
40
  state: State<T | undefined>;
38
41
  isLoading: State<boolean>;
39
42
  execute: () => Promise<T | undefined>;
40
43
  };
41
- export declare function useFetch<T>(scope: Scope, input: string | URL, options?: RequestInit & AsyncOptions): {
44
+ export declare function useFetch<T, TError = Error>(scope: Scope, input: string | URL, options?: RequestInit & AsyncOptions<TError>): {
42
45
  state: State<T | undefined>;
43
46
  isLoading: State<boolean>;
44
47
  execute: () => Promise<T | undefined>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "revojs",
3
- "version": "0.0.82",
3
+ "version": "0.0.84",
4
4
  "type": "module",
5
5
  "repository": "coverbase/revojs",
6
6
  "license": "MIT",