humn 1.0.1 → 1.1.0

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/dist/humn.js CHANGED
@@ -1,207 +1,209 @@
1
- let C = null, S = null;
2
- const x = () => C, g = (t) => {
3
- C = t;
4
- }, A = () => S, k = (t) => {
5
- S = t;
1
+ let E = null, N = null;
2
+ const w = () => E, v = (s) => {
3
+ E = s;
4
+ }, S = () => N, C = (s) => {
5
+ N = s;
6
6
  };
7
- class T {
8
- /**
9
- * Creates an instance of Cortex.
10
- * @param {CortexParams} CortexParams - The parameters for the Cortex.
11
- */
12
- constructor({ memory: e, synapses: s }) {
13
- this._memory = e, this._listeners = /* @__PURE__ */ new Set();
14
- const i = () => this._memory, c = (n) => {
15
- let r;
7
+ class $ {
8
+ constructor({ memory: t, synapses: o }) {
9
+ const i = { ...t };
10
+ this._persistenceMap = /* @__PURE__ */ new Map();
11
+ for (const [n, e] of Object.entries(t)) if (e && e.__humn_persist) {
12
+ const r = e.config.key || n;
13
+ this._persistenceMap.set(n, r);
14
+ try {
15
+ const c = localStorage.getItem(r);
16
+ i[n] = c !== null ? JSON.parse(c) : e.initial;
17
+ } catch {
18
+ i[n] = e.initial;
19
+ }
20
+ }
21
+ this._memory = i, this._listeners = /* @__PURE__ */ new Map(), this.synapses = o((n) => {
22
+ let e, r = /* @__PURE__ */ new Set();
16
23
  if (typeof n == "function") {
17
- const o = structuredClone(this._memory);
18
- r = n(o) || o;
19
- } else
20
- r = { ...this._memory, ...n };
21
- this._memory = r, this._listeners.forEach((o) => o());
22
- };
23
- this.synapses = s(c, i);
24
+ const c = structuredClone(this._memory), a = n(this._createChangeTrackingProxy(c, r));
25
+ a && typeof a == "object" ? (e = { ...this._memory, ...a }, Object.keys(a).forEach((l) => r.add(l))) : e = c;
26
+ } else e = { ...this._memory, ...n }, r = new Set(Object.keys(n));
27
+ this._memory = e, this._persistenceMap.size > 0 && this._persistenceMap.forEach((c, a) => {
28
+ if (Array.from(r).some((l) => l === a || l.startsWith(a + "."))) try {
29
+ const l = this._memory[a];
30
+ localStorage.setItem(c, JSON.stringify(l));
31
+ } catch {
32
+ }
33
+ }), this._notifyRelevantListeners(r);
34
+ }, () => this._memory);
35
+ }
36
+ _createChangeTrackingProxy(t, o, i = "") {
37
+ return new Proxy(t, { get: (n, e) => {
38
+ if (typeof e == "symbol" || e === "__proto__") return n[e];
39
+ const r = n[e], c = i ? `${i}.${e}` : e;
40
+ return typeof r == "object" && r !== null ? this._createChangeTrackingProxy(r, o, c) : r;
41
+ }, set: (n, e, r) => {
42
+ if (typeof e == "symbol" || e === "__proto__") return n[e] = r, !0;
43
+ const c = i ? `${i}.${e}` : e;
44
+ return o.add(c), n[e] = r, !0;
45
+ } });
46
+ }
47
+ _notifyRelevantListeners(t) {
48
+ this._listeners.forEach((o, i) => {
49
+ Array.from(o).some((n) => Array.from(t).some((e) => n === e || n.startsWith(e + ".") || e.startsWith(n + "."))) && i();
50
+ });
51
+ }
52
+ _createAccessTrackingProxy(t, o, i = "") {
53
+ return typeof t != "object" || t === null ? t : new Proxy(t, { get: (n, e) => {
54
+ if (typeof e == "symbol" || e === "__proto__") return n[e];
55
+ const r = i ? `${i}.${e}` : e;
56
+ o.add(r);
57
+ const c = n[e];
58
+ return typeof c == "object" && c !== null ? this._createAccessTrackingProxy(c, o, r) : c;
59
+ } });
24
60
  }
25
- /**
26
- * Get the memory and register the current observer.
27
- * @returns {object} The current state
28
- */
29
61
  get memory() {
30
- const e = x();
31
- return e && this._listeners.add(e), this._memory;
62
+ const t = w();
63
+ if (!t) return this._memory;
64
+ this._listeners.has(t) || this._listeners.set(t, /* @__PURE__ */ new Set());
65
+ const o = this._listeners.get(t);
66
+ return o.clear(), this._createAccessTrackingProxy(this._memory, o);
32
67
  }
33
68
  }
34
- let h = null;
35
- const E = /* @__PURE__ */ new Set();
36
- function I(t) {
37
- let e = 5381, s = t.length;
38
- for (; s; )
39
- e = e * 33 ^ t.charCodeAt(--s);
40
- return (e >>> 0).toString(36);
41
- }
42
- function O(t) {
43
- return t.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim();
44
- }
45
- function K(t, ...e) {
46
- const s = t.reduce((r, o, l) => r + o + (e[l] || ""), ""), i = O(s);
47
- if (!i) return "";
48
- const c = I(i), n = `humn-${c}`;
49
- return E.has(c) || (h || (h = document.createElement("style"), h.id = "humn-styles", document.head.appendChild(h)), h.textContent += `.${n} {
50
- ${i}
69
+ let f = null;
70
+ const b = /* @__PURE__ */ new Set();
71
+ function j(s, ...t) {
72
+ const o = (function(e) {
73
+ return e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim();
74
+ })(s.reduce((e, r, c) => e + r + (t[c] || ""), ""));
75
+ if (!o) return "";
76
+ const i = (function(e) {
77
+ let r = 5381, c = e.length;
78
+ for (; c; ) r = 33 * r ^ e.charCodeAt(--c);
79
+ return (r >>> 0).toString(36);
80
+ })(o), n = `humn-${i}`;
81
+ return b.has(i) || (f || (f = document.createElement("style"), f.id = "humn-styles", document.head.appendChild(f)), f.textContent += `.${n} {
82
+ ${o}
51
83
  }
52
- `, E.add(c)), n;
84
+ `, b.add(i)), n;
53
85
  }
54
- const $ = (t, e = {}, s = []) => {
55
- const c = (Array.isArray(s) ? s : [s]).flat().filter((n) => n != null && n !== !1 && n !== "");
56
- return {
57
- tag: t,
58
- props: e,
59
- children: c
60
- };
61
- };
62
- function B(t) {
63
- const e = A();
64
- e && e.mounts.push(t);
86
+ const M = (s, t = {}, o = []) => ({ tag: s, props: t, children: (Array.isArray(o) ? o : [o]).flat().filter((i) => i != null && i !== !1 && i !== "") });
87
+ function P(s) {
88
+ const t = S();
89
+ t && t.mounts.push(s);
65
90
  }
66
- function M(t) {
67
- const e = A();
68
- e && e.cleanups.push(t);
91
+ function O(s) {
92
+ const t = S();
93
+ t && t.cleanups.push(s);
69
94
  }
70
- function b(t) {
71
- return t && t.some((e) => e && e.props && e.props.key != null);
95
+ function x(s) {
96
+ return s && s.some((t) => t && t.props && t.props.key != null);
72
97
  }
73
- function a(t) {
74
- if (typeof t == "string" || typeof t == "number")
75
- return document.createTextNode(String(t));
76
- if (typeof t.tag == "function") {
77
- const s = d(t);
78
- t.child = s;
79
- const i = a(s);
80
- return t.el = i, t.hooks && t.hooks.mounts.length > 0 && setTimeout(() => t.hooks.mounts.forEach((c) => c()), 0), i;
98
+ function d(s) {
99
+ if (typeof s == "string" || typeof s == "number") return document.createTextNode(String(s));
100
+ if (typeof s.tag == "function") {
101
+ const o = T(s);
102
+ s.child = o;
103
+ const i = d(o);
104
+ return s.el = i, s.hooks && s.hooks.mounts.length > 0 && setTimeout(() => s.hooks.mounts.forEach((n) => n()), 0), i;
81
105
  }
82
- const e = document.createElement(t.tag);
83
- return t.el = e, _(e, t.props), t.children.forEach((s) => {
84
- e.appendChild(a(s));
85
- }), e;
106
+ const t = document.createElement(s.tag);
107
+ return s.el = t, A(t, s.props), s.children.forEach((o) => {
108
+ t.appendChild(d(o));
109
+ }), t;
86
110
  }
87
- function _(t, e = {}, s = {}) {
88
- if (!t) return;
89
- const i = { ...s, ...e };
90
- for (const c in i) {
91
- const n = s[c], r = e[c];
92
- if (r == null) {
93
- t.removeAttribute(c);
94
- continue;
95
- }
96
- if (c === "value" || c === "checked") {
97
- t[c] !== r && (t[c] = r);
98
- continue;
99
- }
100
- if (n !== r) {
101
- if (c.startsWith("on")) {
102
- const o = c.slice(2).toLowerCase();
103
- n && t.removeEventListener(o, n), t.addEventListener(o, r);
111
+ function A(s, t = {}, o = {}) {
112
+ if (!s) return;
113
+ const i = { ...o, ...t };
114
+ for (const n in i) {
115
+ const e = o[n], r = t[n];
116
+ if (r != null) if (n !== "value" && n !== "checked") {
117
+ if (e !== r) {
118
+ if (n.startsWith("on")) {
119
+ const c = n.slice(2).toLowerCase();
120
+ e && s.removeEventListener(c, e), s.addEventListener(c, r);
121
+ }
122
+ n === "disabled" ? s.disabled = r === !0 || r === "true" : s.setAttribute(n, r);
104
123
  }
105
- c === "disabled" ? t.disabled = r === !0 || r === "true" : t.setAttribute(c, r);
106
- }
107
- }
108
- }
109
- function L(t, e, s) {
110
- if (!(b(e) || b(s))) {
111
- const n = Math.max(e.length, s.length);
112
- for (let r = 0; r < n; r++)
113
- m(t, e[r], s[r], r);
114
- return;
124
+ } else s[n] !== r && (s[n] = r);
125
+ else s.removeAttribute(n);
115
126
  }
116
- const c = {};
117
- s.forEach((n, r) => {
118
- const o = (n.props && n.props.key) != null ? n.props.key : r;
119
- c[o] = { vNode: n, index: r };
120
- }), e.forEach((n, r) => {
121
- const o = (n.props && n.props.key) != null ? n.props.key : r, l = c[o];
122
- if (l) {
123
- const f = l.vNode;
124
- m(t, n, f, r);
125
- const u = n.el || f.el, y = t.childNodes[r];
126
- u && y !== u && t.insertBefore(u, y), delete c[o];
127
- } else {
128
- const f = a(n), u = t.childNodes[r];
129
- u ? t.insertBefore(f, u) : t.appendChild(f);
130
- }
131
- }), Object.values(c).forEach(({ vNode: n }) => {
132
- n.el && n.el.parentNode === t && t.removeChild(n.el);
133
- });
134
127
  }
135
- function d(t) {
136
- const e = {
137
- mounts: [],
138
- cleanups: []
139
- };
140
- k(e);
141
- const s = t.tag(t.props);
142
- return k(null), t.hooks = e, s;
128
+ function T(s) {
129
+ const t = { mounts: [], cleanups: [] };
130
+ C(t);
131
+ const o = s.tag(s.props);
132
+ return C(null), s.hooks = t, o;
143
133
  }
144
- function p(t) {
145
- t && (t.hooks && t.hooks.cleanups && t.hooks.cleanups.forEach((e) => e()), t.child && p(t.child), t.children && t.children.forEach(p));
134
+ function _(s) {
135
+ s && (s.hooks && s.hooks.cleanups && s.hooks.cleanups.forEach((t) => t()), s.child && _(s.child), s.children && s.children.forEach(_));
146
136
  }
147
- function m(t, e, s, i = 0) {
148
- if (e == null) {
149
- const n = s.el || t.childNodes[i];
150
- p(s), n && t.removeChild(n);
151
- return;
152
- }
153
- if (typeof e.tag == "function") {
154
- const n = !s, r = d(e);
155
- e.child = r;
156
- const o = s ? s.child : void 0;
157
- m(t, r, o, i), e.el = r.el, n && e.hooks && e.hooks.mounts.length > 0 && setTimeout(() => {
158
- e.hooks.mounts.forEach((l) => l());
159
- }, 0);
160
- return;
137
+ function y(s, t, o, i = 0) {
138
+ if (t == null) {
139
+ const e = o.el || s.childNodes[i];
140
+ return _(o), void (e && s.removeChild(e));
161
141
  }
162
- if (s == null) {
163
- t.appendChild(a(e));
164
- return;
142
+ if (typeof t.tag == "function") {
143
+ const e = !o, r = T(t);
144
+ return t.child = r, y(s, r, o ? o.child : void 0, i), t.el = r.el, void (e && t.hooks && t.hooks.mounts.length > 0 && setTimeout(() => {
145
+ t.hooks.mounts.forEach((c) => c());
146
+ }, 0));
165
147
  }
166
- if (e == null) {
167
- const n = s.el || t.childNodes[i];
168
- n && t.removeChild(n);
169
- return;
148
+ if (o == null) return void s.appendChild(d(t));
149
+ if (t == null) {
150
+ const e = o.el || s.childNodes[i];
151
+ return void (e && s.removeChild(e));
170
152
  }
171
- if (typeof e != typeof s || typeof e != "string" && e.tag !== s.tag) {
172
- const n = s.el || t.childNodes[i];
173
- n && t.replaceChild(a(e), n);
174
- return;
153
+ if (typeof t != typeof o || typeof t != "string" && t.tag !== o.tag) {
154
+ const e = o.el || s.childNodes[i];
155
+ return void (e && s.replaceChild(d(t), e));
175
156
  }
176
- if (typeof e == "string" || typeof e == "number") {
177
- if (e !== s) {
178
- const n = t.childNodes[i];
179
- n ? n.nodeValue = String(e) : t.appendChild(document.createTextNode(String(e)));
157
+ if (typeof t == "string" || typeof t == "number") {
158
+ if (t !== o) {
159
+ const e = s.childNodes[i];
160
+ e ? e.nodeValue = String(t) : s.appendChild(document.createTextNode(String(t)));
180
161
  }
181
162
  return;
182
163
  }
183
- const c = s.el || t.childNodes[i];
184
- c && (e.el = c, _(c, e.props, s.props), L(c, e.children, s.children));
164
+ const n = o.el || s.childNodes[i];
165
+ n && (t.el = n, A(n, t.props, o.props), (function(e, r, c) {
166
+ if (!x(r) && !x(c)) {
167
+ const l = Math.max(r.length, c.length);
168
+ for (let h = 0; h < l; h++) y(e, r[h], c[h], h);
169
+ return;
170
+ }
171
+ const a = {};
172
+ c.forEach((l, h) => {
173
+ const m = (l.props && l.props.key) != null ? l.props.key : h;
174
+ a[m] = { vNode: l, index: h };
175
+ }), r.forEach((l, h) => {
176
+ const m = (l.props && l.props.key) != null ? l.props.key : h, g = a[m];
177
+ if (g) {
178
+ const p = g.vNode;
179
+ y(e, l, p, h);
180
+ const u = l.el || p.el, k = e.childNodes[h];
181
+ u && k !== u && e.insertBefore(u, k), delete a[m];
182
+ } else {
183
+ const p = d(l), u = e.childNodes[h];
184
+ u ? e.insertBefore(p, u) : e.appendChild(p);
185
+ }
186
+ }), Object.values(a).forEach(({ vNode: l }) => {
187
+ l.el && l.el.parentNode === e && (_(l), e.removeChild(l.el));
188
+ });
189
+ })(n, t.children, o.children));
185
190
  }
186
- const j = (t, e) => {
187
- let s = null;
191
+ const L = (s, t) => {
192
+ let o = null;
188
193
  const i = () => {
189
- g(i);
190
- const c = {
191
- tag: e,
192
- props: {},
193
- children: []
194
- };
195
- m(t, c, s), g(null), s = c;
194
+ v(i);
195
+ const n = { tag: t, props: {}, children: [] };
196
+ y(s, n, o), v(null), o = n;
196
197
  };
197
198
  i();
198
- };
199
+ }, W = (s, t = {}) => ({ __humn_persist: !0, initial: s, config: t });
199
200
  export {
200
- T as Cortex,
201
- K as css,
202
- $ as h,
203
- j as mount,
204
- M as onCleanup,
205
- B as onMount
201
+ $ as Cortex,
202
+ j as css,
203
+ M as h,
204
+ L as mount,
205
+ O as onCleanup,
206
+ P as onMount,
207
+ W as persist
206
208
  };
207
209
  //# sourceMappingURL=humn.js.map
package/dist/humn.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"humn.js","sources":["../src/observer.js","../src/cortex.js","../src/css.js","../src/h.js","../src/lifecycle.js","../src/patch.js","../src/mount.js"],"sourcesContent":["/**\n * @file Observer module for tracking global state during rendering.\n * @module observer\n */\n\nlet currentObserver = null; // For Cortex/State dependency\nlet currentInstance = null; // For Lifecycle Hooks\n\n/**\n * Gets the current observer (render function).\n * @returns {function|null}\n */\nexport const getObserver = () => currentObserver;\n\n/**\n * Sets the current observer.\n * @param {function|null} obs\n */\nexport const setObserver = (obs) => {\n currentObserver = obs;\n};\n\n/**\n * Gets the current component instance (hook container).\n * @returns {object|null}\n */\nexport const getInstance = () => currentInstance;\n\n/**\n * Sets the current component instance.\n * @param {object|null} inst\n */\nexport const setInstance = (inst) => {\n currentInstance = inst;\n};\n","import { getObserver } from \"./observer.js\";\n\n/**\n * @typedef {object} Synapses\n * @property {function} set - Function to update the memory\n * @property {function} get - Function to get the memory\n */\n\n/**\n * @typedef {object} CortexParams\n * @property {object} memory - The initial state\n * @property {function(function, function): object} synapses - The synapses function\n */\n\n/**\n * The Cortex class manages the state of the application.\n */\nexport class Cortex {\n /**\n * Creates an instance of Cortex.\n * @param {CortexParams} CortexParams - The parameters for the Cortex.\n */\n constructor({ memory, synapses }) {\n this._memory = memory;\n this._listeners = new Set();\n\n const get = () => this._memory;\n\n const set = (updater) => {\n let nextState;\n if (typeof updater === \"function\") {\n const clone = structuredClone(this._memory);\n const result = updater(clone);\n nextState = result || clone;\n } else {\n nextState = { ...this._memory, ...updater };\n }\n\n this._memory = nextState;\n this._listeners.forEach((render) => render());\n };\n\n this.synapses = synapses(set, get);\n }\n\n /**\n * Get the memory and register the current observer.\n * @returns {object} The current state\n */\n get memory() {\n const currentObserver = getObserver();\n if (currentObserver) this._listeners.add(currentObserver);\n return this._memory;\n }\n}\n","/**\n * @file Runtime Scoped CSS implementation using Native CSS Nesting.\n * @module css\n */\n\nlet styleSheet = null;\nconst cache = new Set();\n\n/**\n * Simple DJB2 hashing function.\n */\nfunction hashString(str) {\n let hash = 5381;\n let i = str.length;\n while (i) {\n hash = (hash * 33) ^ str.charCodeAt(--i);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Lightweight Runtime Minifier.\n * Removes comments and collapses whitespace.\n * We do not strip spaces around colons/brackets to ensure safety for calc().\n */\nfunction minify(css) {\n return css\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\") // Remove comments\n .replace(/\\s+/g, \" \") // Collapse newlines/tabs to single space\n .trim(); // Remove leading/trailing\n}\n\n/**\n * Scoped CSS Tag.\n * Wraps content in a unique class using Native CSS Nesting.\n */\nexport function css(strings, ...args) {\n const raw = strings.reduce((acc, str, i) => {\n return acc + str + (args[i] || \"\");\n }, \"\");\n\n const content = minify(raw);\n\n if (!content) return \"\";\n\n const hash = hashString(content);\n const className = `humn-${hash}`;\n\n if (cache.has(hash)) {\n return className;\n }\n\n if (!styleSheet) {\n styleSheet = document.createElement(\"style\");\n styleSheet.id = \"humn-styles\";\n document.head.appendChild(styleSheet);\n }\n\n styleSheet.textContent += `.${className} { \n ${content} \n }\\n`;\n cache.add(hash);\n\n return className;\n}\n","/**\n * @typedef {object} VNode\n * @property {string} tag\n * @property {object} props\n * @property {VNode[]} children\n */\n\n/**\n * Creates a virtual DOM node.\n * This is a hyperscript-like function.\n *\n * @param {string} tag - The tag name of the element.\n * @param {object} props - The properties of the element.\n * @param {VNode[]|VNode} children - The children of the element.\n * @returns {VNode} The virtual DOM node.\n */\nexport const h = (tag, props = {}, children = []) => {\n const childArray = Array.isArray(children) ? children : [children];\n\n // Filter out null/false so we don't have \"ghost\" nodes\n const cleanChildren = childArray\n .flat() \n .filter(c => c !== null && c !== undefined && c !== false && c !== '');\n\n return {\n tag,\n props,\n children: cleanChildren\n };\n};\n","/**\n * @file Lifecycle hooks for components.\n * @module lifecycle\n */\nimport { getInstance } from \"./observer.js\";\n\n/**\n * Registers a callback to run after the component mounts.\n * @param {function} fn - The callback function.\n */\nexport function onMount(fn) {\n const instance = getInstance();\n if (instance) {\n instance.mounts.push(fn);\n }\n}\n\n/**\n * Registers a callback to run when the component unmounts.\n * @param {function} fn - The callback function.\n */\nexport function onCleanup(fn) {\n const instance = getInstance();\n if (instance) {\n instance.cleanups.push(fn);\n }\n}\n","/**\n * @file This file contains the diffing and patching algorithm for the virtual DOM,\n * including support for Keyed Diffing.\n * @module patch\n */\nimport { setInstance } from \"./observer.js\";\n\n/**\n * Checks if a list of children contains keys.\n * @param {Array<import(\"./h\").VNode>} children - The list of VNodes.\n * @returns {boolean} True if keys are present.\n */\nexport function hasKeys(children) {\n return children && children.some((c) => c && c.props && c.props.key != null);\n}\n\n/**\n * Creates a real DOM element from a virtual node.\n * @param {import(\"./h\").VNode | string | number} vNode - The virtual node.\n * @returns {Text | HTMLElement} The created DOM element.\n */\nfunction createElement(vNode) {\n if (typeof vNode === \"string\" || typeof vNode === \"number\") {\n return document.createTextNode(String(vNode));\n }\n\n if (typeof vNode.tag === \"function\") {\n const childVNode = renderComponent(vNode);\n vNode.child = childVNode;\n\n // Recursively create the DOM for the child\n const el = createElement(childVNode);\n vNode.el = el;\n\n // Queue Mount Hooks\n if (vNode.hooks && vNode.hooks.mounts.length > 0) {\n setTimeout(() => vNode.hooks.mounts.forEach((fn) => fn()), 0);\n }\n return el;\n }\n\n const el = document.createElement(vNode.tag);\n vNode.el = el;\n patchProps(el, vNode.props);\n\n vNode.children.forEach((child) => {\n el.appendChild(createElement(child));\n });\n\n return el;\n}\n\n/**\n * Updates the properties (attributes/events) of a DOM element.\n * @param {HTMLElement} el - The DOM element to update.\n * @param {object} [newProps={}] - The new properties.\n * @param {object} [oldProps={}] - The old properties.\n */\nfunction patchProps(el, newProps = {}, oldProps = {}) {\n if (!el) return;\n\n const allProps = { ...oldProps, ...newProps };\n\n for (const key in allProps) {\n const oldValue = oldProps[key];\n const newValue = newProps[key];\n\n // Handle removed props\n if (newValue === undefined || newValue === null) {\n el.removeAttribute(key);\n continue;\n }\n\n // We check against the LIVE DOM value to prevent cursor jumping\n if (key === \"value\" || key === \"checked\") {\n if (el[key] !== newValue) {\n el[key] = newValue;\n }\n continue;\n }\n\n // If prop hasn't changed, skip\n if (oldValue === newValue) continue;\n\n // Handle Events\n if (key.startsWith(\"on\")) {\n const eventName = key.slice(2).toLowerCase();\n if (oldValue) el.removeEventListener(eventName, oldValue);\n el.addEventListener(eventName, newValue);\n }\n // Handle the disabled attribute\n if (key === \"disabled\") {\n el.disabled = newValue === true || newValue === \"true\";\n }\n // Handle standard attributes\n else {\n el.setAttribute(key, newValue);\n }\n }\n}\n\n/**\n * Reconciles the children of a node, handling both simple lists and keyed reordering.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {Array<import(\"./h\").VNode>} newChildren - The new list of children.\n * @param {Array<import(\"./h\").VNode>} oldChildren - The old list of children.\n */\nfunction reconcileChildren(parent, newChildren, oldChildren) {\n const isKeyed = hasKeys(newChildren) || hasKeys(oldChildren);\n\n // If no keys are used, use the fast index-based simple loop.\n // This is faster for static lists or simple text replacements.\n if (!isKeyed) {\n const maxLen = Math.max(newChildren.length, oldChildren.length);\n for (let i = 0; i < maxLen; i++) {\n patch(parent, newChildren[i], oldChildren[i], i);\n }\n return;\n }\n\n // Keyed Diffing\n // Map existing children by Key\n const keyed = {};\n oldChildren.forEach((child, i) => {\n const key = (child.props && child.props.key) != null ? child.props.key : i;\n keyed[key] = { vNode: child, index: i };\n });\n\n newChildren.forEach((newChild, i) => {\n const key =\n (newChild.props && newChild.props.key) != null ? newChild.props.key : i;\n const oldItem = keyed[key];\n\n if (oldItem) {\n // A. MATCH FOUND\n const oldVNode = oldItem.vNode;\n\n // Update the node's content (Recursion)\n patch(parent, newChild, oldVNode, i);\n\n // If the DOM node isn't in the right spot, move it.\n // We use oldVNode.el because patch transfers the ref, but just to be safe:\n const el = newChild.el || oldVNode.el;\n\n // Get the node currently at this index in the real DOM\n const domChildAtIndex = parent.childNodes[i];\n\n // If the element exists but is in the wrong place, move it\n if (el && domChildAtIndex !== el) {\n parent.insertBefore(el, domChildAtIndex);\n }\n\n // Remove from map so we know it was re-used\n delete keyed[key];\n } else {\n // B. NO MATCH (New Item)\n const newEl = createElement(newChild);\n const domChildAtIndex = parent.childNodes[i];\n\n if (domChildAtIndex) {\n parent.insertBefore(newEl, domChildAtIndex);\n } else {\n parent.appendChild(newEl);\n }\n }\n });\n\n // Remove any old keys that weren't used in the new list\n Object.values(keyed).forEach(({ vNode }) => {\n if (vNode.el && vNode.el.parentNode === parent) {\n parent.removeChild(vNode.el);\n }\n });\n}\n\n/**\n * Executes a Functional Component, tracks hooks, and returns the VNode.\n * @param {import(\"./h\").VNode} vNode - The component vNode.\n * @returns {import(\"./h\").VNode} The rendered child vNode.\n */\nfunction renderComponent(vNode) {\n // 1. Prepare Hook Container\n const hooks = {\n mounts: [],\n cleanups: [],\n };\n\n // 2. Set Global Scope\n setInstance(hooks);\n\n // 3. Run the User's Component Function\n // We pass props as the first argument\n const renderedVNode = vNode.tag(vNode.props);\n\n // 4. Clear Global Scope\n setInstance(null);\n\n // 5. Attach hooks to the VNode so we can run them later\n vNode.hooks = hooks;\n\n return renderedVNode;\n}\n\n/**\n * Helper to recursively run cleanup hooks when a tree is removed.\n * @param {import(\"./h\").VNode} vNode - The vNode to unmount.\n */\nfunction runUnmount(vNode) {\n if (!vNode) return;\n\n // 1. Run hooks for this node\n if (vNode.hooks && vNode.hooks.cleanups) {\n vNode.hooks.cleanups.forEach((fn) => fn());\n }\n\n // 2. Recurse into child (if component)\n if (vNode.child) {\n runUnmount(vNode.child);\n }\n\n // 3. Recurse into children (if element)\n if (vNode.children) {\n vNode.children.forEach(runUnmount);\n }\n}\n\n/**\n * The main diffing function. Compares V-DOM trees and updates the real DOM.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {import(\"./h\").VNode | string | number} newVNode - The new virtual node.\n * @param {import(\"./h\").VNode | string | number} oldVNode - The old virtual node.\n * @param {number} [index=0] - The index of the child node (used for simple diffing).\n */\nexport function patch(parent, newVNode, oldVNode, index = 0) {\n // --- HANDLE UNMOUNTING (Cleanup Hooks) ---\n if (newVNode === undefined || newVNode === null) {\n const el = oldVNode.el || parent.childNodes[index];\n\n // Recursive Cleanup\n runUnmount(oldVNode);\n\n if (el) parent.removeChild(el);\n return;\n }\n\n // --- HANDLE COMPONENT (Functional VNode) ---\n if (typeof newVNode.tag === \"function\") {\n const isNew = !oldVNode;\n\n // 1. Render the component function\n const childVNode = renderComponent(newVNode);\n\n // 2. Store the result in the vNode (\"unwrap\" it)\n newVNode.child = childVNode;\n\n // 3. Recursively patch the result\n const oldChild = oldVNode ? oldVNode.child : undefined;\n patch(parent, childVNode, oldChild, index);\n\n // 4. Ensure VNode holds the DOM reference\n newVNode.el = childVNode.el;\n\n // 5. Run Mount Hooks (Next Tick)\n if (isNew && newVNode.hooks && newVNode.hooks.mounts.length > 0) {\n setTimeout(() => {\n newVNode.hooks.mounts.forEach((fn) => fn());\n }, 0);\n }\n // TODO: Handle updates (running old cleanups if necessary) for Phase 2\n return;\n }\n\n // Start - No old node? Create new.\n if (oldVNode === undefined || oldVNode === null) {\n parent.appendChild(createElement(newVNode));\n return;\n }\n\n // Removal - No new node? Remove old.\n if (newVNode === undefined || newVNode === null) {\n // Try to find the element on the VNode, or fallback to index\n const el = oldVNode.el || parent.childNodes[index];\n if (el) parent.removeChild(el);\n return;\n }\n\n // Changed Type - (e.g. <div> becomes <span>) -> Replace whole node\n if (\n typeof newVNode !== typeof oldVNode ||\n (typeof newVNode !== \"string\" && newVNode.tag !== oldVNode.tag)\n ) {\n const el = oldVNode.el || parent.childNodes[index];\n if (el) parent.replaceChild(createElement(newVNode), el);\n return;\n }\n\n // Text Update\n if (typeof newVNode === \"string\" || typeof newVNode === \"number\") {\n if (newVNode !== oldVNode) {\n const el = parent.childNodes[index];\n if (el) {\n el.nodeValue = String(newVNode);\n } else {\n // Self healing: if text node missing, append it\n parent.appendChild(document.createTextNode(String(newVNode)));\n }\n }\n return;\n }\n\n // Same Tag - Update Props & Children\n const el = oldVNode.el || parent.childNodes[index];\n\n if (!el) return;\n\n // Transfer DOM reference to the new VNode\n newVNode.el = el;\n\n patchProps(el, newVNode.props, oldVNode.props);\n\n reconcileChildren(el, newVNode.children, oldVNode.children);\n}\n","/**\n * @file Mounts the application to the DOM.\n * @module mount\n */\nimport { setObserver } from \"./observer.js\";\nimport { patch } from \"./patch.js\";\n\n/**\n * Mounts a component to a target DOM element.\n * @param {HTMLElement} target - The DOM element to mount to.\n * @param {function} Component - The root component function.\n */\nexport const mount = (target, Component) => {\n let prevVNode = null;\n\n const lifecycle = () => {\n setObserver(lifecycle);\n\n const nextVNode = {\n tag: Component,\n props: {},\n children: [],\n };\n\n patch(target, nextVNode, prevVNode);\n setObserver(null);\n prevVNode = nextVNode;\n };\n\n lifecycle();\n};\n"],"names":["currentObserver","currentInstance","getObserver","setObserver","obs","getInstance","setInstance","inst","Cortex","memory","synapses","get","set","updater","nextState","clone","render","styleSheet","cache","hashString","str","hash","i","minify","css","strings","args","raw","acc","content","className","h","tag","props","children","cleanChildren","c","onMount","fn","instance","onCleanup","hasKeys","createElement","vNode","childVNode","renderComponent","el","patchProps","child","newProps","oldProps","allProps","key","oldValue","newValue","eventName","reconcileChildren","parent","newChildren","oldChildren","maxLen","patch","keyed","newChild","oldItem","oldVNode","domChildAtIndex","newEl","hooks","renderedVNode","runUnmount","newVNode","index","isNew","oldChild","mount","target","Component","prevVNode","lifecycle","nextVNode"],"mappings":"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"}
1
+ {"version":3,"file":"humn.js","sources":["../src/observer.js","../src/cortex.js","../src/css.js","../src/h.js","../src/lifecycle.js","../src/patch.js","../src/mount.js","../src/persist.js"],"sourcesContent":["/**\n * @file Observer module for tracking global state during rendering.\n * @module observer\n */\n\nlet currentObserver = null // For Cortex/State dependency\nlet currentInstance = null // For Lifecycle Hooks\n\n/**\n * Gets the current observer (render function).\n * @returns {function|null}\n */\nexport const getObserver = () => currentObserver\n\n/**\n * Sets the current observer.\n * @param {function|null} obs\n */\nexport const setObserver = (obs) => {\n currentObserver = obs\n}\n\n/**\n * Gets the current component instance (hook container).\n * @returns {object|null}\n */\nexport const getInstance = () => currentInstance\n\n/**\n * Sets the current component instance.\n * @param {object|null} inst\n */\nexport const setInstance = (inst) => {\n currentInstance = inst\n}\n","import { isDev } from './metrics.js'\nimport { getObserver } from './observer.js'\n\n/**\n * @typedef {object} Synapses\n * @property {function} set - Function to update the memory\n * @property {function} get - Function to get the memory\n */\n\n/**\n * @typedef {object} CortexParams\n * @property {object} memory - The initial state\n * @property {function(function, function): object} synapses - The synapses function\n */\n\n/**\n * The Cortex class manages the state of the application.\n * This uses a Proxy for fine-grained reactivity, ensuring only those components\n * which use the updated value get re-rendered.\n */\nexport class Cortex {\n /**\n * Creates an instance of Cortex.\n * @param {CortexParams} CortexParams - The parameters for the Cortex.\n */\n constructor({ memory, synapses }) {\n const liveMemory = { ...memory }\n this._persistenceMap = new Map()\n\n // Load in any existing values from local-storage\n for (const [key, value] of Object.entries(memory)) {\n if (value && value.__humn_persist) {\n const storageKey = value.config.key || key\n this._persistenceMap.set(key, storageKey)\n\n try {\n const stored = localStorage.getItem(storageKey)\n if (stored !== null) {\n liveMemory[key] = JSON.parse(stored)\n } else {\n liveMemory[key] = value.initial\n }\n } catch (err) {\n if (isDev)\n console.warn(`Humn: Failed to load '${key}' from storage.`, err)\n liveMemory[key] = value.initial\n }\n }\n }\n\n this._memory = liveMemory\n this._listeners = new Map()\n\n const get = () => this._memory\n\n const set = (updater) => {\n let nextState\n let changedPaths = new Set()\n\n if (typeof updater === 'function') {\n const clone = structuredClone(this._memory)\n const proxy = this._createChangeTrackingProxy(clone, changedPaths)\n const result = updater(proxy)\n\n if (result && typeof result === 'object') {\n nextState = { ...this._memory, ...result }\n Object.keys(result).forEach((key) => changedPaths.add(key))\n } else {\n nextState = clone\n }\n } else {\n nextState = { ...this._memory, ...updater }\n changedPaths = new Set(Object.keys(updater))\n }\n\n this._memory = nextState\n\n // If we need to persist any of the values\n // we save them to localStorage here\n if (this._persistenceMap.size > 0) {\n this._persistenceMap.forEach((storageKey, stateKey) => {\n const isDirty = Array.from(changedPaths).some(\n (path) => path === stateKey || path.startsWith(stateKey + '.'),\n )\n\n if (isDirty) {\n try {\n const value = this._memory[stateKey]\n localStorage.setItem(storageKey, JSON.stringify(value))\n } catch (err) {\n if (isDev)\n console.error(`Humn: Failed to save '${stateKey}'.`, err)\n }\n }\n })\n }\n\n this._notifyRelevantListeners(changedPaths)\n }\n\n this.synapses = synapses(set, get)\n }\n\n /**\n * Creates a Proxy that tracks which properties are being mutated.\n * Includes a GET trap to recursively proxy nested objects for deep mutation tracking.\n */\n _createChangeTrackingProxy(obj, changedPaths, path = '') {\n return new Proxy(obj, {\n get: (target, prop) => {\n if (typeof prop === 'symbol' || prop === '__proto__')\n return target[prop]\n\n const value = target[prop]\n const fullPath = path ? `${path}.${prop}` : prop\n\n // Recursively proxy nested objects so we can trap their sets too\n if (typeof value === 'object' && value !== null) {\n return this._createChangeTrackingProxy(value, changedPaths, fullPath)\n }\n return value\n },\n set: (target, prop, value) => {\n if (typeof prop === 'symbol' || prop === '__proto__') {\n target[prop] = value\n return true\n }\n\n const fullPath = path ? `${path}.${prop}` : prop\n changedPaths.add(fullPath)\n\n target[prop] = value\n return true\n },\n })\n }\n\n /**\n * Only notify listeners that read properties which changed\n */\n _notifyRelevantListeners(changedPaths) {\n this._listeners.forEach((accessedPaths, renderFn) => {\n const shouldNotify = Array.from(accessedPaths).some((accessedPath) => {\n return Array.from(changedPaths).some((changedPath) => {\n // Check for exact match or parent/child relationship\n return (\n accessedPath === changedPath ||\n accessedPath.startsWith(changedPath + '.') ||\n changedPath.startsWith(accessedPath + '.')\n )\n })\n })\n\n if (shouldNotify) renderFn()\n })\n }\n\n /**\n * Creates a Proxy that tracks which properties are accessed during render\n */\n _createAccessTrackingProxy(obj, accessedPaths, path = '') {\n if (typeof obj !== 'object' || obj === null) return obj\n\n return new Proxy(obj, {\n get: (target, prop) => {\n // We don't care about prototype and symbol properties\n if (typeof prop === 'symbol' || prop === '__proto__')\n return target[prop]\n\n const fullPath = path ? `${path}.${prop}` : prop\n accessedPaths.add(fullPath)\n\n const value = target[prop]\n\n // Recursively wrap nested objects\n if (typeof value === 'object' && value !== null)\n return this._createAccessTrackingProxy(value, accessedPaths, fullPath)\n\n return value\n },\n })\n }\n\n /**\n * Returns memory wrapped in a tracking Proxy\n */\n get memory() {\n const currentObserver = getObserver()\n\n if (!currentObserver) return this._memory\n\n if (!this._listeners.has(currentObserver))\n this._listeners.set(currentObserver, new Set())\n\n const accessedPaths = this._listeners.get(currentObserver)\n\n // This gives us fresh tracking each render\n accessedPaths.clear()\n\n return this._createAccessTrackingProxy(this._memory, accessedPaths)\n }\n}\n","/**\n * @file Runtime Scoped CSS implementation using Native CSS Nesting.\n * @module css\n */\n\nlet styleSheet = null\nconst cache = new Set()\n\n/**\n * Simple DJB2 hashing function.\n */\nfunction hashString(str) {\n let hash = 5381\n let i = str.length\n while (i) {\n hash = (hash * 33) ^ str.charCodeAt(--i)\n }\n return (hash >>> 0).toString(36)\n}\n\n/**\n * Lightweight Runtime Minifier.\n * Removes comments and collapses whitespace.\n * We do not strip spaces around colons/brackets to ensure safety for calc().\n */\nfunction minify(css) {\n return css\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove comments\n .replace(/\\s+/g, ' ') // Collapse newlines/tabs to single space\n .trim() // Remove leading/trailing\n}\n\n/**\n * Scoped CSS Tag.\n * Wraps content in a unique class using Native CSS Nesting.\n */\nexport function css(strings, ...args) {\n const raw = strings.reduce((acc, str, i) => {\n return acc + str + (args[i] || '')\n }, '')\n\n const content = minify(raw)\n\n if (!content) return ''\n\n const hash = hashString(content)\n const className = `humn-${hash}`\n\n if (cache.has(hash)) {\n return className\n }\n\n if (!styleSheet) {\n styleSheet = document.createElement('style')\n styleSheet.id = 'humn-styles'\n document.head.appendChild(styleSheet)\n }\n\n styleSheet.textContent += `.${className} { \n ${content} \n }\\n`\n cache.add(hash)\n\n return className\n}\n","/**\n * @typedef {object} VNode\n * @property {string} tag\n * @property {object} props\n * @property {VNode[]} children\n */\n\n/**\n * Creates a virtual DOM node.\n * This is a hyperscript-like function.\n *\n * @param {string} tag - The tag name of the element.\n * @param {object} props - The properties of the element.\n * @param {VNode[]|VNode} children - The children of the element.\n * @returns {VNode} The virtual DOM node.\n */\nexport const h = (tag, props = {}, children = []) => {\n const childArray = Array.isArray(children) ? children : [children]\n\n // Filter out null/false so we don't have \"ghost\" nodes\n const cleanChildren = childArray\n .flat()\n .filter((c) => c !== null && c !== undefined && c !== false && c !== '')\n\n return {\n tag,\n props,\n children: cleanChildren,\n }\n}\n","/**\n * @file Lifecycle hooks for components.\n * @module lifecycle\n */\nimport { getInstance } from './observer.js'\n\n/**\n * Registers a callback to run after the component mounts.\n * @param {function} fn - The callback function.\n */\nexport function onMount(fn) {\n const instance = getInstance()\n if (instance) {\n instance.mounts.push(fn)\n }\n}\n\n/**\n * Registers a callback to run when the component unmounts.\n * @param {function} fn - The callback function.\n */\nexport function onCleanup(fn) {\n const instance = getInstance()\n if (instance) {\n instance.cleanups.push(fn)\n }\n}\n","/**\n * @file This file contains the diffing and patching algorithm for the virtual DOM,\n * including support for Keyed Diffing.\n * @module patch\n */\nimport { track } from './metrics.js'\nimport { setInstance } from './observer.js'\n\n/**\n * Checks if a list of children contains keys.\n * @param {Array<import(\"./h\").VNode>} children - The list of VNodes.\n * @returns {boolean} True if keys are present.\n */\nexport function hasKeys(children) {\n return children && children.some((c) => c && c.props && c.props.key != null)\n}\n\n/**\n * Creates a real DOM element from a virtual node.\n * @param {import(\"./h\").VNode | string | number} vNode - The virtual node.\n * @returns {Text | HTMLElement} The created DOM element.\n */\nfunction createElement(vNode) {\n if (typeof vNode === 'string' || typeof vNode === 'number') {\n return document.createTextNode(String(vNode))\n }\n\n if (typeof vNode.tag === 'function') {\n const childVNode = renderComponent(vNode)\n vNode.child = childVNode\n\n // Recursively create the DOM for the child\n const el = createElement(childVNode)\n vNode.el = el\n\n // Queue Mount Hooks\n if (vNode.hooks && vNode.hooks.mounts.length > 0) {\n setTimeout(() => vNode.hooks.mounts.forEach((fn) => fn()), 0)\n }\n return el\n }\n\n track('elementsCreated')\n\n const el = document.createElement(vNode.tag)\n vNode.el = el\n patchProps(el, vNode.props)\n\n vNode.children.forEach((child) => {\n el.appendChild(createElement(child))\n })\n\n return el\n}\n\n/**\n * Updates the properties (attributes/events) of a DOM element.\n * @param {HTMLElement} el - The DOM element to update.\n * @param {object} [newProps={}] - The new properties.\n * @param {object} [oldProps={}] - The old properties.\n */\nfunction patchProps(el, newProps = {}, oldProps = {}) {\n if (!el) return\n\n const allProps = { ...oldProps, ...newProps }\n\n for (const key in allProps) {\n const oldValue = oldProps[key]\n const newValue = newProps[key]\n\n // Handle removed props\n if (newValue === undefined || newValue === null) {\n el.removeAttribute(key)\n track('patches')\n continue\n }\n\n // We check against the LIVE DOM value to prevent cursor jumping\n if (key === 'value' || key === 'checked') {\n if (el[key] !== newValue) {\n el[key] = newValue\n track('patches')\n }\n continue\n }\n\n // If prop hasn't changed, skip\n if (oldValue === newValue) continue\n\n track('patches')\n\n // Handle Events\n if (key.startsWith('on')) {\n const eventName = key.slice(2).toLowerCase()\n if (oldValue) el.removeEventListener(eventName, oldValue)\n el.addEventListener(eventName, newValue)\n }\n // Handle the disabled attribute\n if (key === 'disabled') {\n el.disabled = newValue === true || newValue === 'true'\n }\n // Handle standard attributes\n else {\n el.setAttribute(key, newValue)\n }\n }\n}\n\n/**\n * Reconciles the children of a node, handling both simple lists and keyed reordering.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {Array<import(\"./h\").VNode>} newChildren - The new list of children.\n * @param {Array<import(\"./h\").VNode>} oldChildren - The old list of children.\n */\nfunction reconcileChildren(parent, newChildren, oldChildren) {\n const isKeyed = hasKeys(newChildren) || hasKeys(oldChildren)\n\n // If no keys are used, use the fast index-based simple loop.\n // This is faster for static lists or simple text replacements.\n if (!isKeyed) {\n const maxLen = Math.max(newChildren.length, oldChildren.length)\n for (let i = 0; i < maxLen; i++) {\n patch(parent, newChildren[i], oldChildren[i], i)\n }\n return\n }\n\n // Keyed Diffing\n // Map existing children by Key\n const keyed = {}\n oldChildren.forEach((child, i) => {\n const key = (child.props && child.props.key) != null ? child.props.key : i\n keyed[key] = { vNode: child, index: i }\n })\n\n newChildren.forEach((newChild, i) => {\n const key =\n (newChild.props && newChild.props.key) != null ? newChild.props.key : i\n const oldItem = keyed[key]\n\n if (oldItem) {\n // A. MATCH FOUND\n const oldVNode = oldItem.vNode\n\n // Update the node's content (Recursion)\n patch(parent, newChild, oldVNode, i)\n\n // If the DOM node isn't in the right spot, move it.\n // We use oldVNode.el because patch transfers the ref, but just to be safe:\n const el = newChild.el || oldVNode.el\n\n // Get the node currently at this index in the real DOM\n const domChildAtIndex = parent.childNodes[i]\n\n // If the element exists but is in the wrong place, move it\n if (el && domChildAtIndex !== el) {\n parent.insertBefore(el, domChildAtIndex)\n track('patches')\n }\n\n // Remove from map so we know it was re-used\n delete keyed[key]\n } else {\n // B. NO MATCH (New Item)\n const newEl = createElement(newChild)\n const domChildAtIndex = parent.childNodes[i]\n\n if (domChildAtIndex) {\n parent.insertBefore(newEl, domChildAtIndex)\n } else {\n parent.appendChild(newEl)\n }\n }\n })\n\n // Remove any old keys that weren't used in the new list\n Object.values(keyed).forEach(({ vNode }) => {\n if (vNode.el && vNode.el.parentNode === parent) {\n runUnmount(vNode) // Clean up hooks\n parent.removeChild(vNode.el)\n track('elementsRemoved')\n }\n })\n}\n\n/**\n * Executes a Functional Component, tracks hooks, and returns the VNode.\n * @param {import(\"./h\").VNode} vNode - The component vNode.\n * @returns {import(\"./h\").VNode} The rendered child vNode.\n */\nfunction renderComponent(vNode) {\n track('componentsRendered')\n\n // 1. Prepare Hook Container\n const hooks = {\n mounts: [],\n cleanups: [],\n }\n\n // 2. Set Global Scope\n setInstance(hooks)\n\n // 3. Run the User's Component Function\n // We pass props as the first argument\n const renderedVNode = vNode.tag(vNode.props)\n\n // 4. Clear Global Scope\n setInstance(null)\n\n // 5. Attach hooks to the VNode so we can run them later\n vNode.hooks = hooks\n\n return renderedVNode\n}\n\n/**\n * Helper to recursively run cleanup hooks when a tree is removed.\n * @param {import(\"./h\").VNode} vNode - The vNode to unmount.\n */\nfunction runUnmount(vNode) {\n if (!vNode) return\n\n // 1. Run hooks for this node\n if (vNode.hooks && vNode.hooks.cleanups) {\n vNode.hooks.cleanups.forEach((fn) => fn())\n }\n\n // 2. Recurse into child (if component)\n if (vNode.child) {\n runUnmount(vNode.child)\n }\n\n // 3. Recurse into children (if element)\n if (vNode.children) {\n vNode.children.forEach(runUnmount)\n }\n}\n\n/**\n * The main diffing function. Compares V-DOM trees and updates the real DOM.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {import(\"./h\").VNode | string | number} newVNode - The new virtual node.\n * @param {import(\"./h\").VNode | string | number} oldVNode - The old virtual node.\n * @param {number} [index=0] - The index of the child node (used for simple diffing).\n */\nexport function patch(parent, newVNode, oldVNode, index = 0) {\n track('diffs')\n\n if (newVNode === undefined || newVNode === null) {\n const el = oldVNode.el || parent.childNodes[index]\n\n // Recursive Cleanup\n runUnmount(oldVNode)\n\n if (el) {\n parent.removeChild(el)\n track('elementsRemoved')\n }\n return\n }\n\n if (typeof newVNode.tag === 'function') {\n const isNew = !oldVNode\n\n const childVNode = renderComponent(newVNode)\n newVNode.child = childVNode\n\n const oldChild = oldVNode ? oldVNode.child : undefined\n patch(parent, childVNode, oldChild, index)\n\n newVNode.el = childVNode.el\n\n // Run mount hooks on the next tick\n if (isNew && newVNode.hooks && newVNode.hooks.mounts.length > 0) {\n setTimeout(() => {\n newVNode.hooks.mounts.forEach((fn) => fn())\n }, 0)\n }\n // TODO: Handle updates (running old cleanups if necessary) for Phase 2\n return\n }\n\n // Start - No old node? Create new.\n if (oldVNode === undefined || oldVNode === null) {\n parent.appendChild(createElement(newVNode))\n return\n }\n\n // Removal - No new node? Remove old.\n if (newVNode === undefined || newVNode === null) {\n // Try to find the element on the VNode, or fallback to index\n const el = oldVNode.el || parent.childNodes[index]\n if (el) {\n parent.removeChild(el)\n track('elementsRemoved')\n }\n return\n }\n\n // Changed Type - (e.g. <div> becomes <span>) -> Replace whole node\n if (\n typeof newVNode !== typeof oldVNode ||\n (typeof newVNode !== 'string' && newVNode.tag !== oldVNode.tag)\n ) {\n const el = oldVNode.el || parent.childNodes[index]\n if (el) {\n parent.replaceChild(createElement(newVNode), el)\n track('patches')\n }\n return\n }\n\n // Text Update\n if (typeof newVNode === 'string' || typeof newVNode === 'number') {\n if (newVNode !== oldVNode) {\n const el = parent.childNodes[index]\n if (el) {\n el.nodeValue = String(newVNode)\n track('patches')\n } else {\n // Self healing: if text node missing, append it\n parent.appendChild(document.createTextNode(String(newVNode)))\n }\n }\n return\n }\n\n // Same Tag - Update Props & Children\n const el = oldVNode.el || parent.childNodes[index]\n\n if (!el) return\n\n // Transfer DOM reference to the new VNode\n newVNode.el = el\n\n patchProps(el, newVNode.props, oldVNode.props)\n\n reconcileChildren(el, newVNode.children, oldVNode.children)\n}\n","/**\n * @file Mounts the application to the DOM.\n * @module mount\n */\nimport { setObserver } from './observer.js'\nimport { patch } from './patch.js'\n\n/**\n * Mounts a component to a target DOM element.\n * @param {HTMLElement} target - The DOM element to mount to.\n * @param {function} Component - The root component function.\n */\nexport const mount = (target, Component) => {\n let prevVNode = null\n\n const lifecycle = () => {\n setObserver(lifecycle)\n\n const nextVNode = {\n tag: Component,\n props: {},\n children: [],\n }\n\n patch(target, nextVNode, prevVNode)\n setObserver(null)\n prevVNode = nextVNode\n }\n\n lifecycle()\n}\n","/**\n * @typedef {object} HumnPersist\n * @property {boolean} __humn_persist\n * @property {any} initial\n * @property {PersistConfig} config\n */\n\n/**\n * @typedef {object} PersistConfig\n * @property {string} key\n */\n\n/**\n * Marks a section of the state for persistence in localStorage.\n *\n * @param {any} initial - The initial value of the state.\n * @param {PersistConfig} config - The configuration for persistence.\n * @returns {HumnPersist}\n */\nexport const persist = (initial, config = {}) => ({\n __humn_persist: true,\n initial,\n config,\n})\n"],"names":["currentObserver","currentInstance","getObserver","setObserver","obs","getInstance","setInstance","inst","Cortex","constructor","memory","synapses","liveMemory","this","_persistenceMap","Map","key","value","Object","entries","__humn_persist","storageKey","config","set","stored","localStorage","getItem","JSON","parse","initial","err","_memory","_listeners","updater","nextState","changedPaths","Set","clone","structuredClone","result","_createChangeTrackingProxy","keys","forEach","add","size","stateKey","Array","from","some","path","startsWith","setItem","stringify","_notifyRelevantListeners","obj","Proxy","get","target","prop","fullPath","accessedPaths","renderFn","accessedPath","changedPath","_createAccessTrackingProxy","has","clear","styleSheet","cache","css","strings","args","content","replace","trim","reduce","acc","str","i","hash","length","charCodeAt","toString","className","document","createElement","id","head","appendChild","textContent","h","tag","props","children","isArray","flat","filter","c","onMount","fn","instance","mounts","push","onCleanup","cleanups","hasKeys","vNode","createTextNode","String","childVNode","renderComponent","child","el","hooks","setTimeout","patchProps","newProps","oldProps","allProps","oldValue","newValue","eventName","slice","toLowerCase","removeEventListener","addEventListener","disabled","setAttribute","removeAttribute","renderedVNode","runUnmount","patch","parent","newVNode","oldVNode","index","childNodes","removeChild","isNew","replaceChild","nodeValue","newChildren","oldChildren","maxLen","Math","max","keyed","newChild","oldItem","domChildAtIndex","insertBefore","newEl","values","parentNode","mount","Component","prevVNode","lifecycle","nextVNode","persist"],"mappings":"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"}
package/dist/humn.umd.js CHANGED
@@ -1,5 +1,5 @@
1
- (function(u,f){typeof exports=="object"&&typeof module<"u"?f(exports):typeof define=="function"&&define.amd?define(["exports"],f):(u=typeof globalThis<"u"?globalThis:u||self,f(u.Humn={}))})(this,(function(u){"use strict";let f=null,k=null;const I=()=>f,d=t=>{f=t},E=()=>k,b=t=>{k=t};class O{constructor({memory:e,synapses:s}){this._memory=e,this._listeners=new Set;const r=()=>this._memory,c=n=>{let i;if(typeof n=="function"){const o=structuredClone(this._memory);i=n(o)||o}else i={...this._memory,...n};this._memory=i,this._listeners.forEach(o=>o())};this.synapses=s(c,r)}get memory(){const e=I();return e&&this._listeners.add(e),this._memory}}let a=null;const C=new Set;function x(t){let e=5381,s=t.length;for(;s;)e=e*33^t.charCodeAt(--s);return(e>>>0).toString(36)}function L(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\s+/g," ").trim()}function M(t,...e){const s=t.reduce((i,o,l)=>i+o+(e[l]||""),""),r=L(s);if(!r)return"";const c=x(r),n=`humn-${c}`;return C.has(c)||(a||(a=document.createElement("style"),a.id="humn-styles",document.head.appendChild(a)),a.textContent+=`.${n} {
2
- ${r}
1
+ (function(h,f){typeof exports=="object"&&typeof module<"u"?f(exports):typeof define=="function"&&define.amd?define(["exports"],f):f((h=typeof globalThis<"u"?globalThis:h||self).Humn={})})(this,function(h){"use strict";let f=null,b=null;const w=()=>f,v=t=>{f=t},C=()=>b,x=t=>{b=t};let d=null;const E=new Set;function N(t){return t&&t.some(e=>e&&e.props&&e.props.key!=null)}function m(t){if(typeof t=="string"||typeof t=="number")return document.createTextNode(String(t));if(typeof t.tag=="function"){const s=T(t);t.child=s;const r=m(s);return t.el=r,t.hooks&&t.hooks.mounts.length>0&&setTimeout(()=>t.hooks.mounts.forEach(o=>o()),0),r}const e=document.createElement(t.tag);return t.el=e,S(e,t.props),t.children.forEach(s=>{e.appendChild(m(s))}),e}function S(t,e={},s={}){if(!t)return;const r={...s,...e};for(const o in r){const n=s[o],i=e[o];if(i!=null)if(o!=="value"&&o!=="checked"){if(n!==i){if(o.startsWith("on")){const c=o.slice(2).toLowerCase();n&&t.removeEventListener(c,n),t.addEventListener(c,i)}o==="disabled"?t.disabled=i===!0||i==="true":t.setAttribute(o,i)}}else t[o]!==i&&(t[o]=i);else t.removeAttribute(o)}}function T(t){const e={mounts:[],cleanups:[]};x(e);const s=t.tag(t.props);return x(null),t.hooks=e,s}function g(t){t&&(t.hooks&&t.hooks.cleanups&&t.hooks.cleanups.forEach(e=>e()),t.child&&g(t.child),t.children&&t.children.forEach(g))}function _(t,e,s,r=0){if(e==null){const n=s.el||t.childNodes[r];return g(s),void(n&&t.removeChild(n))}if(typeof e.tag=="function"){const n=!s,i=T(e);return e.child=i,_(t,i,s?s.child:void 0,r),e.el=i.el,void(n&&e.hooks&&e.hooks.mounts.length>0&&setTimeout(()=>{e.hooks.mounts.forEach(c=>c())},0))}if(s==null)return void t.appendChild(m(e));if(e==null){const n=s.el||t.childNodes[r];return void(n&&t.removeChild(n))}if(typeof e!=typeof s||typeof e!="string"&&e.tag!==s.tag){const n=s.el||t.childNodes[r];return void(n&&t.replaceChild(m(e),n))}if(typeof e=="string"||typeof e=="number"){if(e!==s){const n=t.childNodes[r];n?n.nodeValue=String(e):t.appendChild(document.createTextNode(String(e)))}return}const o=s.el||t.childNodes[r];o&&(e.el=o,S(o,e.props,s.props),(function(n,i,c){if(!N(i)&&!N(c)){const l=Math.max(i.length,c.length);for(let u=0;u<l;u++)_(n,i[u],c[u],u);return}const a={};c.forEach((l,u)=>{const k=(l.props&&l.props.key)!=null?l.props.key:u;a[k]={vNode:l,index:u}}),i.forEach((l,u)=>{const k=(l.props&&l.props.key)!=null?l.props.key:u,A=a[k];if(A){const y=A.vNode;_(n,l,y,u);const p=l.el||y.el,j=n.childNodes[u];p&&j!==p&&n.insertBefore(p,j),delete a[k]}else{const y=m(l),p=n.childNodes[u];p?n.insertBefore(y,p):n.appendChild(y)}}),Object.values(a).forEach(({vNode:l})=>{l.el&&l.el.parentNode===n&&(g(l),n.removeChild(l.el))})})(o,e.children,s.children))}h.Cortex=class{constructor({memory:t,synapses:e}){const s={...t};this._persistenceMap=new Map;for(const[r,o]of Object.entries(t))if(o&&o.__humn_persist){const n=o.config.key||r;this._persistenceMap.set(r,n);try{const i=localStorage.getItem(n);s[r]=i!==null?JSON.parse(i):o.initial}catch{s[r]=o.initial}}this._memory=s,this._listeners=new Map,this.synapses=e(r=>{let o,n=new Set;if(typeof r=="function"){const i=structuredClone(this._memory),c=r(this._createChangeTrackingProxy(i,n));c&&typeof c=="object"?(o={...this._memory,...c},Object.keys(c).forEach(a=>n.add(a))):o=i}else o={...this._memory,...r},n=new Set(Object.keys(r));this._memory=o,this._persistenceMap.size>0&&this._persistenceMap.forEach((i,c)=>{if(Array.from(n).some(a=>a===c||a.startsWith(c+".")))try{const a=this._memory[c];localStorage.setItem(i,JSON.stringify(a))}catch{}}),this._notifyRelevantListeners(n)},()=>this._memory)}_createChangeTrackingProxy(t,e,s=""){return new Proxy(t,{get:(r,o)=>{if(typeof o=="symbol"||o==="__proto__")return r[o];const n=r[o],i=s?`${s}.${o}`:o;return typeof n=="object"&&n!==null?this._createChangeTrackingProxy(n,e,i):n},set:(r,o,n)=>{if(typeof o=="symbol"||o==="__proto__")return r[o]=n,!0;const i=s?`${s}.${o}`:o;return e.add(i),r[o]=n,!0}})}_notifyRelevantListeners(t){this._listeners.forEach((e,s)=>{Array.from(e).some(r=>Array.from(t).some(o=>r===o||r.startsWith(o+".")||o.startsWith(r+".")))&&s()})}_createAccessTrackingProxy(t,e,s=""){return typeof t!="object"||t===null?t:new Proxy(t,{get:(r,o)=>{if(typeof o=="symbol"||o==="__proto__")return r[o];const n=s?`${s}.${o}`:o;e.add(n);const i=r[o];return typeof i=="object"&&i!==null?this._createAccessTrackingProxy(i,e,n):i}})}get memory(){const t=w();if(!t)return this._memory;this._listeners.has(t)||this._listeners.set(t,new Set);const e=this._listeners.get(t);return e.clear(),this._createAccessTrackingProxy(this._memory,e)}},h.css=function(t,...e){const s=(function(n){return n.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\s+/g," ").trim()})(t.reduce((n,i,c)=>n+i+(e[c]||""),""));if(!s)return"";const r=(function(n){let i=5381,c=n.length;for(;c;)i=33*i^n.charCodeAt(--c);return(i>>>0).toString(36)})(s),o=`humn-${r}`;return E.has(r)||(d||(d=document.createElement("style"),d.id="humn-styles",document.head.appendChild(d)),d.textContent+=`.${o} {
2
+ ${s}
3
3
  }
4
- `,C.add(c)),n}const j=(t,e={},s=[])=>{const c=(Array.isArray(s)?s:[s]).flat().filter(n=>n!=null&&n!==!1&&n!=="");return{tag:t,props:e,children:c}};function K(t){const e=E();e&&e.mounts.push(t)}function $(t){const e=E();e&&e.cleanups.push(t)}function S(t){return t&&t.some(e=>e&&e.props&&e.props.key!=null)}function m(t){if(typeof t=="string"||typeof t=="number")return document.createTextNode(String(t));if(typeof t.tag=="function"){const s=_(t);t.child=s;const r=m(s);return t.el=r,t.hooks&&t.hooks.mounts.length>0&&setTimeout(()=>t.hooks.mounts.forEach(c=>c()),0),r}const e=document.createElement(t.tag);return t.el=e,A(e,t.props),t.children.forEach(s=>{e.appendChild(m(s))}),e}function A(t,e={},s={}){if(!t)return;const r={...s,...e};for(const c in r){const n=s[c],i=e[c];if(i==null){t.removeAttribute(c);continue}if(c==="value"||c==="checked"){t[c]!==i&&(t[c]=i);continue}if(n!==i){if(c.startsWith("on")){const o=c.slice(2).toLowerCase();n&&t.removeEventListener(o,n),t.addEventListener(o,i)}c==="disabled"?t.disabled=i===!0||i==="true":t.setAttribute(c,i)}}}function B(t,e,s){if(!(S(e)||S(s))){const n=Math.max(e.length,s.length);for(let i=0;i<n;i++)y(t,e[i],s[i],i);return}const c={};s.forEach((n,i)=>{const o=(n.props&&n.props.key)!=null?n.props.key:i;c[o]={vNode:n,index:i}}),e.forEach((n,i)=>{const o=(n.props&&n.props.key)!=null?n.props.key:i,l=c[o];if(l){const p=l.vNode;y(t,n,p,i);const h=n.el||p.el,T=t.childNodes[i];h&&T!==h&&t.insertBefore(h,T),delete c[o]}else{const p=m(n),h=t.childNodes[i];h?t.insertBefore(p,h):t.appendChild(p)}}),Object.values(c).forEach(({vNode:n})=>{n.el&&n.el.parentNode===t&&t.removeChild(n.el)})}function _(t){const e={mounts:[],cleanups:[]};b(e);const s=t.tag(t.props);return b(null),t.hooks=e,s}function g(t){t&&(t.hooks&&t.hooks.cleanups&&t.hooks.cleanups.forEach(e=>e()),t.child&&g(t.child),t.children&&t.children.forEach(g))}function y(t,e,s,r=0){if(e==null){const n=s.el||t.childNodes[r];g(s),n&&t.removeChild(n);return}if(typeof e.tag=="function"){const n=!s,i=_(e);e.child=i;const o=s?s.child:void 0;y(t,i,o,r),e.el=i.el,n&&e.hooks&&e.hooks.mounts.length>0&&setTimeout(()=>{e.hooks.mounts.forEach(l=>l())},0);return}if(s==null){t.appendChild(m(e));return}if(e==null){const n=s.el||t.childNodes[r];n&&t.removeChild(n);return}if(typeof e!=typeof s||typeof e!="string"&&e.tag!==s.tag){const n=s.el||t.childNodes[r];n&&t.replaceChild(m(e),n);return}if(typeof e=="string"||typeof e=="number"){if(e!==s){const n=t.childNodes[r];n?n.nodeValue=String(e):t.appendChild(document.createTextNode(String(e)))}return}const c=s.el||t.childNodes[r];c&&(e.el=c,A(c,e.props,s.props),B(c,e.children,s.children))}const H=(t,e)=>{let s=null;const r=()=>{d(r);const c={tag:e,props:{},children:[]};y(t,c,s),d(null),s=c};r()};u.Cortex=O,u.css=M,u.h=j,u.mount=H,u.onCleanup=$,u.onMount=K,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})}));
4
+ `,E.add(r)),o},h.h=(t,e={},s=[])=>({tag:t,props:e,children:(Array.isArray(s)?s:[s]).flat().filter(r=>r!=null&&r!==!1&&r!=="")}),h.mount=(t,e)=>{let s=null;const r=()=>{v(r);const o={tag:e,props:{},children:[]};_(t,o,s),v(null),s=o};r()},h.onCleanup=function(t){const e=C();e&&e.cleanups.push(t)},h.onMount=function(t){const e=C();e&&e.mounts.push(t)},h.persist=(t,e={})=>({__humn_persist:!0,initial:t,config:e}),Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});
5
5
  //# sourceMappingURL=humn.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"humn.umd.js","sources":["../src/observer.js","../src/cortex.js","../src/css.js","../src/h.js","../src/lifecycle.js","../src/patch.js","../src/mount.js"],"sourcesContent":["/**\n * @file Observer module for tracking global state during rendering.\n * @module observer\n */\n\nlet currentObserver = null; // For Cortex/State dependency\nlet currentInstance = null; // For Lifecycle Hooks\n\n/**\n * Gets the current observer (render function).\n * @returns {function|null}\n */\nexport const getObserver = () => currentObserver;\n\n/**\n * Sets the current observer.\n * @param {function|null} obs\n */\nexport const setObserver = (obs) => {\n currentObserver = obs;\n};\n\n/**\n * Gets the current component instance (hook container).\n * @returns {object|null}\n */\nexport const getInstance = () => currentInstance;\n\n/**\n * Sets the current component instance.\n * @param {object|null} inst\n */\nexport const setInstance = (inst) => {\n currentInstance = inst;\n};\n","import { getObserver } from \"./observer.js\";\n\n/**\n * @typedef {object} Synapses\n * @property {function} set - Function to update the memory\n * @property {function} get - Function to get the memory\n */\n\n/**\n * @typedef {object} CortexParams\n * @property {object} memory - The initial state\n * @property {function(function, function): object} synapses - The synapses function\n */\n\n/**\n * The Cortex class manages the state of the application.\n */\nexport class Cortex {\n /**\n * Creates an instance of Cortex.\n * @param {CortexParams} CortexParams - The parameters for the Cortex.\n */\n constructor({ memory, synapses }) {\n this._memory = memory;\n this._listeners = new Set();\n\n const get = () => this._memory;\n\n const set = (updater) => {\n let nextState;\n if (typeof updater === \"function\") {\n const clone = structuredClone(this._memory);\n const result = updater(clone);\n nextState = result || clone;\n } else {\n nextState = { ...this._memory, ...updater };\n }\n\n this._memory = nextState;\n this._listeners.forEach((render) => render());\n };\n\n this.synapses = synapses(set, get);\n }\n\n /**\n * Get the memory and register the current observer.\n * @returns {object} The current state\n */\n get memory() {\n const currentObserver = getObserver();\n if (currentObserver) this._listeners.add(currentObserver);\n return this._memory;\n }\n}\n","/**\n * @file Runtime Scoped CSS implementation using Native CSS Nesting.\n * @module css\n */\n\nlet styleSheet = null;\nconst cache = new Set();\n\n/**\n * Simple DJB2 hashing function.\n */\nfunction hashString(str) {\n let hash = 5381;\n let i = str.length;\n while (i) {\n hash = (hash * 33) ^ str.charCodeAt(--i);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Lightweight Runtime Minifier.\n * Removes comments and collapses whitespace.\n * We do not strip spaces around colons/brackets to ensure safety for calc().\n */\nfunction minify(css) {\n return css\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\") // Remove comments\n .replace(/\\s+/g, \" \") // Collapse newlines/tabs to single space\n .trim(); // Remove leading/trailing\n}\n\n/**\n * Scoped CSS Tag.\n * Wraps content in a unique class using Native CSS Nesting.\n */\nexport function css(strings, ...args) {\n const raw = strings.reduce((acc, str, i) => {\n return acc + str + (args[i] || \"\");\n }, \"\");\n\n const content = minify(raw);\n\n if (!content) return \"\";\n\n const hash = hashString(content);\n const className = `humn-${hash}`;\n\n if (cache.has(hash)) {\n return className;\n }\n\n if (!styleSheet) {\n styleSheet = document.createElement(\"style\");\n styleSheet.id = \"humn-styles\";\n document.head.appendChild(styleSheet);\n }\n\n styleSheet.textContent += `.${className} { \n ${content} \n }\\n`;\n cache.add(hash);\n\n return className;\n}\n","/**\n * @typedef {object} VNode\n * @property {string} tag\n * @property {object} props\n * @property {VNode[]} children\n */\n\n/**\n * Creates a virtual DOM node.\n * This is a hyperscript-like function.\n *\n * @param {string} tag - The tag name of the element.\n * @param {object} props - The properties of the element.\n * @param {VNode[]|VNode} children - The children of the element.\n * @returns {VNode} The virtual DOM node.\n */\nexport const h = (tag, props = {}, children = []) => {\n const childArray = Array.isArray(children) ? children : [children];\n\n // Filter out null/false so we don't have \"ghost\" nodes\n const cleanChildren = childArray\n .flat() \n .filter(c => c !== null && c !== undefined && c !== false && c !== '');\n\n return {\n tag,\n props,\n children: cleanChildren\n };\n};\n","/**\n * @file Lifecycle hooks for components.\n * @module lifecycle\n */\nimport { getInstance } from \"./observer.js\";\n\n/**\n * Registers a callback to run after the component mounts.\n * @param {function} fn - The callback function.\n */\nexport function onMount(fn) {\n const instance = getInstance();\n if (instance) {\n instance.mounts.push(fn);\n }\n}\n\n/**\n * Registers a callback to run when the component unmounts.\n * @param {function} fn - The callback function.\n */\nexport function onCleanup(fn) {\n const instance = getInstance();\n if (instance) {\n instance.cleanups.push(fn);\n }\n}\n","/**\n * @file This file contains the diffing and patching algorithm for the virtual DOM,\n * including support for Keyed Diffing.\n * @module patch\n */\nimport { setInstance } from \"./observer.js\";\n\n/**\n * Checks if a list of children contains keys.\n * @param {Array<import(\"./h\").VNode>} children - The list of VNodes.\n * @returns {boolean} True if keys are present.\n */\nexport function hasKeys(children) {\n return children && children.some((c) => c && c.props && c.props.key != null);\n}\n\n/**\n * Creates a real DOM element from a virtual node.\n * @param {import(\"./h\").VNode | string | number} vNode - The virtual node.\n * @returns {Text | HTMLElement} The created DOM element.\n */\nfunction createElement(vNode) {\n if (typeof vNode === \"string\" || typeof vNode === \"number\") {\n return document.createTextNode(String(vNode));\n }\n\n if (typeof vNode.tag === \"function\") {\n const childVNode = renderComponent(vNode);\n vNode.child = childVNode;\n\n // Recursively create the DOM for the child\n const el = createElement(childVNode);\n vNode.el = el;\n\n // Queue Mount Hooks\n if (vNode.hooks && vNode.hooks.mounts.length > 0) {\n setTimeout(() => vNode.hooks.mounts.forEach((fn) => fn()), 0);\n }\n return el;\n }\n\n const el = document.createElement(vNode.tag);\n vNode.el = el;\n patchProps(el, vNode.props);\n\n vNode.children.forEach((child) => {\n el.appendChild(createElement(child));\n });\n\n return el;\n}\n\n/**\n * Updates the properties (attributes/events) of a DOM element.\n * @param {HTMLElement} el - The DOM element to update.\n * @param {object} [newProps={}] - The new properties.\n * @param {object} [oldProps={}] - The old properties.\n */\nfunction patchProps(el, newProps = {}, oldProps = {}) {\n if (!el) return;\n\n const allProps = { ...oldProps, ...newProps };\n\n for (const key in allProps) {\n const oldValue = oldProps[key];\n const newValue = newProps[key];\n\n // Handle removed props\n if (newValue === undefined || newValue === null) {\n el.removeAttribute(key);\n continue;\n }\n\n // We check against the LIVE DOM value to prevent cursor jumping\n if (key === \"value\" || key === \"checked\") {\n if (el[key] !== newValue) {\n el[key] = newValue;\n }\n continue;\n }\n\n // If prop hasn't changed, skip\n if (oldValue === newValue) continue;\n\n // Handle Events\n if (key.startsWith(\"on\")) {\n const eventName = key.slice(2).toLowerCase();\n if (oldValue) el.removeEventListener(eventName, oldValue);\n el.addEventListener(eventName, newValue);\n }\n // Handle the disabled attribute\n if (key === \"disabled\") {\n el.disabled = newValue === true || newValue === \"true\";\n }\n // Handle standard attributes\n else {\n el.setAttribute(key, newValue);\n }\n }\n}\n\n/**\n * Reconciles the children of a node, handling both simple lists and keyed reordering.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {Array<import(\"./h\").VNode>} newChildren - The new list of children.\n * @param {Array<import(\"./h\").VNode>} oldChildren - The old list of children.\n */\nfunction reconcileChildren(parent, newChildren, oldChildren) {\n const isKeyed = hasKeys(newChildren) || hasKeys(oldChildren);\n\n // If no keys are used, use the fast index-based simple loop.\n // This is faster for static lists or simple text replacements.\n if (!isKeyed) {\n const maxLen = Math.max(newChildren.length, oldChildren.length);\n for (let i = 0; i < maxLen; i++) {\n patch(parent, newChildren[i], oldChildren[i], i);\n }\n return;\n }\n\n // Keyed Diffing\n // Map existing children by Key\n const keyed = {};\n oldChildren.forEach((child, i) => {\n const key = (child.props && child.props.key) != null ? child.props.key : i;\n keyed[key] = { vNode: child, index: i };\n });\n\n newChildren.forEach((newChild, i) => {\n const key =\n (newChild.props && newChild.props.key) != null ? newChild.props.key : i;\n const oldItem = keyed[key];\n\n if (oldItem) {\n // A. MATCH FOUND\n const oldVNode = oldItem.vNode;\n\n // Update the node's content (Recursion)\n patch(parent, newChild, oldVNode, i);\n\n // If the DOM node isn't in the right spot, move it.\n // We use oldVNode.el because patch transfers the ref, but just to be safe:\n const el = newChild.el || oldVNode.el;\n\n // Get the node currently at this index in the real DOM\n const domChildAtIndex = parent.childNodes[i];\n\n // If the element exists but is in the wrong place, move it\n if (el && domChildAtIndex !== el) {\n parent.insertBefore(el, domChildAtIndex);\n }\n\n // Remove from map so we know it was re-used\n delete keyed[key];\n } else {\n // B. NO MATCH (New Item)\n const newEl = createElement(newChild);\n const domChildAtIndex = parent.childNodes[i];\n\n if (domChildAtIndex) {\n parent.insertBefore(newEl, domChildAtIndex);\n } else {\n parent.appendChild(newEl);\n }\n }\n });\n\n // Remove any old keys that weren't used in the new list\n Object.values(keyed).forEach(({ vNode }) => {\n if (vNode.el && vNode.el.parentNode === parent) {\n parent.removeChild(vNode.el);\n }\n });\n}\n\n/**\n * Executes a Functional Component, tracks hooks, and returns the VNode.\n * @param {import(\"./h\").VNode} vNode - The component vNode.\n * @returns {import(\"./h\").VNode} The rendered child vNode.\n */\nfunction renderComponent(vNode) {\n // 1. Prepare Hook Container\n const hooks = {\n mounts: [],\n cleanups: [],\n };\n\n // 2. Set Global Scope\n setInstance(hooks);\n\n // 3. Run the User's Component Function\n // We pass props as the first argument\n const renderedVNode = vNode.tag(vNode.props);\n\n // 4. Clear Global Scope\n setInstance(null);\n\n // 5. Attach hooks to the VNode so we can run them later\n vNode.hooks = hooks;\n\n return renderedVNode;\n}\n\n/**\n * Helper to recursively run cleanup hooks when a tree is removed.\n * @param {import(\"./h\").VNode} vNode - The vNode to unmount.\n */\nfunction runUnmount(vNode) {\n if (!vNode) return;\n\n // 1. Run hooks for this node\n if (vNode.hooks && vNode.hooks.cleanups) {\n vNode.hooks.cleanups.forEach((fn) => fn());\n }\n\n // 2. Recurse into child (if component)\n if (vNode.child) {\n runUnmount(vNode.child);\n }\n\n // 3. Recurse into children (if element)\n if (vNode.children) {\n vNode.children.forEach(runUnmount);\n }\n}\n\n/**\n * The main diffing function. Compares V-DOM trees and updates the real DOM.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {import(\"./h\").VNode | string | number} newVNode - The new virtual node.\n * @param {import(\"./h\").VNode | string | number} oldVNode - The old virtual node.\n * @param {number} [index=0] - The index of the child node (used for simple diffing).\n */\nexport function patch(parent, newVNode, oldVNode, index = 0) {\n // --- HANDLE UNMOUNTING (Cleanup Hooks) ---\n if (newVNode === undefined || newVNode === null) {\n const el = oldVNode.el || parent.childNodes[index];\n\n // Recursive Cleanup\n runUnmount(oldVNode);\n\n if (el) parent.removeChild(el);\n return;\n }\n\n // --- HANDLE COMPONENT (Functional VNode) ---\n if (typeof newVNode.tag === \"function\") {\n const isNew = !oldVNode;\n\n // 1. Render the component function\n const childVNode = renderComponent(newVNode);\n\n // 2. Store the result in the vNode (\"unwrap\" it)\n newVNode.child = childVNode;\n\n // 3. Recursively patch the result\n const oldChild = oldVNode ? oldVNode.child : undefined;\n patch(parent, childVNode, oldChild, index);\n\n // 4. Ensure VNode holds the DOM reference\n newVNode.el = childVNode.el;\n\n // 5. Run Mount Hooks (Next Tick)\n if (isNew && newVNode.hooks && newVNode.hooks.mounts.length > 0) {\n setTimeout(() => {\n newVNode.hooks.mounts.forEach((fn) => fn());\n }, 0);\n }\n // TODO: Handle updates (running old cleanups if necessary) for Phase 2\n return;\n }\n\n // Start - No old node? Create new.\n if (oldVNode === undefined || oldVNode === null) {\n parent.appendChild(createElement(newVNode));\n return;\n }\n\n // Removal - No new node? Remove old.\n if (newVNode === undefined || newVNode === null) {\n // Try to find the element on the VNode, or fallback to index\n const el = oldVNode.el || parent.childNodes[index];\n if (el) parent.removeChild(el);\n return;\n }\n\n // Changed Type - (e.g. <div> becomes <span>) -> Replace whole node\n if (\n typeof newVNode !== typeof oldVNode ||\n (typeof newVNode !== \"string\" && newVNode.tag !== oldVNode.tag)\n ) {\n const el = oldVNode.el || parent.childNodes[index];\n if (el) parent.replaceChild(createElement(newVNode), el);\n return;\n }\n\n // Text Update\n if (typeof newVNode === \"string\" || typeof newVNode === \"number\") {\n if (newVNode !== oldVNode) {\n const el = parent.childNodes[index];\n if (el) {\n el.nodeValue = String(newVNode);\n } else {\n // Self healing: if text node missing, append it\n parent.appendChild(document.createTextNode(String(newVNode)));\n }\n }\n return;\n }\n\n // Same Tag - Update Props & Children\n const el = oldVNode.el || parent.childNodes[index];\n\n if (!el) return;\n\n // Transfer DOM reference to the new VNode\n newVNode.el = el;\n\n patchProps(el, newVNode.props, oldVNode.props);\n\n reconcileChildren(el, newVNode.children, oldVNode.children);\n}\n","/**\n * @file Mounts the application to the DOM.\n * @module mount\n */\nimport { setObserver } from \"./observer.js\";\nimport { patch } from \"./patch.js\";\n\n/**\n * Mounts a component to a target DOM element.\n * @param {HTMLElement} target - The DOM element to mount to.\n * @param {function} Component - The root component function.\n */\nexport const mount = (target, Component) => {\n let prevVNode = null;\n\n const lifecycle = () => {\n setObserver(lifecycle);\n\n const nextVNode = {\n tag: Component,\n props: {},\n children: [],\n };\n\n patch(target, nextVNode, prevVNode);\n setObserver(null);\n prevVNode = nextVNode;\n };\n\n lifecycle();\n};\n"],"names":["currentObserver","currentInstance","getObserver","setObserver","obs","getInstance","setInstance","inst","Cortex","memory","synapses","get","set","updater","nextState","clone","render","styleSheet","cache","hashString","str","hash","i","minify","css","strings","args","raw","acc","content","className","h","tag","props","children","cleanChildren","c","onMount","fn","instance","onCleanup","hasKeys","createElement","vNode","childVNode","renderComponent","el","patchProps","child","newProps","oldProps","allProps","key","oldValue","newValue","eventName","reconcileChildren","parent","newChildren","oldChildren","maxLen","patch","keyed","newChild","oldItem","oldVNode","domChildAtIndex","newEl","hooks","renderedVNode","runUnmount","newVNode","index","isNew","oldChild","mount","target","Component","prevVNode","lifecycle","nextVNode"],"mappings":"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"}
1
+ {"version":3,"file":"humn.umd.js","sources":["../src/observer.js","../src/css.js","../src/patch.js","../src/persist.js","../src/cortex.js","../src/h.js","../src/mount.js","../src/lifecycle.js"],"sourcesContent":["/**\n * @file Observer module for tracking global state during rendering.\n * @module observer\n */\n\nlet currentObserver = null // For Cortex/State dependency\nlet currentInstance = null // For Lifecycle Hooks\n\n/**\n * Gets the current observer (render function).\n * @returns {function|null}\n */\nexport const getObserver = () => currentObserver\n\n/**\n * Sets the current observer.\n * @param {function|null} obs\n */\nexport const setObserver = (obs) => {\n currentObserver = obs\n}\n\n/**\n * Gets the current component instance (hook container).\n * @returns {object|null}\n */\nexport const getInstance = () => currentInstance\n\n/**\n * Sets the current component instance.\n * @param {object|null} inst\n */\nexport const setInstance = (inst) => {\n currentInstance = inst\n}\n","/**\n * @file Runtime Scoped CSS implementation using Native CSS Nesting.\n * @module css\n */\n\nlet styleSheet = null\nconst cache = new Set()\n\n/**\n * Simple DJB2 hashing function.\n */\nfunction hashString(str) {\n let hash = 5381\n let i = str.length\n while (i) {\n hash = (hash * 33) ^ str.charCodeAt(--i)\n }\n return (hash >>> 0).toString(36)\n}\n\n/**\n * Lightweight Runtime Minifier.\n * Removes comments and collapses whitespace.\n * We do not strip spaces around colons/brackets to ensure safety for calc().\n */\nfunction minify(css) {\n return css\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove comments\n .replace(/\\s+/g, ' ') // Collapse newlines/tabs to single space\n .trim() // Remove leading/trailing\n}\n\n/**\n * Scoped CSS Tag.\n * Wraps content in a unique class using Native CSS Nesting.\n */\nexport function css(strings, ...args) {\n const raw = strings.reduce((acc, str, i) => {\n return acc + str + (args[i] || '')\n }, '')\n\n const content = minify(raw)\n\n if (!content) return ''\n\n const hash = hashString(content)\n const className = `humn-${hash}`\n\n if (cache.has(hash)) {\n return className\n }\n\n if (!styleSheet) {\n styleSheet = document.createElement('style')\n styleSheet.id = 'humn-styles'\n document.head.appendChild(styleSheet)\n }\n\n styleSheet.textContent += `.${className} { \n ${content} \n }\\n`\n cache.add(hash)\n\n return className\n}\n","/**\n * @file This file contains the diffing and patching algorithm for the virtual DOM,\n * including support for Keyed Diffing.\n * @module patch\n */\nimport { track } from './metrics.js'\nimport { setInstance } from './observer.js'\n\n/**\n * Checks if a list of children contains keys.\n * @param {Array<import(\"./h\").VNode>} children - The list of VNodes.\n * @returns {boolean} True if keys are present.\n */\nexport function hasKeys(children) {\n return children && children.some((c) => c && c.props && c.props.key != null)\n}\n\n/**\n * Creates a real DOM element from a virtual node.\n * @param {import(\"./h\").VNode | string | number} vNode - The virtual node.\n * @returns {Text | HTMLElement} The created DOM element.\n */\nfunction createElement(vNode) {\n if (typeof vNode === 'string' || typeof vNode === 'number') {\n return document.createTextNode(String(vNode))\n }\n\n if (typeof vNode.tag === 'function') {\n const childVNode = renderComponent(vNode)\n vNode.child = childVNode\n\n // Recursively create the DOM for the child\n const el = createElement(childVNode)\n vNode.el = el\n\n // Queue Mount Hooks\n if (vNode.hooks && vNode.hooks.mounts.length > 0) {\n setTimeout(() => vNode.hooks.mounts.forEach((fn) => fn()), 0)\n }\n return el\n }\n\n track('elementsCreated')\n\n const el = document.createElement(vNode.tag)\n vNode.el = el\n patchProps(el, vNode.props)\n\n vNode.children.forEach((child) => {\n el.appendChild(createElement(child))\n })\n\n return el\n}\n\n/**\n * Updates the properties (attributes/events) of a DOM element.\n * @param {HTMLElement} el - The DOM element to update.\n * @param {object} [newProps={}] - The new properties.\n * @param {object} [oldProps={}] - The old properties.\n */\nfunction patchProps(el, newProps = {}, oldProps = {}) {\n if (!el) return\n\n const allProps = { ...oldProps, ...newProps }\n\n for (const key in allProps) {\n const oldValue = oldProps[key]\n const newValue = newProps[key]\n\n // Handle removed props\n if (newValue === undefined || newValue === null) {\n el.removeAttribute(key)\n track('patches')\n continue\n }\n\n // We check against the LIVE DOM value to prevent cursor jumping\n if (key === 'value' || key === 'checked') {\n if (el[key] !== newValue) {\n el[key] = newValue\n track('patches')\n }\n continue\n }\n\n // If prop hasn't changed, skip\n if (oldValue === newValue) continue\n\n track('patches')\n\n // Handle Events\n if (key.startsWith('on')) {\n const eventName = key.slice(2).toLowerCase()\n if (oldValue) el.removeEventListener(eventName, oldValue)\n el.addEventListener(eventName, newValue)\n }\n // Handle the disabled attribute\n if (key === 'disabled') {\n el.disabled = newValue === true || newValue === 'true'\n }\n // Handle standard attributes\n else {\n el.setAttribute(key, newValue)\n }\n }\n}\n\n/**\n * Reconciles the children of a node, handling both simple lists and keyed reordering.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {Array<import(\"./h\").VNode>} newChildren - The new list of children.\n * @param {Array<import(\"./h\").VNode>} oldChildren - The old list of children.\n */\nfunction reconcileChildren(parent, newChildren, oldChildren) {\n const isKeyed = hasKeys(newChildren) || hasKeys(oldChildren)\n\n // If no keys are used, use the fast index-based simple loop.\n // This is faster for static lists or simple text replacements.\n if (!isKeyed) {\n const maxLen = Math.max(newChildren.length, oldChildren.length)\n for (let i = 0; i < maxLen; i++) {\n patch(parent, newChildren[i], oldChildren[i], i)\n }\n return\n }\n\n // Keyed Diffing\n // Map existing children by Key\n const keyed = {}\n oldChildren.forEach((child, i) => {\n const key = (child.props && child.props.key) != null ? child.props.key : i\n keyed[key] = { vNode: child, index: i }\n })\n\n newChildren.forEach((newChild, i) => {\n const key =\n (newChild.props && newChild.props.key) != null ? newChild.props.key : i\n const oldItem = keyed[key]\n\n if (oldItem) {\n // A. MATCH FOUND\n const oldVNode = oldItem.vNode\n\n // Update the node's content (Recursion)\n patch(parent, newChild, oldVNode, i)\n\n // If the DOM node isn't in the right spot, move it.\n // We use oldVNode.el because patch transfers the ref, but just to be safe:\n const el = newChild.el || oldVNode.el\n\n // Get the node currently at this index in the real DOM\n const domChildAtIndex = parent.childNodes[i]\n\n // If the element exists but is in the wrong place, move it\n if (el && domChildAtIndex !== el) {\n parent.insertBefore(el, domChildAtIndex)\n track('patches')\n }\n\n // Remove from map so we know it was re-used\n delete keyed[key]\n } else {\n // B. NO MATCH (New Item)\n const newEl = createElement(newChild)\n const domChildAtIndex = parent.childNodes[i]\n\n if (domChildAtIndex) {\n parent.insertBefore(newEl, domChildAtIndex)\n } else {\n parent.appendChild(newEl)\n }\n }\n })\n\n // Remove any old keys that weren't used in the new list\n Object.values(keyed).forEach(({ vNode }) => {\n if (vNode.el && vNode.el.parentNode === parent) {\n runUnmount(vNode) // Clean up hooks\n parent.removeChild(vNode.el)\n track('elementsRemoved')\n }\n })\n}\n\n/**\n * Executes a Functional Component, tracks hooks, and returns the VNode.\n * @param {import(\"./h\").VNode} vNode - The component vNode.\n * @returns {import(\"./h\").VNode} The rendered child vNode.\n */\nfunction renderComponent(vNode) {\n track('componentsRendered')\n\n // 1. Prepare Hook Container\n const hooks = {\n mounts: [],\n cleanups: [],\n }\n\n // 2. Set Global Scope\n setInstance(hooks)\n\n // 3. Run the User's Component Function\n // We pass props as the first argument\n const renderedVNode = vNode.tag(vNode.props)\n\n // 4. Clear Global Scope\n setInstance(null)\n\n // 5. Attach hooks to the VNode so we can run them later\n vNode.hooks = hooks\n\n return renderedVNode\n}\n\n/**\n * Helper to recursively run cleanup hooks when a tree is removed.\n * @param {import(\"./h\").VNode} vNode - The vNode to unmount.\n */\nfunction runUnmount(vNode) {\n if (!vNode) return\n\n // 1. Run hooks for this node\n if (vNode.hooks && vNode.hooks.cleanups) {\n vNode.hooks.cleanups.forEach((fn) => fn())\n }\n\n // 2. Recurse into child (if component)\n if (vNode.child) {\n runUnmount(vNode.child)\n }\n\n // 3. Recurse into children (if element)\n if (vNode.children) {\n vNode.children.forEach(runUnmount)\n }\n}\n\n/**\n * The main diffing function. Compares V-DOM trees and updates the real DOM.\n * @param {HTMLElement} parent - The parent DOM element.\n * @param {import(\"./h\").VNode | string | number} newVNode - The new virtual node.\n * @param {import(\"./h\").VNode | string | number} oldVNode - The old virtual node.\n * @param {number} [index=0] - The index of the child node (used for simple diffing).\n */\nexport function patch(parent, newVNode, oldVNode, index = 0) {\n track('diffs')\n\n if (newVNode === undefined || newVNode === null) {\n const el = oldVNode.el || parent.childNodes[index]\n\n // Recursive Cleanup\n runUnmount(oldVNode)\n\n if (el) {\n parent.removeChild(el)\n track('elementsRemoved')\n }\n return\n }\n\n if (typeof newVNode.tag === 'function') {\n const isNew = !oldVNode\n\n const childVNode = renderComponent(newVNode)\n newVNode.child = childVNode\n\n const oldChild = oldVNode ? oldVNode.child : undefined\n patch(parent, childVNode, oldChild, index)\n\n newVNode.el = childVNode.el\n\n // Run mount hooks on the next tick\n if (isNew && newVNode.hooks && newVNode.hooks.mounts.length > 0) {\n setTimeout(() => {\n newVNode.hooks.mounts.forEach((fn) => fn())\n }, 0)\n }\n // TODO: Handle updates (running old cleanups if necessary) for Phase 2\n return\n }\n\n // Start - No old node? Create new.\n if (oldVNode === undefined || oldVNode === null) {\n parent.appendChild(createElement(newVNode))\n return\n }\n\n // Removal - No new node? Remove old.\n if (newVNode === undefined || newVNode === null) {\n // Try to find the element on the VNode, or fallback to index\n const el = oldVNode.el || parent.childNodes[index]\n if (el) {\n parent.removeChild(el)\n track('elementsRemoved')\n }\n return\n }\n\n // Changed Type - (e.g. <div> becomes <span>) -> Replace whole node\n if (\n typeof newVNode !== typeof oldVNode ||\n (typeof newVNode !== 'string' && newVNode.tag !== oldVNode.tag)\n ) {\n const el = oldVNode.el || parent.childNodes[index]\n if (el) {\n parent.replaceChild(createElement(newVNode), el)\n track('patches')\n }\n return\n }\n\n // Text Update\n if (typeof newVNode === 'string' || typeof newVNode === 'number') {\n if (newVNode !== oldVNode) {\n const el = parent.childNodes[index]\n if (el) {\n el.nodeValue = String(newVNode)\n track('patches')\n } else {\n // Self healing: if text node missing, append it\n parent.appendChild(document.createTextNode(String(newVNode)))\n }\n }\n return\n }\n\n // Same Tag - Update Props & Children\n const el = oldVNode.el || parent.childNodes[index]\n\n if (!el) return\n\n // Transfer DOM reference to the new VNode\n newVNode.el = el\n\n patchProps(el, newVNode.props, oldVNode.props)\n\n reconcileChildren(el, newVNode.children, oldVNode.children)\n}\n","/**\n * @typedef {object} HumnPersist\n * @property {boolean} __humn_persist\n * @property {any} initial\n * @property {PersistConfig} config\n */\n\n/**\n * @typedef {object} PersistConfig\n * @property {string} key\n */\n\n/**\n * Marks a section of the state for persistence in localStorage.\n *\n * @param {any} initial - The initial value of the state.\n * @param {PersistConfig} config - The configuration for persistence.\n * @returns {HumnPersist}\n */\nexport const persist = (initial, config = {}) => ({\n __humn_persist: true,\n initial,\n config,\n})\n","import { isDev } from './metrics.js'\nimport { getObserver } from './observer.js'\n\n/**\n * @typedef {object} Synapses\n * @property {function} set - Function to update the memory\n * @property {function} get - Function to get the memory\n */\n\n/**\n * @typedef {object} CortexParams\n * @property {object} memory - The initial state\n * @property {function(function, function): object} synapses - The synapses function\n */\n\n/**\n * The Cortex class manages the state of the application.\n * This uses a Proxy for fine-grained reactivity, ensuring only those components\n * which use the updated value get re-rendered.\n */\nexport class Cortex {\n /**\n * Creates an instance of Cortex.\n * @param {CortexParams} CortexParams - The parameters for the Cortex.\n */\n constructor({ memory, synapses }) {\n const liveMemory = { ...memory }\n this._persistenceMap = new Map()\n\n // Load in any existing values from local-storage\n for (const [key, value] of Object.entries(memory)) {\n if (value && value.__humn_persist) {\n const storageKey = value.config.key || key\n this._persistenceMap.set(key, storageKey)\n\n try {\n const stored = localStorage.getItem(storageKey)\n if (stored !== null) {\n liveMemory[key] = JSON.parse(stored)\n } else {\n liveMemory[key] = value.initial\n }\n } catch (err) {\n if (isDev)\n console.warn(`Humn: Failed to load '${key}' from storage.`, err)\n liveMemory[key] = value.initial\n }\n }\n }\n\n this._memory = liveMemory\n this._listeners = new Map()\n\n const get = () => this._memory\n\n const set = (updater) => {\n let nextState\n let changedPaths = new Set()\n\n if (typeof updater === 'function') {\n const clone = structuredClone(this._memory)\n const proxy = this._createChangeTrackingProxy(clone, changedPaths)\n const result = updater(proxy)\n\n if (result && typeof result === 'object') {\n nextState = { ...this._memory, ...result }\n Object.keys(result).forEach((key) => changedPaths.add(key))\n } else {\n nextState = clone\n }\n } else {\n nextState = { ...this._memory, ...updater }\n changedPaths = new Set(Object.keys(updater))\n }\n\n this._memory = nextState\n\n // If we need to persist any of the values\n // we save them to localStorage here\n if (this._persistenceMap.size > 0) {\n this._persistenceMap.forEach((storageKey, stateKey) => {\n const isDirty = Array.from(changedPaths).some(\n (path) => path === stateKey || path.startsWith(stateKey + '.'),\n )\n\n if (isDirty) {\n try {\n const value = this._memory[stateKey]\n localStorage.setItem(storageKey, JSON.stringify(value))\n } catch (err) {\n if (isDev)\n console.error(`Humn: Failed to save '${stateKey}'.`, err)\n }\n }\n })\n }\n\n this._notifyRelevantListeners(changedPaths)\n }\n\n this.synapses = synapses(set, get)\n }\n\n /**\n * Creates a Proxy that tracks which properties are being mutated.\n * Includes a GET trap to recursively proxy nested objects for deep mutation tracking.\n */\n _createChangeTrackingProxy(obj, changedPaths, path = '') {\n return new Proxy(obj, {\n get: (target, prop) => {\n if (typeof prop === 'symbol' || prop === '__proto__')\n return target[prop]\n\n const value = target[prop]\n const fullPath = path ? `${path}.${prop}` : prop\n\n // Recursively proxy nested objects so we can trap their sets too\n if (typeof value === 'object' && value !== null) {\n return this._createChangeTrackingProxy(value, changedPaths, fullPath)\n }\n return value\n },\n set: (target, prop, value) => {\n if (typeof prop === 'symbol' || prop === '__proto__') {\n target[prop] = value\n return true\n }\n\n const fullPath = path ? `${path}.${prop}` : prop\n changedPaths.add(fullPath)\n\n target[prop] = value\n return true\n },\n })\n }\n\n /**\n * Only notify listeners that read properties which changed\n */\n _notifyRelevantListeners(changedPaths) {\n this._listeners.forEach((accessedPaths, renderFn) => {\n const shouldNotify = Array.from(accessedPaths).some((accessedPath) => {\n return Array.from(changedPaths).some((changedPath) => {\n // Check for exact match or parent/child relationship\n return (\n accessedPath === changedPath ||\n accessedPath.startsWith(changedPath + '.') ||\n changedPath.startsWith(accessedPath + '.')\n )\n })\n })\n\n if (shouldNotify) renderFn()\n })\n }\n\n /**\n * Creates a Proxy that tracks which properties are accessed during render\n */\n _createAccessTrackingProxy(obj, accessedPaths, path = '') {\n if (typeof obj !== 'object' || obj === null) return obj\n\n return new Proxy(obj, {\n get: (target, prop) => {\n // We don't care about prototype and symbol properties\n if (typeof prop === 'symbol' || prop === '__proto__')\n return target[prop]\n\n const fullPath = path ? `${path}.${prop}` : prop\n accessedPaths.add(fullPath)\n\n const value = target[prop]\n\n // Recursively wrap nested objects\n if (typeof value === 'object' && value !== null)\n return this._createAccessTrackingProxy(value, accessedPaths, fullPath)\n\n return value\n },\n })\n }\n\n /**\n * Returns memory wrapped in a tracking Proxy\n */\n get memory() {\n const currentObserver = getObserver()\n\n if (!currentObserver) return this._memory\n\n if (!this._listeners.has(currentObserver))\n this._listeners.set(currentObserver, new Set())\n\n const accessedPaths = this._listeners.get(currentObserver)\n\n // This gives us fresh tracking each render\n accessedPaths.clear()\n\n return this._createAccessTrackingProxy(this._memory, accessedPaths)\n }\n}\n","/**\n * @typedef {object} VNode\n * @property {string} tag\n * @property {object} props\n * @property {VNode[]} children\n */\n\n/**\n * Creates a virtual DOM node.\n * This is a hyperscript-like function.\n *\n * @param {string} tag - The tag name of the element.\n * @param {object} props - The properties of the element.\n * @param {VNode[]|VNode} children - The children of the element.\n * @returns {VNode} The virtual DOM node.\n */\nexport const h = (tag, props = {}, children = []) => {\n const childArray = Array.isArray(children) ? children : [children]\n\n // Filter out null/false so we don't have \"ghost\" nodes\n const cleanChildren = childArray\n .flat()\n .filter((c) => c !== null && c !== undefined && c !== false && c !== '')\n\n return {\n tag,\n props,\n children: cleanChildren,\n }\n}\n","/**\n * @file Mounts the application to the DOM.\n * @module mount\n */\nimport { setObserver } from './observer.js'\nimport { patch } from './patch.js'\n\n/**\n * Mounts a component to a target DOM element.\n * @param {HTMLElement} target - The DOM element to mount to.\n * @param {function} Component - The root component function.\n */\nexport const mount = (target, Component) => {\n let prevVNode = null\n\n const lifecycle = () => {\n setObserver(lifecycle)\n\n const nextVNode = {\n tag: Component,\n props: {},\n children: [],\n }\n\n patch(target, nextVNode, prevVNode)\n setObserver(null)\n prevVNode = nextVNode\n }\n\n lifecycle()\n}\n","/**\n * @file Lifecycle hooks for components.\n * @module lifecycle\n */\nimport { getInstance } from './observer.js'\n\n/**\n * Registers a callback to run after the component mounts.\n * @param {function} fn - The callback function.\n */\nexport function onMount(fn) {\n const instance = getInstance()\n if (instance) {\n instance.mounts.push(fn)\n }\n}\n\n/**\n * Registers a callback to run when the component unmounts.\n * @param {function} fn - The callback function.\n */\nexport function onCleanup(fn) {\n const instance = getInstance()\n if (instance) {\n instance.cleanups.push(fn)\n }\n}\n"],"names":["g","f","exports","module","define","amd","globalThis","self","Humn","this","currentObserver","currentInstance","getObserver","setObserver","obs","getInstance","setInstance","inst","styleSheet","cache","Set","hasKeys","children","some","c","props","key","createElement","vNode","document","createTextNode","String","tag","childVNode","renderComponent","child","el","hooks","mounts","length","setTimeout","forEach","fn","patchProps","appendChild","newProps","oldProps","allProps","oldValue","newValue","startsWith","eventName","slice","toLowerCase","removeEventListener","addEventListener","disabled","setAttribute","removeAttribute","cleanups","renderedVNode","runUnmount","patch","parent","newVNode","oldVNode","index","childNodes","removeChild","isNew","replaceChild","nodeValue","newChildren","oldChildren","maxLen","Math","max","i","keyed","newChild","oldItem","domChildAtIndex","insertBefore","newEl","Object","values","parentNode","Cortex","constructor","memory","synapses","liveMemory","_persistenceMap","Map","value","entries","__humn_persist","storageKey","config","set","stored","localStorage","getItem","JSON","parse","initial","err","_memory","_listeners","updater","nextState","changedPaths","clone","structuredClone","result","_createChangeTrackingProxy","keys","add","size","stateKey","Array","from","path","setItem","stringify","_notifyRelevantListeners","obj","Proxy","get","target","prop","fullPath","accessedPaths","renderFn","accessedPath","changedPath","_createAccessTrackingProxy","has","clear","css","strings","args","content","replace","trim","reduce","acc","str","hash","charCodeAt","toString","className","id","head","textContent","h","isArray","flat","filter","mount","Component","prevVNode","lifecycle","nextVNode","onCleanup","instance","push","onMount","persist","defineProperty","Symbol","toStringTag"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -10,6 +10,8 @@
10
10
  */
11
11
  /**
12
12
  * The Cortex class manages the state of the application.
13
+ * This uses a Proxy for fine-grained reactivity, ensuring only those components
14
+ * which use the updated value get re-rendered.
13
15
  */
14
16
  export declare class Cortex {
15
17
  /**
@@ -17,14 +19,27 @@ export declare class Cortex {
17
19
  * @param {CortexParams} CortexParams - The parameters for the Cortex.
18
20
  */
19
21
  constructor({ memory, synapses }: CortexParams);
22
+ _persistenceMap: Map<any, any>;
20
23
  _memory: any;
21
- _listeners: Set<any>;
24
+ _listeners: Map<any, any>;
22
25
  synapses: any;
23
26
  /**
24
- * Get the memory and register the current observer.
25
- * @returns {object} The current state
27
+ * Creates a Proxy that tracks which properties are being mutated.
28
+ * Includes a GET trap to recursively proxy nested objects for deep mutation tracking.
26
29
  */
27
- get memory(): object;
30
+ _createChangeTrackingProxy(obj: any, changedPaths: any, path?: string): any;
31
+ /**
32
+ * Only notify listeners that read properties which changed
33
+ */
34
+ _notifyRelevantListeners(changedPaths: any): void;
35
+ /**
36
+ * Creates a Proxy that tracks which properties are accessed during render
37
+ */
38
+ _createAccessTrackingProxy(obj: any, accessedPaths: any, path?: string): any;
39
+ /**
40
+ * Returns memory wrapped in a tracking Proxy
41
+ */
42
+ get memory(): any;
28
43
  }
29
44
 
30
45
  export declare type CortexParams = {
@@ -46,6 +61,12 @@ export declare function css(strings: any, ...args: any[]): string;
46
61
 
47
62
  export declare function h(tag: string, props?: object, children?: VNode[] | VNode): VNode;
48
63
 
64
+ export declare type HumnPersist = {
65
+ __humn_persist: boolean;
66
+ initial: any;
67
+ config: PersistConfig;
68
+ };
69
+
49
70
  export declare function mount(target: HTMLElement, Component: Function): void;
50
71
 
51
72
  /**
@@ -60,6 +81,12 @@ export declare function onCleanup(fn: Function): void;
60
81
  */
61
82
  export declare function onMount(fn: Function): void;
62
83
 
84
+ export declare function persist(initial: any, config?: PersistConfig): HumnPersist;
85
+
86
+ export declare type PersistConfig = {
87
+ key: string;
88
+ };
89
+
63
90
  export declare type Synapses = {
64
91
  /**
65
92
  * - Function to update the memory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humn",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "A minimal, human-centric reactive UI library with built in state management.",
5
5
  "type": "module",
6
6
  "main": "./dist/humn.umd.js",
@@ -20,9 +20,17 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "build": "vite build",
23
- "test": "vitest",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest watch",
24
25
  "dev": "vite --port 3000 --open /playground/",
25
- "prepublishOnly": "npm run build"
26
+ "prepublishOnly": "npm run build",
27
+ "prepare": "husky",
28
+ "git-diff": "git log origin/main..HEAD --pretty=format:'%ad:: %s' > git-diff.txt && echo '\n----------\n' >> git-diff.txt && git diff origin/main...HEAD --color ':!*.lock' >> git-diff.txt"
29
+ },
30
+ "lint-staged": {
31
+ "**/*": [
32
+ "npx prettier . --write"
33
+ ]
26
34
  },
27
35
  "keywords": [
28
36
  "reactive",
@@ -40,15 +48,22 @@
40
48
  "url": "https://github.com/KeeghanM/humn"
41
49
  },
42
50
  "devDependencies": {
51
+ "@rollup/plugin-terser": "^0.4.4",
43
52
  "@semantic-release/changelog": "^6.0.3",
44
53
  "@semantic-release/git": "^10.0.1",
45
54
  "@semantic-release/github": "^12.0.2",
46
55
  "@semantic-release/npm": "^13.1.2",
56
+ "@trivago/prettier-plugin-sort-imports": "^6.0.0",
47
57
  "@types/node": "^24.10.1",
48
58
  "conventional-changelog-conventionalcommits": "^9.1.0",
59
+ "husky": "^9.1.7",
60
+ "jsdom": "^27.2.0",
61
+ "lint-staged": "^16.2.7",
62
+ "prettier": "^3.7.3",
49
63
  "semantic-release": "^25.0.2",
50
64
  "typescript": "^5.9.3",
51
65
  "vite": "^7.2.6",
52
- "vite-plugin-dts": "^4.5.4"
66
+ "vite-plugin-dts": "^4.5.4",
67
+ "vitest": "^4.0.15"
53
68
  }
54
69
  }