revojs 0.0.36 → 0.0.38

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.
@@ -7,6 +7,10 @@ export type Infer<T> = T extends TypeOf<infer U> ? U : unknown;
7
7
  export type Slot = unknown | Template | Array<Slot> | (() => Slot);
8
8
  export type Hydration = Comment | Text | Element | Array<Hydration>;
9
9
  export type EventListener<T extends Event> = ((event: T) => void) | Array<(event: T) => void>;
10
+ export type HostContext = {
11
+ host?: CustomElement<Events, Attributes>;
12
+ internals?: ElementInternals;
13
+ };
10
14
  export type Template = {
11
15
  tag: string;
12
16
  attributes: Record<string, unknown>;
@@ -53,7 +57,6 @@ export interface Component<TEvents extends Events, TAttributes extends Attribute
53
57
  readonly events: EventOutput<TEvents>;
54
58
  readonly attributes: State<AttributeOutput<TAttributes>>;
55
59
  readonly shadowRoot: false | ShadowRootOptions;
56
- readonly host?: CustomElement<TEvents, TAttributes>;
57
60
  setup: () => Slot | Promise<Slot>;
58
61
  }
59
62
  export interface ComponentConstructor<TEvents extends Events, TAttributes extends Attributes> {
@@ -61,10 +64,9 @@ export interface ComponentConstructor<TEvents extends Events, TAttributes extend
61
64
  $events: TEvents;
62
65
  $attributes: TAttributes;
63
66
  $styles: Array<string>;
64
- new (input?: Input<TEvents, TAttributes>, scope?: Scope, host?: CustomElement<TEvents, TAttributes>): Component<TEvents, TAttributes>;
67
+ new (input?: Input<TEvents, TAttributes>, scope?: Scope): Component<TEvents, TAttributes>;
65
68
  }
66
69
  export interface CustomElement<TEvents extends Events, TAttributes extends Attributes> extends HTMLElement {
67
- readonly internals: ElementInternals;
68
70
  readonly component: Component<TEvents, TAttributes>;
69
71
  }
