revojs 0.0.83 → 0.0.85

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,15 +438,31 @@ 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
+ if (STATES === void 0) {
445
+ const element = document.getElementById("STATES");
446
+ STATES = element?.textContent ? JSON.parse(element.textContent) : {};
447
+ }
448
+ state.value = STATES[name];
449
+ createCompute(scope, () => STATES && (STATES[name] = state.value));
450
+ }
451
+ if (isServer()) {
452
+ const { states } = useRuntime(scope);
453
+ states[name] = state;
454
+ }
455
+ return state;
456
+ }
457
+ function useAsync(scope, name, invoke, options) {
439
458
  const { tasks } = useRuntime(scope);
440
- const state = createState();
459
+ const state = useState(scope, name);
441
460
  const isLoading = createState(false);
442
461
  const execute = async () => {
443
462
  isLoading.value = true;
444
463
  try {
445
464
  const result = await invoke();
446
- if (options?.viewTransition) await startViewTransition(options.viewTransition, () => state.value = result);
465
+ if (JSON.stringify(state.value ?? {}) !== JSON.stringify(result)) if (options?.viewTransition) await startViewTransition(options.viewTransition, () => state.value = result);
447
466
  else state.value = result;
448
467
  } catch (error) {
449
468
  options?.catch?.(error);
@@ -461,7 +480,7 @@ function useAsync(scope, invoke, options) {
461
480
  };
462
481
  }
463
482
  function useFetch(scope, input, options) {
464
- return useAsync(scope, async () => await $fetch(scope, input, options), options);
483
+ return useAsync(scope, input.toString(), () => $fetch(scope, input, options), options);
465
484
  }
466
485
  async function createRuntime() {
467
486
  const radix = new Radix();
@@ -469,10 +488,25 @@ async function createRuntime() {
469
488
  const routes = await import("#virtual/routes").then((module) => module.default);
470
489
  for (const path in routes) {
471
490
  const [name, method] = toPath(path);
472
- radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (event) => {
491
+ radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (scope) => {
473
492
  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)));
493
+ if (isRoute(route)) return route.fetch(scope);
494
+ const { states } = useRuntime(scope);
495
+ const content = await renderToString(scope, await import("#virtual/client").then((module) => module.client), { head: { children: ["<!--STATES-->"] } });
496
+ const entries = Object.entries(states).reduce((states$1, [name$1, state]) => {
497
+ return {
498
+ ...states$1,
499
+ [name$1]: state.value
500
+ };
501
+ }, {});
502
+ return sendHtml(scope, content.replace("<!--STATES-->", await renderToString(scope, {
503
+ tag: "script",
504
+ attributes: {
505
+ id: "STATES",
506
+ type: "application/json"
507
+ },
508
+ children: [JSON.stringify(entries)]
509
+ })));
476
510
  } }));
477
511
  }
478
512
  const assets = await import("#virtual/assets").then((module) => module.default);
@@ -515,6 +549,7 @@ async function createRuntime() {
515
549
  }
516
550
  };
517
551
  }
552
+ let STATES;
518
553
  const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
519
554
  const ROUTE_CONTEXT = defineContext("ROUTE_CONTEXT");
520
555
 
@@ -566,7 +601,7 @@ function toString(slot) {
566
601
  }
567
602
  }
568
603
  function toArray(hydration) {
569
- if (Array.isArray(hydration)) return hydration.reduce((items, child) => items.concat(toArray(child)), new Array());
604
+ if (Array.isArray(hydration)) return hydration.reduce((items, child) => items.concat(toArray(child)), []);
570
605
  return [hydration];
571
606
  }
572
607
  function toRange(hydration) {
@@ -646,43 +681,44 @@ function hydrate(scope, parentNode, slot, index, previous) {
646
681
  if (parentNode.childNodes.item(index) === null) parentNode.appendChild(toFragment(hydration));
647
682
  return hydration;
648
683
  }
649
- async function renderToString(scope, slot) {
684
+ async function renderToString(scope, slot, defaults) {
650
685
  const { tasks } = useRuntime(scope);
651
686
  if (typeof slot === "number" || typeof slot === "bigint" || typeof slot === "boolean" || typeof slot === "string" || typeof slot === "symbol") return slot.toString();
652
687
  if (typeof slot === "function") {
653
688
  let input = slot;
654
689
  while (typeof input === "function") input = await input();
655
- return await renderToString(scope, input);
690
+ return await renderToString(scope, input, defaults);
656
691
  }
657
692
  if (Array.isArray(slot)) {
658
693
  let items = "";
659
- for (const childSlot of slot) items += await renderToString(scope, childSlot);
694
+ for (const childSlot of slot) items += await renderToString(scope, childSlot, defaults);
660
695
  if (items === "") return "<!---->";
661
696
  return items;
662
697
  }
663
698
  if (isTemplate(slot)) {
664
- const CustomElement = components.get(slot.tag);
665
- const prefix = Object.entries(slot.attributes).reduce((chunks, [name, value]) => {
699
+ const merge = mergeObjects(slot, defaults?.[slot.tag]);
700
+ const CustomElement = components.get(merge.tag);
701
+ const prefix = Object.entries(merge.attributes).reduce((chunks, [name, value]) => {
666
702
  if (value && !name.startsWith("on")) chunks.push(`${name}='${toString(value)}'`);
667
703
  return chunks;
668
- }, [slot.tag]).join(" ");
704
+ }, [merge.tag]).join(" ");
669
705
  let content = `<${prefix}>`;
670
706
  if (CustomElement) {
671
- const element = new CustomElement(slot.attributes, scope);
707
+ const element = new CustomElement(merge.attributes, scope);
672
708
  const result = element.setup();
673
709
  while (tasks.length) await tasks.shift();
674
- const template = await renderToString(element.scope, result);
710
+ const template = await renderToString(element.scope, result, defaults);
675
711
  if (element.shadowRoot) {
676
712
  const shadow = {
677
713
  tag: "template",
678
714
  attributes: { shadowRootMode: element.shadowRoot.mode },
679
715
  children: [template]
680
716
  };
681
- content += await renderToString(element.scope, shadow);
717
+ content += await renderToString(element.scope, shadow, defaults);
682
718
  } else content += template;
683
719
  }
684
- for (const childSlot of slot.children) content += await renderToString(scope, childSlot);
685
- content += `</${slot.tag}>`;
720
+ for (const childSlot of merge.children) content += await renderToString(scope, childSlot, defaults);
721
+ content += `</${merge.tag}>`;
686
722
  return content;
687
723
  }
688
724
  return "<!---->";
@@ -959,4 +995,4 @@ function useLocale(scope, context) {
959
995
  const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
960
996
 
961
997
  //#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 };
998
+ export { $fetch, AfterNavigateEvent, CLIENT, Compute, HOST_CONTEXT, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, SERVER, STATES, 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,16 +34,19 @@ 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>;
45
48
  };
46
49
  export declare function createRuntime(): Promise<Runtime>;
50
+ export declare let STATES: Record<string, unknown>;
47
51
  export declare const RUNTIME_CONTEXT: import("..").Descriptor<RuntimeContext<Record<string, unknown>>>;
48
52
  export declare const ROUTE_CONTEXT: import("..").Descriptor<RouteContext>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "revojs",
3
- "version": "0.0.83",
3
+ "version": "0.0.85",
4
4
  "type": "module",
5
5
  "repository": "coverbase/revojs",
6
6
  "license": "MIT",