revojs 0.0.83 → 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.
@@ -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> = {
@@ -80,11 +81,11 @@ export declare function isComponent<T>(value?: T): value is ComponentConstructor
80
81
  export declare function useHost(scope: Scope): HostContext;
81
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;
82
83
  export declare function toString(slot: Slot): string;
83
- export declare function toArray(hydration: Hydration): Array<Node>;
84
+ export declare function toArray(hydration: Hydration): Array<Comment | Text | Element>;
84
85
  export declare function toRange(hydration: Hydration): Range;
85
86
  export declare function toFragment(hydration: Hydration): DocumentFragment;
86
87
  export declare function hydrate(scope: Scope, parentNode: Node, slot: Slot, index: number, previous?: Hydration): Hydration;
87
- 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>;
88
89
  export declare function defineComponent<TEvents extends Events, TAttributes extends Attributes>(options: ComponentOptions<TEvents, TAttributes>): ComponentConstructor<TEvents, TAttributes>;
89
90
  export declare function toCustomElement<TEvents extends Events, TAttributes extends Attributes>(Component: ComponentConstructor<TEvents, TAttributes>): CustomElementConstructor<TEvents, TAttributes>;
90
91
  export declare function registerComponent<TEvents extends Events, TAttributes extends Attributes>(component: ComponentConstructor<TEvents, TAttributes>): ComponentConstructor<TEvents, TAttributes>;
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 "<!---->";
@@ -959,4 +977,4 @@ function useLocale(scope, context) {
959
977
  const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
960
978
 
961
979
  //#endregion
962
- 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.83",
3
+ "version": "0.0.84",
4
4
  "type": "module",
5
5
  "repository": "coverbase/revojs",
6
6
  "license": "MIT",