zenith 1.0.0-beta.13 → 1.0.0-beta.14

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/README.md CHANGED
@@ -1,50 +1,98 @@
1
1
  # Zenith
2
2
 
3
- Zenith is a tiny yet powerful reactive JavaScript framework that is under 2.5kb minified and gzipped, and 2.25kb minified and brotlified.
3
+ Zenith is a tiny reactive JavaScript framework with a virtual DOM, keyed reconciliation, and targeted component redraws. Its rendering model can update an entire application or a specific component, which is useful when parts of a page manage their own content, such as canvas, WebGL, and SVG interfaces.
4
4
 
5
- Its virtual dom and diffing algorithm function on an entire page or on specific nodes — especially useful in cases where you know that only a portion of the (v)dom tree will change. It allows for granular control over components that need to govern themselves and their own content, such as canvas, WebGL, or SVG. Additionally, it includes an opt-in object pool to minimize garbage collection.
5
+ Zenith supports component lifecycle hooks, memoization, DOM events, SVG and MathML, and optional helpers. It is inspired by [Mithril.js](https://github.com/MithrilJS/mithril.js).
6
6
 
7
- Zenith is fast, flexible, fully tested, and doesn’t require a build step. It wouldn’t exist without [Mithril.js](https://github.com/MithrilJS/mithril.js).
8
-
9
- **The current release release is alpha. It is used in production, but is still rapidly evolving. Consider the API relatively safe.**
7
+ **Status:** Zenith is currently in beta. We aim to keep the API stable through 1.0.0, but breaking changes may still occur during the beta period.
10
8
 
11
9
  ## Installation
12
10
 
13
- For now, use the .js files in /dist/.
11
+ Install the beta package:
14
12
 
15
- Will be available on npm soon.
13
+ ```sh
14
+ npm install zenith@beta
15
+ ```
16
16
 
17
- ## Additional Information
17
+ Import the functions you need:
18
18
 
19
- WIP: [Zenith site](https://aleph-1.com/zenith)
19
+ ```js
20
+ import { bind, comp, compDef, elem } from 'zenith';
21
+ ```
20
22
 
21
- Documentation coming soon.
23
+ Prebuilt browser files are also included in `dist/`. The `zenith.global.js` build is intended for direct browser use; the `zenith.js` build is an ES module.
22
24
 
23
- ## Simple Use Case
25
+ ## Example: counter
24
26
 
25
27
  ```html
26
- <!DOCTYPE html>
28
+ <!doctype html>
27
29
  <html lang="en">
28
30
  <head>
31
+ <meta charset="utf-8">
32
+ <title>Zenith counter</title>
29
33
  </head>
30
34
  <body>
31
35
  <main id="app"></main>
32
- <script src="js/zenith.min.js"></script>
33
- <script>
34
- let counter = 0;
35
- const CounterDef = z.compDef({
36
- draw: vNode => z.elem('div', z.text(`Counter: {$counter}`)),
37
- tick: vNode => {
38
- counter++;
39
- vNode.redraw();
40
- }
36
+ <script type="module">
37
+ import { bind, comp, compDef, elem } from 'zenith';
38
+
39
+ let count = 0;
40
+
41
+ const Counter = compDef({
42
+ draw: () => elem('button', {
43
+ onclick: () => { count++; }
44
+ }, `Count: ${count}`)
41
45
  });
42
- z.mount(document.querySelector('#app'), z.comp(CounterDef));
46
+
47
+ bind(document.querySelector('#app'), comp(Counter));
43
48
  </script>
44
49
  </body>
45
50
  </html>
46
51
  ```
47
52
 
53
+ The example assumes an environment that resolves npm package imports, such as a bundler or development server. Event handlers automatically schedule a redraw unless the event's `draw` property is set to `false`.
54
+
55
+ ## Components and redraws
56
+
57
+ Create components with `compDef()` and `comp()`, then mount them using `bind()`. Call `draw()` when external state changes outside an event handler:
58
+
59
+ ```js
60
+ import { bind, comp, compDef, draw, elem } from 'zenith';
61
+
62
+ let message = 'Hello';
63
+
64
+ const Message = compDef({
65
+ draw: () => elem('p', message)
66
+ });
67
+
68
+ const view = comp(Message);
69
+ bind(document.querySelector('#app'), view);
70
+
71
+ message = 'Updated';
72
+ draw(view);
73
+ ```
74
+
75
+ Redraws are scheduled in a microtask. Call `sync()` if you need to apply queued redraws immediately. `draw(view, true)` requests a targeted redraw of a component.
76
+
77
+ Component definitions can use `init`, `draw`, `drawn`, `remove`, and `removed` lifecycle hooks. `remove` may return a Promise to defer removal. Components also support optional memoization through `$memo`.
78
+
79
+ ## Package builds
80
+
81
+ The npm package includes prebuilt files under `dist/`, including:
82
+
83
+ - `zenith.js` — ES module
84
+ - `zenith.global.js` — global browser build
85
+ - `zenith.development.js` — development build
86
+ - `zenith-helpers.js` — optional helpers (import from `zenith/helpers`)
87
+
88
+ The library is designed for a very small compressed footprint; actual size depends on the build and compression settings.
89
+
90
+ ## Documentation
91
+
92
+ Additional information: [Zenith website](https://aleph-1.com/zenith) (work in progress).
93
+
94
+ Report bugs and request features through [GitHub Issues](https://github.com/aleph1/Zenith/issues).
95
+
48
96
  ## License
49
97
 
50
- [MIT](LICENSE.md)
98
+ [MIT](LICENSE)
@@ -0,0 +1,14 @@
1
+ import type { VNode } from '../vnode.defs';
2
+ /**
3
+ * Finds the closest ancestor vNode matching the predicate.
4
+ * Walks up the tree from the given vNode's parent.
5
+ * Returns undefined if no match is found.
6
+ *
7
+ * @example
8
+ * // Find the closest list component ancestor
9
+ * const list = closest(vNode, n => n.is === is.comp && n.$def === List);
10
+ *
11
+ * // Find the closest ancestor with a specific attribute
12
+ * const themed = closest(vNode, n => n.attrs?.theme);
13
+ */
14
+ export declare const closest: (vNode: VNode, predicate: (vNode: VNode) => boolean) => VNode | undefined;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Combines class names, filtering out falsy values.
3
+ *
4
+ * @example
5
+ * cls('btn', isActive && 'btn-active', hasError && 'btn-error')
6
+ * // => 'btn btn-active' (if isActive, not hasError)
7
+ */
8
+ export declare const cls: (...args: (string | false | null | undefined | 0)[]) => string;
@@ -0,0 +1,19 @@
1
+ import { Signal } from './signal';
2
+ export interface DerivedSignal<T> extends Signal<T> {
3
+ destroy(): void;
4
+ }
5
+ /**
6
+ * Creates a computed signal that updates when any dependency changes.
7
+ * Call destroy() in component cleanup to prevent memory leaks.
8
+ *
9
+ * @example
10
+ * const firstName = signal('John');
11
+ * const lastName = signal('Smith');
12
+ * const fullName = derived(
13
+ * () => `${firstName.val} ${lastName.val}`,
14
+ * [firstName, lastName]
15
+ * );
16
+ * // In component cleanup:
17
+ * removed: () => fullName.destroy()
18
+ */
19
+ export declare const derived: <T>(fn: () => T, deps: Signal<any>[]) => DerivedSignal<T>;
@@ -0,0 +1,20 @@
1
+ import type { VNodeNode } from '../vnode.defs';
2
+ /**
3
+ * Converts an HTML string to DOM nodes wrapped in node() vnodes.
4
+ *
5
+ * XSS WARNING: Only use with trusted, sanitized HTML.
6
+ * Never pass user-generated content without sanitization.
7
+ *
8
+ * @example
9
+ * // Safe static content
10
+ * html('<div class="card"><h2>Title</h2></div>')
11
+ *
12
+ * // Unsafe user input
13
+ * html(`<div>${userInput}</div>`)
14
+ *
15
+ * // Safe alternative
16
+ * elem('div', userInput)
17
+ *
18
+ * @see https://owasp.org/www-community/attacks/xss/
19
+ */
20
+ export declare const html: (value: string | number | bigint) => VNodeNode | VNodeNode[];
@@ -0,0 +1,13 @@
1
+ export { keep } from './keep';
2
+ export { is } from './is';
3
+ export { cls } from './cls';
4
+ export { slot } from './slot';
5
+ export { html } from './html';
6
+ export { closest } from './closest';
7
+ export { inject } from './inject';
8
+ export { signal } from './signal';
9
+ export type { Signal } from './signal';
10
+ export { derived } from './derived';
11
+ export type { DerivedSignal } from './derived';
12
+ export { router } from './router';
13
+ export { Portal } from './portal';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { VNode } from '../vnode.defs';
2
+ /**
3
+ * Retrieves values provided by ancestor components.
4
+ * Walks up the tree collecting requested keys, with closer
5
+ * ancestors taking priority (shadowing).
6
+ * Returns an object with only the keys that were found.
7
+ *
8
+ * @example
9
+ * const { theme, locale } = inject(vNode, 'theme', 'locale');
10
+ */
11
+ export declare const inject: (vNode: VNode, ...keys: string[]) => Record<string, any>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * vNode type constants for use with predicate checks.
3
+ *
4
+ * @example
5
+ * if (vNode.is === is.elem) // is a DOM element
6
+ * if (vNode.is === is.comp) // is a component
7
+ */
8
+ export declare const is: {
9
+ elem: number;
10
+ text: number;
11
+ comp: number;
12
+ node: number;
13
+ compDef: number;
14
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A memoization predicate that prevents all re-renders.
3
+ * Pass to a component's $memo property to make it fully static.
4
+ *
5
+ * @example
6
+ * const Static = compDef({
7
+ * $memo: keep,
8
+ * draw: () => elem('div', 'I never re-render')
9
+ * });
10
+ */
11
+ export declare const keep: () => boolean;
@@ -0,0 +1,21 @@
1
+ import type { VNodeComp, VNodeCompDefinition, VNodeAnyOrArray } from '../vnode.defs';
2
+ interface PortalAttrs {
3
+ to: string | Element;
4
+ children: VNodeAnyOrArray;
5
+ }
6
+ /**
7
+ * Renders children to a different DOM location.
8
+ * Useful for modals, tooltips, and overlays that need
9
+ * to escape their parent's stacking context or overflow.
10
+ *
11
+ * @example
12
+ * comp(Portal, {
13
+ * to: '#modals', // CSS selector
14
+ * to: document.body, // or Element reference
15
+ * children: comp(Modal)
16
+ * })
17
+ */
18
+ export declare const Portal: VNodeCompDefinition<PortalAttrs> & {
19
+ to: (vNode: VNodeComp<PortalAttrs>) => Element | null;
20
+ };
21
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { VNodeCompDefinition, VNodeAnyOrArray } from '../vnode.defs';
2
+ interface RouterOptions {
3
+ mode?: 'hash' | 'history';
4
+ }
5
+ type RouteComponent = (params: Record<string, string>) => VNodeAnyOrArray;
6
+ interface RouterRoutes {
7
+ [pattern: string]: RouteComponent;
8
+ '*'?: RouteComponent;
9
+ }
10
+ /**
11
+ * Creates a hash or history-based router as a component definition.
12
+ * Supports dynamic params (:id) and wildcard routes (*).
13
+ *
14
+ * @example
15
+ * const App = router({
16
+ * '/': () => comp(Home),
17
+ * '/users/:id': ({ id }) => comp(User, { id }),
18
+ * '*': () => comp(NotFound)
19
+ * });
20
+ *
21
+ * // Hash mode (default)
22
+ * draw(comp(App), document.body);
23
+ *
24
+ * // History mode
25
+ * draw(comp(router(routes, { mode: 'history' })), document.body);
26
+ */
27
+ export declare const router: (routes: RouterRoutes, options?: RouterOptions) => VNodeCompDefinition;
28
+ export {};
@@ -0,0 +1,21 @@
1
+ type SignalSubscriber<T> = (val: T) => void;
2
+ export interface Signal<T> {
3
+ get val(): T;
4
+ set val(newVal: T);
5
+ sub(fn: SignalSubscriber<T>): () => void;
6
+ notify(): void;
7
+ }
8
+ /**
9
+ * Creates a reactive value that notifies subscribers on change.
10
+ * Uses strict inequality (!==) to detect changes, so object
11
+ * mutations won't trigger notifications — use immutable updates
12
+ * or call notify() manually.
13
+ *
14
+ * @example
15
+ * const count = signal(0);
16
+ * const unsub = count.sub(val => console.log(val));
17
+ * count.val = 1; // logs 1
18
+ * unsub(); // stop listening
19
+ */
20
+ export declare const signal: <T>(val: T) => Signal<T>;
21
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { VNode, VNodeAttrs } from '../vnode.defs';
2
+ /**
3
+ * Resolves a content slot to a renderable vNode.
4
+ * Supports multiple content formats for flexible component APIs.
5
+ *
6
+ * - string → returned as-is
7
+ * - function → called with attrs, returns result
8
+ * - array → each item recursively resolved
9
+ * - vNode → returned as-is
10
+ * - null / undefined → returns nothing
11
+ *
12
+ * Note: component definitions must be wrapped in comp() by the caller.
13
+ *
14
+ * @example
15
+ * const Card = compDef({
16
+ * draw: (vNode) => elem('div', { class: 'card' },
17
+ * slot(vNode.attrs.header, vNode.attrs),
18
+ * slot(vNode.attrs.children, vNode.attrs)
19
+ * )
20
+ * });
21
+ *
22
+ * // Usage
23
+ * comp(Card, {
24
+ * header: elem('h2', 'Title'), // vNode
25
+ * children: (attrs) => elem('p', 'Hi'), // function
26
+ * children: comp(Modal, { ... }), // wrap in comp() explicitly
27
+ * })
28
+ */
29
+ export declare const slot: (content: VNode | VNode[] | string | ((attrs: VNodeAttrs) => VNode | VNode[] | string) | null | undefined, attrs: VNodeAttrs) => VNode | VNode[] | string | undefined;
@@ -0,0 +1,28 @@
1
+ declare global {
2
+ interface Window {
3
+ DEBUG?: boolean;
4
+ }
5
+ }
6
+ import { VNodeElem, VNodeComp, VNodeNode, VNodeAny, VNodeArray, VNodeElemAttributes, VNodeCompAttributes, VNodeCompDefinition, VNodeContainer } from './vnode.defs';
7
+ declare const ns: {
8
+ math: string;
9
+ svg: string;
10
+ };
11
+ export declare const diff: {
12
+ none: number;
13
+ self: number;
14
+ nodes: number;
15
+ all: number;
16
+ };
17
+ export declare const sync: () => void;
18
+ export declare const draw: (vNode: VNodeContainer, surgical?: boolean) => void;
19
+ export declare const elem: {
20
+ (tag: string): VNodeElem;
21
+ (tag: string, attrs: VNodeElemAttributes, ...args: VNodeArray): VNodeElem;
22
+ (tag: string, ...args: VNodeArray): VNodeElem;
23
+ };
24
+ export declare const compDef: (componentDefinition: VNodeCompDefinition) => VNodeCompDefinition;
25
+ export declare const comp: (componentDefinition: VNodeCompDefinition, attrs?: VNodeCompAttributes) => VNodeComp;
26
+ export declare const node: (el: Element) => VNodeNode;
27
+ export declare const bind: (el: Element, vNodeAnyOrArray: VNodeAny | VNodeArray) => VNodeComp;
28
+ export { ns };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,82 @@
1
+ export declare const VNODE_ELEM = 1;
2
+ export declare const VNODE_TEXT = 2;
3
+ export declare const VNODE_COMP = 3;
4
+ export declare const VNODE_NODE = 4;
5
+ export declare const VNODE_COMPDEF = 5;
6
+ export interface VNodeElemAttributes {
7
+ class?: string | string[];
8
+ style?: string | Record<string, string | number | null | undefined>;
9
+ $key?: string | number;
10
+ $diff?: number;
11
+ $remove?: boolean;
12
+ is?: string;
13
+ xmlns?: string;
14
+ [property: string]: any;
15
+ }
16
+ export interface VNodeCompAttributes {
17
+ $key?: string | number;
18
+ $remove?: boolean;
19
+ to?: string | Element;
20
+ [property: string]: any;
21
+ }
22
+ export type VNodeAttrs = VNodeElemAttributes | VNodeCompAttributes;
23
+ export interface VNodeNodeAttributes {
24
+ [property: string]: any;
25
+ }
26
+ export interface VNodeCompDefinition<A extends VNodeCompAttributes = VNodeCompAttributes> {
27
+ $tag?: number;
28
+ init?: (vNode: VNodeComp<A>) => void;
29
+ draw: (vNode: VNodeComp<A>, oldChildren?: VNodeFlatArray) => VNodeAnyOrArray;
30
+ drawn?: (vNode: VNodeComp<A>, isFirstDraw?: boolean) => void;
31
+ remove?: (vNode: VNodeComp<A>) => Promise<void> | void;
32
+ removed?: (vNode: VNodeComp<A>) => void;
33
+ $memo?: boolean | ((newAttrs: A, oldAttrs: A) => boolean);
34
+ }
35
+ interface VNodeBase {
36
+ $h?: boolean;
37
+ up: VNodeContainer | null;
38
+ nodes: VNodeFlatArray | null;
39
+ el: any;
40
+ }
41
+ export interface VNodeElem extends VNodeBase {
42
+ is: typeof VNODE_ELEM;
43
+ $tag: string;
44
+ $def: null;
45
+ attrs: VNodeElemAttributes;
46
+ nodes: VNodeFlatArray;
47
+ }
48
+ export interface VNodeText extends VNodeBase {
49
+ is: typeof VNODE_TEXT;
50
+ $tag: string;
51
+ $def: null;
52
+ attrs: null;
53
+ nodes: null;
54
+ }
55
+ export interface VNodeComp<A extends VNodeCompAttributes = VNodeCompAttributes> extends VNodeBase {
56
+ is: typeof VNODE_COMP;
57
+ $tag: number;
58
+ $def: VNodeCompDefinition;
59
+ attrs: A;
60
+ nodes: VNodeFlatArray;
61
+ provide?: Record<string, any>;
62
+ }
63
+ export interface VNodeNode extends VNodeBase {
64
+ is: typeof VNODE_NODE;
65
+ $tag: string;
66
+ $def: null;
67
+ attrs: null;
68
+ nodes: null;
69
+ }
70
+ export type VNode = VNodeElem | VNodeText | VNodeComp | VNodeNode;
71
+ export type VNodeAny = VNode;
72
+ export type VNodeContainer = VNodeComp | VNodeElem;
73
+ export type VNodeDrawable = VNodeComp;
74
+ export type VNodeHTML = VNodeElem;
75
+ export type VNodeDom = Node | Node[];
76
+ export type VNodeChild = VNodeAny | string | number | boolean | null | undefined;
77
+ export type VNodeArray = Array<VNodeChild | VNodeArray>;
78
+ export type VNodeAnyOrArray = VNodeChild | VNodeArray;
79
+ export interface VNodeFlatArray extends Array<VNodeAny> {
80
+ $keys?: Map<any, any> | null;
81
+ }
82
+ export {};
@@ -1,4 +1,4 @@
1
- /*! Zenith Helpers v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
1
+ /*! Zenith Helpers v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
2
  import { node, draw } from './zenith.js';
3
3
 
4
4
  const keep = () => true;
@@ -43,7 +43,7 @@ const inject = (vNode, ...keys) => {
43
43
  const result = {};
44
44
  const needed = new Set(keys);
45
45
  for (let current = vNode.up; current && needed.size > 0; current = current.up) {
46
- if (current.is === is.comp && current.provide) {
46
+ if (current.is === VNODE_COMP && current.provide) {
47
47
  for (const key of needed) {
48
48
  if (current.provide[key] !== void 0) {
49
49
  result[key] = current.provide[key];
@@ -122,24 +122,29 @@ const router = (routes, options = {}) => {
122
122
  });
123
123
  }
124
124
  return {
125
- init(vNode) {
125
+ init: (vNode) => {
126
+ const node = vNode;
126
127
  const matched = matchRoute(getPath());
127
- vNode.route = matched.component;
128
- vNode.params = matched.params;
129
- vNode.onroute = () => {
128
+ node.route = matched.component;
129
+ node.params = matched.params;
130
+ node.onroute = () => {
130
131
  const matched2 = matchRoute(getPath());
131
- vNode.route = matched2.component;
132
- vNode.params = matched2.params;
133
- draw(vNode, true);
132
+ node.route = matched2.component;
133
+ node.params = matched2.params;
134
+ draw(node, true);
134
135
  };
135
- window.addEventListener(eventType, vNode.onroute);
136
+ window.addEventListener(eventType, node.onroute);
136
137
  },
137
138
  draw: (vNode) => {
138
139
  var _a;
139
- return (_a = vNode.route) == null ? void 0 : _a.call(vNode, vNode.params);
140
+ const node = vNode;
141
+ return (_a = node.route) == null ? void 0 : _a.call(node, node.params);
140
142
  },
141
- removed(vNode) {
142
- window.removeEventListener(eventType, vNode.onroute);
143
+ removed: (vNode) => {
144
+ const node = vNode;
145
+ if (node.onroute) {
146
+ window.removeEventListener(eventType, node.onroute);
147
+ }
143
148
  }
144
149
  };
145
150
  };
@@ -1,2 +1,2 @@
1
- /*! Zenith Helpers v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
2
- !function(e){"use strict";const is={elem:1,text:2,comp:3,node:4,compDef:5},signal=e=>{let t=e;const o=new Set,n=()=>{for(const e of o)e(t)};return{get val(){return t},set val(e){t!==e&&(t=e,n())},sub:e=>(o.add(e),()=>o.delete(e)),notify:n}};window.zh={keep:()=>!0,is:is,cls:(...e)=>e.filter(Boolean).join(" "),slot:(e,t)=>{if(e)return"function"==typeof e?e(t):e},html:t=>{const o=document.createElement("div");o.innerHTML=t+"";const n=[...o.childNodes].map(t=>e.node(t));return 1===n.length?n[0]:n},closest:(e,t)=>{for(let o=e.up;o;o=o.up)if(t(o))return o},inject:(e,...t)=>{const o={},n=new Set(t);for(let t=e.up;t&&n.size>0;t=t.up)if(t.is===is.comp&&t.provide)for(const e of n)void 0!==t.provide[e]&&(o[e]=t.provide[e],n.delete(e));return o},signal:signal,derived:(e,t)=>{const o=signal(e()),n=t.map(t=>t.sub(()=>{o.val=e()}));return o.destroy=()=>{for(const e of n)e();n.length=0},o},router:(t,o={})=>{const n="history"===o.mode,r=n?"popstate":"hashchange",s=()=>n?location.pathname:location.hash.slice(1)||"/",c=[],a=e=>{for(const t of c){const o=e.match(t.regex);if(o){const e={};for(let n=0;t.keys.length>n;n++)e[t.keys[n]]=o[n+1];return{component:t.component,params:e}}}return{component:t["*"]||null,params:{}}};for(const e in t){const o=[],n=e.replace(/:[^/]+/g,e=>(o.push(e.slice(1)),"([^/]+)")).replace(/\*/g,"(.*)");c.push({regex:RegExp(`^${n}$`),keys:o,component:t[e]})}return{init(t){const o=a(s());t.route=o.component,t.params=o.params,t.onroute=()=>{const o=a(s());t.route=o.component,t.params=o.params,e.draw(t,!0)},window.addEventListener(r,t.onroute)},draw:e=>{var t;return null==(t=e.route)?void 0:t.call(e,e.params)},removed(e){window.removeEventListener(r,e.onroute)}}},Portal:{to:e=>"string"==typeof e.attrs.to?document.querySelector(e.attrs.to):e.attrs.to,draw:e=>e.attrs.children}}}(z);
1
+ /*! Zenith Helpers v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
+ !function(e){"use strict";const signal=e=>{let t=e;const o=new Set,n=()=>{for(const e of o)e(t)};return{get val(){return t},set val(e){t!==e&&(t=e,n())},sub:e=>(o.add(e),()=>o.delete(e)),notify:n}},t={keep:()=>!0,is:{elem:1,text:2,comp:3,node:4,compDef:5},cls:(...e)=>e.filter(Boolean).join(" "),slot:(e,t)=>{if(e)return"function"==typeof e?e(t):e},html:t=>{const o=document.createElement("div");o.innerHTML=t+"";const n=[...o.childNodes].map(t=>e.node(t));return 1===n.length?n[0]:n},closest:(e,t)=>{for(let o=e.up;o;o=o.up)if(t(o))return o},inject:(e,...t)=>{const o={},n=new Set(t);for(let t=e.up;t&&n.size>0;t=t.up)if(3===t.is&&t.provide)for(const e of n)void 0!==t.provide[e]&&(o[e]=t.provide[e],n.delete(e));return o},signal:signal,derived:(e,t)=>{const o=signal(e()),n=t.map(t=>t.sub(()=>{o.val=e()}));return o.destroy=()=>{for(const e of n)e();n.length=0},o},router:(t,o={})=>{const n="history"===o.mode,r=n?"popstate":"hashchange",s=()=>n?location.pathname:location.hash.slice(1)||"/",c=[],a=e=>{for(const t of c){const o=e.match(t.regex);if(o){const e={};for(let n=0;t.keys.length>n;n++)e[t.keys[n]]=o[n+1];return{component:t.component,params:e}}}return{component:t["*"]||null,params:{}}};for(const e in t){const o=[],n=e.replace(/:[^/]+/g,e=>(o.push(e.slice(1)),"([^/]+)")).replace(/\*/g,"(.*)");c.push({regex:RegExp(`^${n}$`),keys:o,component:t[e]})}return{init:t=>{const o=t,n=a(s());o.route=n.component,o.params=n.params,o.onroute=()=>{const t=a(s());o.route=t.component,o.params=t.params,e.draw(o,!0)},window.addEventListener(r,o.onroute)},draw:e=>{var t;return null==(t=e.route)?void 0:t.call(e,e.params)},removed:e=>{e.onroute&&window.removeEventListener(r,e.onroute)}}},Portal:{to:e=>"string"==typeof e.attrs.to?document.querySelector(e.attrs.to):e.attrs.to,draw:e=>e.attrs.children}};window.zh=t}(z);
@@ -1,2 +1,2 @@
1
- /*! Zenith Helpers v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
2
- import{node as e,draw as t}from"./zenith.js";const keep=()=>!0,is={elem:1,text:2,comp:3,node:4,compDef:5},cls=(...e)=>e.filter(Boolean).join(" "),slot=(e,t)=>{if(e)return"function"==typeof e?e(t):e},html=t=>{const o=document.createElement("div");o.innerHTML=t+"";const n=[...o.childNodes].map(t=>e(t));return 1===n.length?n[0]:n},closest=(e,t)=>{for(let o=e.up;o;o=o.up)if(t(o))return o},inject=(e,...t)=>{const o={},n=new Set(t);for(let t=e.up;t&&n.size>0;t=t.up)if(3===t.is&&t.provide)for(const e of n)void 0!==t.provide[e]&&(o[e]=t.provide[e],n.delete(e));return o},signal=e=>{let t=e;const o=new Set,n=()=>{for(const e of o)e(t)};return{get val(){return t},set val(e){t!==e&&(t=e,n())},sub:e=>(o.add(e),()=>o.delete(e)),notify:n}},derived=(e,t)=>{const o=signal(e()),n=t.map(t=>t.sub(()=>{o.val=e()}));return o.destroy=()=>{for(const e of n)e();n.length=0},o},router=(e,o={})=>{const n="history"===o.mode,r=n?"popstate":"hashchange",s=()=>n?location.pathname:location.hash.slice(1)||"/",a=[],c=t=>{for(const e of a){const o=t.match(e.regex);if(o){const t={};for(let n=0;e.keys.length>n;n++)t[e.keys[n]]=o[n+1];return{component:e.component,params:t}}}return{component:e["*"]||null,params:{}}};for(const t in e){const o=[],n=t.replace(/:[^/]+/g,e=>(o.push(e.slice(1)),"([^/]+)")).replace(/\*/g,"(.*)");a.push({regex:RegExp(`^${n}$`),keys:o,component:e[t]})}return{init(e){const o=c(s());e.route=o.component,e.params=o.params,e.onroute=()=>{const o=c(s());e.route=o.component,e.params=o.params,t(e,!0)},window.addEventListener(r,e.onroute)},draw:e=>{var t;return null==(t=e.route)?void 0:t.call(e,e.params)},removed(e){window.removeEventListener(r,e.onroute)}}},Portal={to:e=>"string"==typeof e.attrs.to?document.querySelector(e.attrs.to):e.attrs.to,draw:e=>e.attrs.children};export{Portal,closest,cls,derived,html,inject,is,keep,router,signal,slot};
1
+ /*! Zenith Helpers v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
+ import{node as e,draw as t}from"./zenith.js";const keep=()=>!0,is={elem:1,text:2,comp:3,node:4,compDef:5},cls=(...e)=>e.filter(Boolean).join(" "),slot=(e,t)=>{if(e)return"function"==typeof e?e(t):e},html=t=>{const o=document.createElement("div");o.innerHTML=t+"";const n=[...o.childNodes].map(t=>e(t));return 1===n.length?n[0]:n},closest=(e,t)=>{for(let o=e.up;o;o=o.up)if(t(o))return o},inject=(e,...t)=>{const o={},n=new Set(t);for(let t=e.up;t&&n.size>0;t=t.up)if(3===t.is&&t.provide)for(const e of n)void 0!==t.provide[e]&&(o[e]=t.provide[e],n.delete(e));return o},signal=e=>{let t=e;const o=new Set,n=()=>{for(const e of o)e(t)};return{get val(){return t},set val(e){t!==e&&(t=e,n())},sub:e=>(o.add(e),()=>o.delete(e)),notify:n}},derived=(e,t)=>{const o=signal(e()),n=t.map(t=>t.sub(()=>{o.val=e()}));return o.destroy=()=>{for(const e of n)e();n.length=0},o},router=(e,o={})=>{const n="history"===o.mode,r=n?"popstate":"hashchange",s=()=>n?location.pathname:location.hash.slice(1)||"/",a=[],c=t=>{for(const e of a){const o=t.match(e.regex);if(o){const t={};for(let n=0;e.keys.length>n;n++)t[e.keys[n]]=o[n+1];return{component:e.component,params:t}}}return{component:e["*"]||null,params:{}}};for(const t in e){const o=[],n=t.replace(/:[^/]+/g,e=>(o.push(e.slice(1)),"([^/]+)")).replace(/\*/g,"(.*)");a.push({regex:RegExp(`^${n}$`),keys:o,component:e[t]})}return{init:e=>{const o=e,n=c(s());o.route=n.component,o.params=n.params,o.onroute=()=>{const e=c(s());o.route=e.component,o.params=e.params,t(o,!0)},window.addEventListener(r,o.onroute)},draw:e=>{var t;return null==(t=e.route)?void 0:t.call(e,e.params)},removed:e=>{e.onroute&&window.removeEventListener(r,e.onroute)}}},Portal={to:e=>"string"==typeof e.attrs.to?document.querySelector(e.attrs.to):e.attrs.to,draw:e=>e.attrs.children};export{Portal,closest,cls,derived,html,inject,is,keep,router,signal,slot};
@@ -1,4 +1,4 @@
1
- /*! Zenith v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
1
+ /*! Zenith v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
2
  const VNODE_ELEM = 1;
3
3
  const VNODE_TEXT = 2;
4
4
  const VNODE_COMP = 3;
@@ -376,6 +376,7 @@ const _unmount = (nodes) => {
376
376
  _unmountReusableArray[0] = nodes;
377
377
  nodes = _unmountReusableArray;
378
378
  }
379
+ nodes = nodes;
379
380
  for (let i = 0; i < nodes.length; i++) {
380
381
  const node2 = nodes[i];
381
382
  if (node2.is === VNODE_COMP) {
@@ -1,2 +1,2 @@
1
- /*! Zenith v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
1
+ /*! Zenith v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
2
  const e=new Map,t=new Set,ns={math:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"},s=[],l={},n=new Map,sync=()=>{let s,l=t.size;if(l){const n=document.activeElement;for(const n of t)if(s=e.has(n.el)?n.el:n.attrs&&n.attrs.to||n.el&&n.el.parentNode||n.up&&n.up.el,t.delete(n),s&&g(n,s),! --l)break;t.size&&Promise.resolve().then(sync),n&&n!==document.activeElement&&"function"==typeof n.focus&&n.focus()}},draw=(e,s)=>{if(s)3===e.is&&(e.$tag|=2),t.add(e);else{let s;for(s=e;s.up;s=s.up);for(t.add(s),s=e;s.up;s=s.up)if(3===s.is){if(2&s.$tag)break;s.$tag|=2}}1===t.size&&Promise.resolve().then(sync)},r=[],o=(e,t=0,s=[])=>{let l;for(e&&"object"==typeof e&&null!=e.length||(r[0]=e,e=r);e.length>t;t++)if(l=e[t],Array.isArray(l))o(l,0,s);else if(null!=l)if(l.is){if(void 0===s.$keys)s.$keys=l.attrs&&"$key"in l.attrs?n:null;else if(!s.$keys!=!(l.attrs&&"$key"in l.attrs))throw Error("$keys");s.push(l)}else if(!0!==l&&!1!==l){if(void 0===s.$keys)s.$keys=null;else if(s.$keys)throw Error("$keys");s.push({is:2,$tag:l+"",$def:null,attrs:null,nodes:null,up:null,el:null})}return s},i=e=>{if(3===e.is&&!e.attrs.to){for(let t=e.nodes.length-1;t>=0;t--){const s=i(e.nodes[t]);if(s)return s}return null}return e.el},a=(e,t,s)=>{if(3!==e.is||e.attrs.to)e.el&&(e.el.nextSibling!==s&&t.insertBefore(e.el,s),s=e.el);else for(let l=e.nodes.length-1;l>=0;l--)s=a(e.nodes[l],t,s);return s},f=(e,t,s,l,n,r)=>{if(l.el){const o=s.is;if(o===l.is)if(1===o)if(s.up=e,s.$tag===l.$tag){s.el=l.el,s.$h=l.$h;const e=s.attrs.$diff||6;2&e&&$(s,l.attrs),4&e?d(s,s.el,s.nodes,l.nodes,s.attrs.xmlns||ns[s.$tag]||n):s.nodes=l.nodes}else u(e,t,s,n),t.insertBefore(s.el,l.el),h(l);else 2===o?(s.el=l.el,s.$tag!==l.$tag&&(s.el.textContent=s.$tag)):3===o?(4&l.$tag&&(l.$tag&=-5),s.up=e,s.$def===l.$def?(s.el=l.el,s.$h=l.$h,s.nodes=l.nodes,(r||2&l.$tag||!s.$def.$memo||(!0===s.$def.$memo?s.attrs!==l.attrs:!s.$def.$memo(s.attrs,l.attrs)))&&(s.$tag&=-3,g(s,t,n))):(u(e,t,s,n),h(l))):4===o&&s.el!==l.el&&(t.insertBefore(s.el,null),l.el.remove());else u(e,t,s,n),h(l)}else u(e,t,s,n)},d=(e,t,s,l,n,r=0)=>{const o=s.length,d=l.length;if(o){let r,$,g=0;if(d)if(s.$keys&&l.$keys){for(;o>g&&d>g&&s[g].attrs.$key===l[g].attrs.$key;)f(e,t,s[g],l[g],n),g++;if(o>g||d>g){const c=new Map;for(let e=g;d>e;e++)c.set(l[e].attrs.$key,l[e]);const m=i(l[d-1]);let p=m?m.nextSibling:null;for(let l=o-1;l>=g;l--){if($=s[l],r=c.get($.attrs.$key),r)if(c.delete($.attrs.$key),3===$.is&&$.attrs.$remove){if(!(4&r.$tag)&&h(r)){s.splice(l,1);continue}r.up=e,s[l]=r}else f(e,t,$,r,n);else{if($.attrs.$remove){s.splice(l,1);continue}u(e,t,$,n)}p=a(s[l],t,p)}for(const e of c.values())h(e)}}else{for(let e=o;d>e;e++)h(l[e]);for(let i=0;o>i;i++)r=l[i],$=s[i],r&&r.el?f(e,t,$,r,n):u(e,t,$,n)}else for(;o>g;g++)u(e,t,s[g],n)}else if(1===e.is)t.textContent="",m(l);else for(let e=0;d>e;e++)h(l[e]);e.nodes=s},$=(e,t=l)=>{let s,n;const r=e.el,o=e.attrs;for(s in"input"===e.$tag&&o.type&&r.setAttribute("type",o.type),o){const i=o[s];if("o"===s[0]&&"n"===s[1])i!==t[s]&&(r[s]="function"==typeof i?t=>{!1===i.call(t.currentTarget,t)&&(t.preventDefault(),t.stopPropagation()),!1!==t.draw&&draw(e)}:null);else if("$"!==s[0]&&("type"!==s||"input"!==e.$tag)&&"is"!==s&&"xmlns"!==s)if(n=typeof i,"string"===n||"number"===n)"value"===s?i!==t[s]&&(r.value=i):i!==t[s]&&r.setAttribute(s,i+"");else if(!0===i)!0!==t[s]&&r.setAttribute(s,s);else if(i){if("style"===s){if("string"==typeof t.style)r.removeAttribute("style");else for(const e in t.style||l)e in i||(r.style[e]="");Object.assign(r.style,i)}}else t[s]&&r.removeAttribute(s)}for(s in t)s in o||("o"===s[0]&&"n"===s[1]?r[s]=null:r.removeAttribute(s))},u=(e,t,s,l)=>{if(1===s.is){s.up=e,s.el=(l=s.attrs&&s.attrs.xmlns||ns[s.$tag]||l)?document.createElementNS(l,s.$tag,s.attrs.is?{is:s.attrs.is}:null):document.createElement(s.$tag,s.attrs.is?{is:s.attrs.is}:null),$(s);for(let e=0;s.nodes.length>e;e++)u(s,s.el,s.nodes[e],l);t.insertBefore(s.el,null)}else if(2===s.is)s.el=document.createTextNode(s.$tag),t.insertBefore(s.el,null);else if(3===s.is){if(s.up=e,s.$def.init&&s.$def.init(s),s.nodes=o(s.$def.draw(s)),8&s.$tag)for(let e=s;e&&!e.$h;e=e.up)e.$h=!0;s.attrs.to&&(s.el=document.createComment(""),t.insertBefore(s.el,null));for(let e=0;s.nodes.length>e;e++)u(s,s.attrs.to||t,s.nodes[e],l);s.el||(s.el=s.nodes[0]&&s.nodes[0].el),s.$def.drawn&&s.$def.drawn(s,!0)}else 4===s.is&&t.insertBefore(s.el,null)},g=(e,t,s)=>{const l=e.nodes,n=e.$def.draw(e,l);e.$tag&=-3,n!==l&&(d(e,e.attrs.to||t,o(n),l,s),e.el||(e.el=e.nodes[0]&&e.nodes[0].el)),e.$def.drawn&&e.$def.drawn(e)},c=[],m=e=>{Array.isArray(e)||(c[0]=e,e=c);for(let t=0;e.length>t;t++){const s=e[t];3===s.is&&((16&s.$tag||s.$def.remove)&&(64&s.$tag||s.$def.remove(s)),(32&s.$tag||s.$def.removed)&&s.$def.removed(s)),s.$h&&s.nodes.length&&(m(s.nodes),s.nodes=null),s.attrs=s.nodes=s.$tag=s.$def=s.el=s.up=null}},p=e=>{if(3===e.is){for(let t=0;e.nodes.length>t;t++)p(e.nodes[t]);e.attrs.to&&e.el&&e.el.remove()}else e.el&&e.el.remove()},y=e=>{p(e),m(e)},h=e=>{if(3===e.is&&(16&e.$tag||e.$def.remove)){if(4&e.$tag)return!1;e.$tag|=68;const t=e.$def.remove(e);if(t&&t.then){const s=()=>{if(4&e.$tag){const t=e.up;if(t){const s=t.nodes.indexOf(e);-1!==s&&t.nodes.splice(s,1)}y(e),draw(t)}};return t.then(s,s),!1}}return y(e),!0},compDef=e=>Object.freeze({is:5,$tag:1|(e.remove?16:0)|(e.removed?32:0)|(e.remove||e.removed?8:0),...e}),comp=(e,t=l)=>({is:3,$tag:e.$tag||0,$def:e,attrs:t,nodes:s,up:null,el:null}),v=compDef({draw:e=>e.attrs.$nodes});window.z={elem:function(e){const t=arguments[1],n=t&&"object"==typeof t&&!Array.isArray(t)&&!("$tag"in t);return{is:1,$tag:e,$def:null,attrs:n?t:l,nodes:arguments.length>(n?2:1)?o(arguments,n?2:1):s,up:null,el:null}},comp:comp,node:e=>({is:4,$tag:e.nodeName.toLowerCase(),$def:null,attrs:null,nodes:null,up:null,el:e}),compDef:compDef,bind:(t,s)=>{const l=e.get(t)||comp(v);return l.attrs={$nodes:s},e.set(l.el=t,l),draw(l),sync(),l},draw:draw,ns:ns,diff:{none:1,self:2,nodes:4,all:6}};
package/dist/zenith.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! Zenith v1.0.0-beta.13 | MIT License | © 2022-2025 Daniel Barber */
1
+ /*! Zenith v1.0.0-beta.14 | MIT License | © 2022-2025 Daniel Barber */
2
2
  const e=new Map,t=new Set,ns={math:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"},diff={none:1,self:2,nodes:4,all:6},s=[],l={},n=new Map,sync=()=>{let s,l=t.size;if(l){const n=document.activeElement;for(const n of t)if(s=e.has(n.el)?n.el:n.attrs&&n.attrs.to||n.el&&n.el.parentNode||n.up&&n.up.el,t.delete(n),s&&g(n,s),! --l)break;t.size&&Promise.resolve().then(sync),n&&n!==document.activeElement&&"function"==typeof n.focus&&n.focus()}},draw=(e,s)=>{if(s)3===e.is&&(e.$tag|=2),t.add(e);else{let s;for(s=e;s.up;s=s.up);for(t.add(s),s=e;s.up;s=s.up)if(3===s.is){if(2&s.$tag)break;s.$tag|=2}}1===t.size&&Promise.resolve().then(sync)},r=[],o=(e,t=0,s=[])=>{let l;for(e&&"object"==typeof e&&null!=e.length||(r[0]=e,e=r);e.length>t;t++)if(l=e[t],Array.isArray(l))o(l,0,s);else if(null!=l)if(l.is){if(void 0===s.$keys)s.$keys=l.attrs&&"$key"in l.attrs?n:null;else if(!s.$keys!=!(l.attrs&&"$key"in l.attrs))throw Error("$keys");s.push(l)}else if(!0!==l&&!1!==l){if(void 0===s.$keys)s.$keys=null;else if(s.$keys)throw Error("$keys");s.push({is:2,$tag:l+"",$def:null,attrs:null,nodes:null,up:null,el:null})}return s},i=e=>{if(3===e.is&&!e.attrs.to){for(let t=e.nodes.length-1;t>=0;t--){const s=i(e.nodes[t]);if(s)return s}return null}return e.el},a=(e,t,s)=>{if(3!==e.is||e.attrs.to)e.el&&(e.el.nextSibling!==s&&t.insertBefore(e.el,s),s=e.el);else for(let l=e.nodes.length-1;l>=0;l--)s=a(e.nodes[l],t,s);return s},f=(e,t,s,l,n,r)=>{if(l.el){const o=s.is;if(o===l.is)if(1===o)if(s.up=e,s.$tag===l.$tag){s.el=l.el,s.$h=l.$h;const e=s.attrs.$diff||6;2&e&&d(s,l.attrs),4&e?$(s,s.el,s.nodes,l.nodes,s.attrs.xmlns||ns[s.$tag]||n):s.nodes=l.nodes}else u(e,t,s,n),t.insertBefore(s.el,l.el),h(l);else 2===o?(s.el=l.el,s.$tag!==l.$tag&&(s.el.textContent=s.$tag)):3===o?(4&l.$tag&&(l.$tag&=-5),s.up=e,s.$def===l.$def?(s.el=l.el,s.$h=l.$h,s.nodes=l.nodes,(r||2&l.$tag||!s.$def.$memo||(!0===s.$def.$memo?s.attrs!==l.attrs:!s.$def.$memo(s.attrs,l.attrs)))&&(s.$tag&=-3,g(s,t,n))):(u(e,t,s,n),h(l))):4===o&&s.el!==l.el&&(t.insertBefore(s.el,null),l.el.remove());else u(e,t,s,n),h(l)}else u(e,t,s,n)},$=(e,t,s,l,n,r=0)=>{const o=s.length,$=l.length;if(o){let r,d,g=0;if($)if(s.$keys&&l.$keys){for(;o>g&&$>g&&s[g].attrs.$key===l[g].attrs.$key;)f(e,t,s[g],l[g],n),g++;if(o>g||$>g){const c=new Map;for(let e=g;$>e;e++)c.set(l[e].attrs.$key,l[e]);const p=i(l[$-1]);let m=p?p.nextSibling:null;for(let l=o-1;l>=g;l--){if(d=s[l],r=c.get(d.attrs.$key),r)if(c.delete(d.attrs.$key),3===d.is&&d.attrs.$remove){if(!(4&r.$tag)&&h(r)){s.splice(l,1);continue}r.up=e,s[l]=r}else f(e,t,d,r,n);else{if(d.attrs.$remove){s.splice(l,1);continue}u(e,t,d,n)}m=a(s[l],t,m)}for(const e of c.values())h(e)}}else{for(let e=o;$>e;e++)h(l[e]);for(let i=0;o>i;i++)r=l[i],d=s[i],r&&r.el?f(e,t,d,r,n):u(e,t,d,n)}else for(;o>g;g++)u(e,t,s[g],n)}else if(1===e.is)t.textContent="",p(l);else for(let e=0;$>e;e++)h(l[e]);e.nodes=s},d=(e,t=l)=>{let s,n;const r=e.el,o=e.attrs;for(s in"input"===e.$tag&&o.type&&r.setAttribute("type",o.type),o){const i=o[s];if("o"===s[0]&&"n"===s[1])i!==t[s]&&(r[s]="function"==typeof i?t=>{!1===i.call(t.currentTarget,t)&&(t.preventDefault(),t.stopPropagation()),!1!==t.draw&&draw(e)}:null);else if("$"!==s[0]&&("type"!==s||"input"!==e.$tag)&&"is"!==s&&"xmlns"!==s)if(n=typeof i,"string"===n||"number"===n)"value"===s?i!==t[s]&&(r.value=i):i!==t[s]&&r.setAttribute(s,i+"");else if(!0===i)!0!==t[s]&&r.setAttribute(s,s);else if(i){if("style"===s){if("string"==typeof t.style)r.removeAttribute("style");else for(const e in t.style||l)e in i||(r.style[e]="");Object.assign(r.style,i)}}else t[s]&&r.removeAttribute(s)}for(s in t)s in o||("o"===s[0]&&"n"===s[1]?r[s]=null:r.removeAttribute(s))},u=(e,t,s,l)=>{if(1===s.is){s.up=e,s.el=(l=s.attrs&&s.attrs.xmlns||ns[s.$tag]||l)?document.createElementNS(l,s.$tag,s.attrs.is?{is:s.attrs.is}:null):document.createElement(s.$tag,s.attrs.is?{is:s.attrs.is}:null),d(s);for(let e=0;s.nodes.length>e;e++)u(s,s.el,s.nodes[e],l);t.insertBefore(s.el,null)}else if(2===s.is)s.el=document.createTextNode(s.$tag),t.insertBefore(s.el,null);else if(3===s.is){if(s.up=e,s.$def.init&&s.$def.init(s),s.nodes=o(s.$def.draw(s)),8&s.$tag)for(let e=s;e&&!e.$h;e=e.up)e.$h=!0;s.attrs.to&&(s.el=document.createComment(""),t.insertBefore(s.el,null));for(let e=0;s.nodes.length>e;e++)u(s,s.attrs.to||t,s.nodes[e],l);s.el||(s.el=s.nodes[0]&&s.nodes[0].el),s.$def.drawn&&s.$def.drawn(s,!0)}else 4===s.is&&t.insertBefore(s.el,null)},g=(e,t,s)=>{const l=e.nodes,n=e.$def.draw(e,l);e.$tag&=-3,n!==l&&($(e,e.attrs.to||t,o(n),l,s),e.el||(e.el=e.nodes[0]&&e.nodes[0].el)),e.$def.drawn&&e.$def.drawn(e)},c=[],p=e=>{Array.isArray(e)||(c[0]=e,e=c);for(let t=0;e.length>t;t++){const s=e[t];3===s.is&&((16&s.$tag||s.$def.remove)&&(64&s.$tag||s.$def.remove(s)),(32&s.$tag||s.$def.removed)&&s.$def.removed(s)),s.$h&&s.nodes.length&&(p(s.nodes),s.nodes=null),s.attrs=s.nodes=s.$tag=s.$def=s.el=s.up=null}},m=e=>{if(3===e.is){for(let t=0;e.nodes.length>t;t++)m(e.nodes[t]);e.attrs.to&&e.el&&e.el.remove()}else e.el&&e.el.remove()},y=e=>{m(e),p(e)},h=e=>{if(3===e.is&&(16&e.$tag||e.$def.remove)){if(4&e.$tag)return!1;e.$tag|=68;const t=e.$def.remove(e);if(t&&t.then){const s=()=>{if(4&e.$tag){const t=e.up;if(t){const s=t.nodes.indexOf(e);-1!==s&&t.nodes.splice(s,1)}y(e),draw(t)}};return t.then(s,s),!1}}return y(e),!0},elem=function(e){const t=arguments[1],n=t&&"object"==typeof t&&!Array.isArray(t)&&!("$tag"in t);return{is:1,$tag:e,$def:null,attrs:n?t:l,nodes:arguments.length>(n?2:1)?o(arguments,n?2:1):s,up:null,el:null}},compDef=e=>Object.freeze({is:5,$tag:1|(e.remove?16:0)|(e.removed?32:0)|(e.remove||e.removed?8:0),...e}),comp=(e,t=l)=>({is:3,$tag:e.$tag||0,$def:e,attrs:t,nodes:s,up:null,el:null}),node=e=>({is:4,$tag:e.nodeName.toLowerCase(),$def:null,attrs:null,nodes:null,up:null,el:e}),v=compDef({draw:e=>e.attrs.$nodes}),bind=(t,s)=>{const l=e.get(t)||comp(v);return l.attrs={$nodes:s},e.set(l.el=t,l),draw(l),sync(),l};export{bind,comp,compDef,diff,draw,elem,node,ns,sync};
package/package.json CHANGED
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "name": "zenith",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.14",
4
4
  "description": "Another front-end framework.",
5
5
  "type": "module",
6
- "main": "dist/zenith.global.js",
7
- "module": "dist/zenith.js",
6
+ "main": "./dist/zenith.js",
7
+ "module": "./dist/zenith.js",
8
+ "types": "./dist/types/index.d.ts",
8
9
  "exports": {
9
- ".": "./dist/zenith.js",
10
- "./helpers": "./dist/zenith-helpers.js"
10
+ ".": {
11
+ "types": "./dist/types/index.d.ts",
12
+ "default": "./dist/zenith.js"
13
+ },
14
+ "./helpers": {
15
+ "types": "./dist/types/helpers/index.d.ts",
16
+ "default": "./dist/zenith-helpers.js"
17
+ }
11
18
  },
12
19
  "files": [
13
20
  "dist/"
14
21
  ],
15
22
  "sideEffects": false,
16
23
  "scripts": {
17
- "build": "rollup --config && node scripts/after-build.mjs",
24
+ "build": "rollup --config && tsc && node scripts/after-build.mjs",
18
25
  "lint": "eslint . --ext .ts",
19
26
  "test": "vitest --run --coverage --reporter verbose",
20
27
  "test:ui": "vitest --ui",