70
72
  export interface CustomElementConstructor<TEvents extends Events, TAttributes extends Attributes> {
@@ -74,6 +76,7 @@ export declare class MountedEvent extends Event {
74
76
  constructor();
75
77
  }
76
78
  export declare const isTemplate: (value?: any) => value is Template;
79
+ export declare const useHost: (scope: Scope) => HostContext;
77
80
  export declare const createElement: <TEvents extends Events, TAttributes extends Attributes>(input: string | ComponentConstructor<TEvents, TAttributes>, attributes?: AttributeInput<TAttributes>, ...children: Array<Slot>) => Slot;
78
81
  export declare const toString: (slot: Slot) => string;
79
82
  export declare const isTextNode: (hydration?: Hydration) => hydration is Text;
@@ -85,7 +88,7 @@ export declare const toFragment: (hydration: Hydration) => DocumentFragment;
85
88
  export declare const hydrate: (scope: Scope, parentNode: Node, slot: Slot, index: number, previous?: Hydration) => Promise<Hydration>;
86
89
  export declare const renderToString: (scope: Scope, slot: Slot) => Promise<string>;
87
90
  export declare const defineComponent: <TEvents extends Events, TAttributes extends Attributes>(options: ComponentOptions<TEvents, TAttributes>) => ComponentConstructor<TEvents, TAttributes>;
88
- export declare const toCustomElement: <TEvents extends Events, TAttributes extends Attributes>(component: ComponentConstructor<TEvents, TAttributes>) => CustomElementConstructor<TEvents, TAttributes>;
91
+ export declare const toCustomElement: <TEvents extends Events, TAttributes extends Attributes>(Component: ComponentConstructor<TEvents, TAttributes>) => CustomElementConstructor<TEvents, TAttributes>;
89
92
  export declare const registerComponent: <TEvents extends Events, TAttributes extends Attributes>(component: ComponentConstructor<TEvents, TAttributes>) => ComponentConstructor<TEvents, TAttributes>;
90
93
  export declare function useEvent<T extends keyof ElementEventMap>(scope: Scope, target: EventTarget | undefined | null, event: T, input: EventListener<ElementEventMap[T]>, options?: AddEventListenerOptions): void;
91
94
  export declare function useEvent<T extends keyof WindowEventMap>(scope: Scope, target: Window | undefined | null, event: T, input: EventListener<WindowEventMap[T]>, options?: AddEventListenerOptions): void;
@@ -98,6 +101,7 @@ export declare const stopPropagation: (event: Event) => void;
98
101
  export declare const stopImmediatePropagation: (event: Event) => void;
99
102
  export declare const components: Map<string, ComponentConstructor<Events, Attributes>>;
100
103
  export declare const globalStyles: CSSStyleSheet[];
104
+ export declare const HOST_CONTEXT: import("..").Descriptor<HostContext>;
101
105
  declare global {
102
106
  interface HTMLElementEventMap {
103
107
  mounted: MountedEvent;
package/dist/index.js CHANGED
@@ -221,12 +221,20 @@ var MountedEvent = class extends Event {
221
221
  const isTemplate = (value) => {
222
222
  return typeof value === "object" && "tag" in value && "attributes" in value && "children" in value;
223
223
  };
224
+ const useHost = (scope) => {
225
+ return scope.getContext(HOST_CONTEXT);
226
+ };
224
227
  const createElement = (input, attributes, ...children) => {
225
- return {
228
+ const template = {
226
229
  tag: typeof input === "function" ? input.$name : input,
227
230
  attributes: attributes ?? {},
228
231
  children
229
232
  };
233
+ if (typeof input === "function" && input.$styles.length) {
234
+ const classes = template.attributes["class"];
235
+ template.attributes["class"] = (classes ? [classes, ...input.$styles] : input.$styles).join(" ");
236
+ }
237
+ return template;
230
238
  };
231
239
  const toString = (slot) => {
232
240
  switch (typeof slot) {
@@ -305,23 +313,24 @@ const hydrate = async (scope, parentNode, slot, index, previous) => {
305
313
  const textContent = slot.toString();
306
314
  if (isTextNode(hydration)) {
307
315
  if (previous) hydration.textContent = textContent;
308
- else if (hydration.textContent !== textContent) parentNode.insertBefore(hydration.splitText(textContent.length), hydration.nextSibling);
316
+ else if (textContent !== hydration.textContent) hydration = parentNode.replaceChild(document.createTextNode(textContent), hydration);
309
317
  } else hydration = document.createTextNode(textContent);
310
318
  }
311
319
  if (isTemplate(slot)) {
312
320
  const Component = components.get(slot.tag);
313
321
  if (Component) registerComponent(Component);
314
322
  if (isElementNode(hydration, slot.tag) === false) hydration = document.createElementNS(namespace(slot.tag), slot.tag);
315
- for (const [name, value] of Object.entries(slot.attributes)) createCompute(scope, (scope$1) => {
323
+ for (const [name, value] of Object.entries(slot.attributes)) createCompute(scope, (childScope) => {
316
324
  const target = hydration;
317
325
  if (name.startsWith("on")) {
318
326
  const event = name.substring(2).toLowerCase();
319
- useEvent(scope$1, target, event, value);
327
+ useEvent(childScope, target, event, value);
320
328
  } else {
321
329
  const set = toString(value);
322
330
  if (set === "" || set === "false") return target.removeAttribute(name);
323
331
  return target.setAttribute(name, set);
324
332
  }
333
+ scope.onStop(() => childScope.stop());
325
334
  });
326
335
  for (const [index$1, childSlot] of slot.children.entries()) await hydrate(scope, hydration, childSlot, index$1);
327
336
  }
@@ -378,8 +387,7 @@ const defineComponent = (options) => {
378
387
  events;
379
388
  attributes;
380
389
  shadowRoot;
381
- host;
382
- constructor(input, scope, host) {
390
+ constructor(input, scope) {
383
391
  this.scope = new Scope(scope);
384
392
  this.events = Object.keys(options.events ?? {}).reduce((output, name) => {
385
393
  Reflect.set(output, name, input?.[name], output);
@@ -390,53 +398,48 @@ const defineComponent = (options) => {
390
398
  return attributes;
391
399
  }, createState({}));
392
400
  this.shadowRoot = options.shadowRoot ?? { mode: "open" };
393
- this.host = host;
394
401
  }
395
- setup = () => {
396
- const findParent = (node) => {
397
- if (node) {
398
- if ("component" in node) return node;
399
- return findParent(node.parentNode);
400
- }
401
- };
402
- const parentNode = findParent(this.host?.parentNode);
403
- if (parentNode) this.scope.parentScope = parentNode.component.scope;
404
- return options.setup(this);
405
- };
402
+ setup = () => options.setup(this);
406
403
  }
407
404
  components.set(options.name, Instance);
408
405
  return Instance;
409
406
  };
410
- const toCustomElement = (component) => {
407
+ const toCustomElement = (Component) => {
411
408
  return class extends HTMLElement {
412
409
  static formAssociated = true;
413
- internals;
414
- component;
415
- constructor() {
416
- super();
417
- this.internals = this.attachInternals();
418
- this.component = new component(void 0, void 0, this);
419
- }
410
+ component = new Component();
420
411
  async connectedCallback() {
421
412
  let rootNode = this;
413
+ const findParent = (node) => {
414
+ if (node) {
415
+ if ("component" in node) return node;
416
+ return findParent(node.parentNode);
417
+ }
418
+ };
419
+ const parentNode = findParent(this.parentNode);
420
+ if (parentNode) this.component.scope.parentScope = parentNode.component.scope;
422
421
  if (this.component.shadowRoot) {
423
422
  const options = defu(this.component.shadowRoot, { mode: "open" });
424
423
  rootNode = this.shadowRoot ?? this.attachShadow(options);
425
424
  if (this.component.shadowRoot.globalStyles) rootNode.adoptedStyleSheets = globalStyles;
426
425
  }
427
- for (const [name, event] of Object.entries(component.$events)) Reflect.set(this.component.events, name, (value) => {
426
+ for (const [name, event] of Object.entries(Component.$events)) Reflect.set(this.component.events, name, (value) => {
428
427
  if (value instanceof Event) return;
429
428
  this.dispatchEvent(new CustomEvent(name.substring(2).toLowerCase(), {
430
429
  ...event,
431
430
  detail: value
432
431
  }));
433
432
  });
433
+ this.component.scope.setContext(HOST_CONTEXT, {
434
+ host: this,
435
+ internals: this.attachInternals()
436
+ });
434
437
  await hydrate(this.component.scope, rootNode, await this.component.setup(), 0);
435
438
  this.dispatchEvent(new MountedEvent());
436
439
  }
437
440
  attributeChangedCallback(name, oldValue, value) {
438
441
  if (value === oldValue) return;
439
- const attribute = component.$attributes?.[name];
442
+ const attribute = Component.$attributes?.[name];
440
443
  if (attribute) {
441
444
  let convertedValue;
442
445
  if (value) switch (attribute.type) {
@@ -460,7 +463,7 @@ const toCustomElement = (component) => {
460
463
  this.component.scope.stop();
461
464
  }
462
465
  static get observedAttributes() {
463
- return Object.keys(component.$attributes ?? {});
466
+ return Object.keys(Component.$attributes ?? {});
464
467
  }
465
468
  };
466
469
  };
@@ -500,6 +503,7 @@ const globalStyles = Array.from(isClient() ? document.styleSheets : []).map((sty
500
503
  sheet.replaceSync(css);
501
504
  return sheet;
502
505
  });
506
+ const HOST_CONTEXT = defineContext("HOST_CONTEXT");
503
507
 
504
508
  //#endregion
505
509
  //#region src/http/index.ts
@@ -920,4 +924,4 @@ const markdownToSlot = (input, options) => {
920
924
  };
921
925
 
922
926
  //#endregion
923
- 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, getMimeType, getRequestUrl, getRoutes, getSetCookies, getVariables, globalStyles, hydrate, isClient, isCommentNode, isElementNode, isServer, isTemplate, isTextNode, markdownToSlot, preventDefault, registerComponent, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, stopImmediatePropagation, stopPropagation, targets, toArray, toCustomElement, toFragment, toPath, toRange, toString, useEvent, useLocale, useRouter, useRuntime };
927
+ export { $fetch, Compute, HOST_CONTEXT, 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, getMimeType, getRequestUrl, getRoutes, getSetCookies, getVariables, globalStyles, hydrate, isClient, isCommentNode, isElementNode, isServer, isTemplate, isTextNode, markdownToSlot, preventDefault, registerComponent, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, stopImmediatePropagation, stopPropagation, targets, toArray, toCustomElement, toFragment, toPath, toRange, toString, useEvent, useHost, useLocale, useRouter, useRuntime };
package/dist/jsx/index.js CHANGED
@@ -39,14 +39,25 @@ const defuArrayFn = createDefu((object, key, currentValue) => {
39
39
  }
40
40
  });
41
41
 
42
+ //#endregion
43
+ //#region src/signals/index.ts
44
+ function defineContext(key) {
45
+ return key;
46
+ }
47
+
42
48
  //#endregion
43
49
  //#region src/html/index.ts
44
50
  const createElement = (input, attributes, ...children) => {
45
- return {
51
+ const template = {
46
52
  tag: typeof input === "function" ? input.$name : input,
47
53
  attributes: attributes ?? {},
48
54
  children
49
55
  };
56
+ if (typeof input === "function" && input.$styles.length) {
57
+ const classes = template.attributes["class"];
58
+ template.attributes["class"] = (classes ? [classes, ...input.$styles] : input.$styles).join(" ");
59
+ }
60
+ return template;
50
61
  };
51
62
  const isClient = () => typeof window !== "undefined";
52
63
  const globalStyles = Array.from(isClient() ? document.styleSheets : []).map((style) => {
@@ -55,6 +66,7 @@ const globalStyles = Array.from(isClient() ? document.styleSheets : []).map((sty
55
66
  sheet.replaceSync(css);
56
67
  return sheet;
57
68
  });
69
+ const HOST_CONTEXT = defineContext("HOST_CONTEXT");
58
70
 
59
71
  //#endregion
60
72
  //#region src/jsx/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "revojs",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "type": "module",
5
5
  "repository": "coverbase/revojs",
6
6
  "license": "MIT",