@cmj/cellui 0.1.3

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.
@@ -0,0 +1,2 @@
1
+ import { DeepSignal } from './signal';
2
+ export declare function ambient<T>(name: string, initialValue: T): DeepSignal<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/dist/cellui.js ADDED
@@ -0,0 +1,513 @@
1
+ let v = null;
2
+ class w {
3
+ _value;
4
+ _subscribers = /* @__PURE__ */ new Set();
5
+ _weakSubscribers = /* @__PURE__ */ new Set();
6
+ constructor(e) {
7
+ this._value = e;
8
+ }
9
+ get value() {
10
+ return v && this.track(v), this._value;
11
+ }
12
+ set value(e) {
13
+ if (this._value !== e) {
14
+ this._value = e, this._subscribers.forEach((n) => n(e));
15
+ for (const n of this._weakSubscribers) {
16
+ const t = n.ref.deref();
17
+ t ? n.updater(t, e) : this._weakSubscribers.delete(n);
18
+ }
19
+ }
20
+ }
21
+ subscribe(e) {
22
+ return this.track(e), e(this._value), () => this._subscribers.delete(e);
23
+ }
24
+ // Silent dependency registration mode for effects
25
+ track(e) {
26
+ return this._subscribers.add(e), () => this._subscribers.delete(e);
27
+ }
28
+ // Memory-safe binding for DOM nodes
29
+ bindNode(e, n) {
30
+ this._weakSubscribers.add({
31
+ ref: new WeakRef(e),
32
+ updater: n
33
+ }), n(e, this._value);
34
+ }
35
+ }
36
+ const S = (o) => {
37
+ const e = new w(o);
38
+ if (typeof o == "object" && o !== null) {
39
+ const n = /* @__PURE__ */ new Map();
40
+ return e.subscribe((t) => {
41
+ t && typeof t == "object" && n.forEach((i, r) => {
42
+ t[r] !== i.value && (i.value = t[r]);
43
+ });
44
+ }), new Proxy(e, {
45
+ get(t, i) {
46
+ if (i in t || typeof i == "symbol" || i === "constructor" || t.hasOwnProperty(i))
47
+ return Reflect.get(t, i);
48
+ if (!n.has(i)) {
49
+ const r = t.value ? t.value[i] : void 0, u = S(r), a = Object.getOwnPropertyDescriptor(w.prototype, "value").set;
50
+ Object.defineProperty(u, "value", {
51
+ get() {
52
+ return v && u.track(v), u._value;
53
+ },
54
+ set(s) {
55
+ if (u._value !== s && (a.call(u, s), t.value && typeof t.value == "object")) {
56
+ const d = Array.isArray(t.value) ? [...t.value] : { ...t.value };
57
+ d[i] = s, Object.getOwnPropertyDescriptor(w.prototype, "value").set.call(t, d);
58
+ }
59
+ }
60
+ }), n.set(i, u);
61
+ }
62
+ return v && n.get(i)?.track(v), n.get(i);
63
+ }
64
+ });
65
+ }
66
+ return e;
67
+ };
68
+ function x(o) {
69
+ const e = () => {
70
+ v = e;
71
+ try {
72
+ o();
73
+ } finally {
74
+ v = null;
75
+ }
76
+ };
77
+ e();
78
+ }
79
+ const E = /* @__PURE__ */ new Map();
80
+ function A(o, e) {
81
+ return E.has(o) || E.set(o, S(e)), E.get(o);
82
+ }
83
+ class $ {
84
+ zone;
85
+ registry = /* @__PURE__ */ new Map();
86
+ constructor(e) {
87
+ this.zone = e;
88
+ }
89
+ connect(e, n) {
90
+ if (e.startsWith("global:")) {
91
+ const t = e.slice(7);
92
+ return A(t, n);
93
+ }
94
+ return this.registry.has(e) || this.registry.set(e, S(n)), this.registry.get(e);
95
+ }
96
+ // DSL Aliases
97
+ infuse(e, n) {
98
+ return this.connect(e, n);
99
+ }
100
+ extract(e) {
101
+ return this.connect(e);
102
+ }
103
+ destroy() {
104
+ this.registry.clear();
105
+ }
106
+ }
107
+ function W(o) {
108
+ return new $(o);
109
+ }
110
+ const H = {
111
+ track: (o) => {
112
+ window.dispatchEvent(
113
+ new CustomEvent("cellui:mount", {
114
+ detail: {
115
+ timestamp: Date.now(),
116
+ target: o
117
+ }
118
+ })
119
+ );
120
+ },
121
+ panic: (o, e) => {
122
+ console.error("[CellUI Shield] Fatal render error:", e);
123
+ const n = e instanceof Error ? e.message : String(e);
124
+ o.innerHTML = `
125
+ <div style="padding: 20px; border: 2px solid #ff4444; border-radius: 8px; background: #fff0f0; color: #ff4444; font-family: monospace;">
126
+ <h3 style="margin-top: 0;">CellUI Render Error</h3>
127
+ <pre style="white-space: pre-wrap; word-break: break-word;">${n}</pre>
128
+ </div>
129
+ `, window.dispatchEvent(
130
+ new CustomEvent("cellui:panic", {
131
+ detail: { error: e, target: o }
132
+ })
133
+ );
134
+ }
135
+ }, _ = /* @__PURE__ */ new WeakMap();
136
+ let k = null;
137
+ function T() {
138
+ k || typeof window > "u" || (k = new MutationObserver((o) => {
139
+ for (const e of o)
140
+ for (const n of Array.from(e.removedNodes)) {
141
+ const t = _.get(n);
142
+ if (t && (t.forEach((i) => {
143
+ try {
144
+ i();
145
+ } catch (r) {
146
+ console.error("[CellUI] Error in onDispose callback:", r);
147
+ }
148
+ }), _.delete(n)), n.nodeType === 1 && typeof document < "u") {
149
+ const i = document.createTreeWalker(n, NodeFilter.SHOW_ELEMENT);
150
+ let r = i.nextNode();
151
+ for (; r; ) {
152
+ const u = _.get(r);
153
+ u && (u.forEach((a) => {
154
+ try {
155
+ a();
156
+ } catch (s) {
157
+ console.error("[CellUI] Error in onDispose callback:", s);
158
+ }
159
+ }), _.delete(r)), r = i.nextNode();
160
+ }
161
+ }
162
+ }
163
+ }), k.observe(document.body, {
164
+ childList: !0,
165
+ subtree: !0
166
+ }));
167
+ }
168
+ const y = {
169
+ Shield: H,
170
+ onDispose: (o, e) => {
171
+ T(), _.has(o) || _.set(o, []), _.get(o).push(e);
172
+ },
173
+ bind: (o) => ({
174
+ __cellui_directive: "bind",
175
+ signal: o
176
+ }),
177
+ initSubstrate: () => (T(), new $("__cellui_root__")),
178
+ Hydrator: {
179
+ isHydrating: !1,
180
+ popContext: () => null
181
+ },
182
+ dispose: (o) => {
183
+ const e = _.get(o);
184
+ e && (e.forEach((i) => i()), _.delete(o));
185
+ const n = document.createTreeWalker(o, NodeFilter.SHOW_ELEMENT);
186
+ let t = n.nextNode();
187
+ for (; t; ) {
188
+ const i = _.get(t);
189
+ i && (i.forEach((r) => r()), _.delete(t)), t = n.nextNode();
190
+ }
191
+ window.dispatchEvent(
192
+ new CustomEvent("cellui:unmount", {
193
+ detail: { target: o }
194
+ })
195
+ );
196
+ }
197
+ }, F = y.bind;
198
+ function V(o, ...e) {
199
+ const n = document.createElement("template");
200
+ if (y.Hydrator.isHydrating) {
201
+ const a = y.Hydrator.popContext();
202
+ return a && e.forEach((s, d) => {
203
+ if (typeof s == "function" && a.events.has(d)) {
204
+ const f = a.events.get(d), c = o[d].match(/on([a-z]+)=/);
205
+ c && f.addEventListener(c[1], s);
206
+ } else if (s && typeof s == "object" && s.__cellui_directive === "bind") {
207
+ const f = s.signal, c = a.binds.get(d);
208
+ if (c) {
209
+ f.bindNode(c, (h, m) => {
210
+ c.type === "checkbox" || c.type === "radio" ? h.checked = !!m : h.value = String(m);
211
+ });
212
+ const l = (h) => {
213
+ const m = h.target;
214
+ m.type === "checkbox" ? f.value = m.checked : f.value = m.value;
215
+ }, p = c.type === "checkbox" || c.type === "radio" || c.tagName === "SELECT" ? "change" : "input";
216
+ c.addEventListener(p, l);
217
+ }
218
+ } else if (s instanceof w) {
219
+ const f = a.markers.get(d);
220
+ if (f) {
221
+ const c = f.nextSibling;
222
+ if (c && c.nodeType === 3) {
223
+ const l = String(s.value);
224
+ c.nodeValue.length > l.length && c.splitText(l.length), s.bindNode(c, (p, h) => {
225
+ p.nodeValue = String(h);
226
+ });
227
+ } else {
228
+ const l = document.createTextNode("");
229
+ f.parentNode.insertBefore(l, f.nextSibling), s.bindNode(l, (p, h) => {
230
+ p.nodeValue = String(h);
231
+ });
232
+ }
233
+ }
234
+ } else if (typeof s == "function" && a.markers.has(d)) {
235
+ const f = a.markers.get(d);
236
+ if (f) {
237
+ const c = f.nextSibling;
238
+ if (c && c.nodeType === 3) {
239
+ const l = String(s());
240
+ c.nodeValue.length > l.length && c.splitText(l.length), x(() => {
241
+ c.nodeValue = String(s());
242
+ });
243
+ } else {
244
+ const l = document.createTextNode("");
245
+ f.parentNode.insertBefore(l, f.nextSibling), x(() => {
246
+ l.nodeValue = String(s());
247
+ });
248
+ }
249
+ }
250
+ }
251
+ }), null;
252
+ }
253
+ n.innerHTML = o.reduce((a, s, d) => a + s + (d < e.length ? `__nex_${d}__` : ""), "");
254
+ const t = n.content.cloneNode(!0);
255
+ t.querySelectorAll("*").forEach((a) => {
256
+ Array.from(a.attributes).forEach((s) => {
257
+ const d = s.value.match(/__nex_(\d+)__/) || s.name.match(/__nex_(\d+)__/);
258
+ if (d) {
259
+ const f = parseInt(d[1], 10), c = e[f];
260
+ if (typeof c == "function" && s.name.startsWith("on")) {
261
+ const l = s.name.slice(2).toLowerCase();
262
+ a.addEventListener(l, c), a.removeAttribute(s.name);
263
+ } else if (c && typeof c == "object" && c.__cellui_directive === "bind") {
264
+ const l = c.signal, p = a.getAttribute("type");
265
+ p === "checkbox" || p === "radio" ? l.bindNode(a, (m, g) => {
266
+ m.checked = !!g;
267
+ }) : l.bindNode(a, (m, g) => {
268
+ m.value = String(g);
269
+ });
270
+ const h = p === "checkbox" || p === "radio" || a.tagName === "SELECT" ? "change" : "input";
271
+ a.addEventListener(h, (m) => {
272
+ const g = m.target;
273
+ p === "checkbox" ? l.value = g.checked : l.value = g.value;
274
+ }), a.removeAttribute(s.name);
275
+ } else if (c instanceof w) {
276
+ const l = s.name;
277
+ c.bindNode(a, (p, h) => {
278
+ p.setAttribute(l, String(h));
279
+ });
280
+ } else
281
+ a.setAttribute(s.name, s.value.replace(/__nex_\d+__/, String(c)));
282
+ }
283
+ });
284
+ });
285
+ const r = document.createTreeWalker(
286
+ t,
287
+ 4
288
+ /* NodeFilter.SHOW_TEXT */
289
+ );
290
+ let u = r.nextNode();
291
+ for (; u; ) {
292
+ const a = u.nodeValue?.match(/__nex_(\d+)__/);
293
+ if (a) {
294
+ const s = parseInt(a[1], 10), d = e[s], f = u.nodeValue.split(`__nex_${s}__`);
295
+ u.nodeValue = f[0];
296
+ const c = document.createTextNode(""), l = document.createTextNode(f.slice(1).join(`__nex_${s}__`));
297
+ u.parentNode.insertBefore(c, u.nextSibling), u.parentNode.insertBefore(l, c.nextSibling), d instanceof w ? d.bindNode(c, (p, h) => {
298
+ p.nodeValue = String(h);
299
+ }) : d && typeof d == "object" && d.__cellui_directive === "bind" ? c.nodeValue = "" : typeof d == "function" ? x(() => {
300
+ c.nodeValue = String(d());
301
+ }) : d instanceof Node ? c.replaceWith(d) : c.nodeValue = String(d), u = l;
302
+ } else
303
+ u = r.nextNode();
304
+ }
305
+ return t;
306
+ }
307
+ async function I(o, e) {
308
+ const n = typeof o == "string" ? document.querySelector(o) : o;
309
+ if (!n)
310
+ throw new Error(`[CellUI] Mount target not found: ${o}`);
311
+ y.initSubstrate();
312
+ const t = window.requestIdleCallback || ((i) => setTimeout(i, 0));
313
+ return new Promise((i) => {
314
+ t(() => {
315
+ try {
316
+ const r = e();
317
+ n.replaceChildren(r), y.Shield.track(n);
318
+ } catch (r) {
319
+ y.Shield.panic(n, r);
320
+ }
321
+ i(() => {
322
+ y.dispose(n), n.innerHTML = "";
323
+ });
324
+ });
325
+ });
326
+ }
327
+ function B(o, ...e) {
328
+ let n = "";
329
+ for (let t = 0; t < o.length; t++) {
330
+ let i = o[t];
331
+ if (t > 0 && typeof e[t - 1] == "function" && /on[a-z]+=["']?$/.test(o[t - 1]) && (i = i.replace(/^["']/, "")), t < e.length) {
332
+ const r = e[t];
333
+ if (typeof r == "function" && /on[a-z]+=["']?$/.test(i))
334
+ i = i.replace(/\s*on[a-z]+=["']?$/, ""), n += i + ` data-cellui-on-${t}=""`;
335
+ else if (n += i, r instanceof w)
336
+ n += `<!--cellui-marker:${t}-->${r.value}`;
337
+ else if (r && typeof r == "object" && r.__cellui_directive === "bind") {
338
+ const u = r.signal;
339
+ n += ` value="${u.value}" data-cellui-bind-${t}=""`;
340
+ } else typeof r == "function" ? n += `<!--cellui-computed-marker:${t}-->${r()}` : r && typeof r == "object" && r.__cellui_ssr_template ? n += `<!--cellui-open:${t}-->${r.html}<!--cellui-close:${t}-->` : r instanceof Array ? n += `<!--cellui-list-open:${t}-->${r.join("")}<!--cellui-list-close:${t}-->` : n += String(r);
341
+ } else
342
+ n += i;
343
+ }
344
+ return {
345
+ __cellui_ssr_template: !0,
346
+ html: n,
347
+ toString() {
348
+ return this.html;
349
+ }
350
+ };
351
+ }
352
+ const M = {
353
+ queue: [],
354
+ start(o) {
355
+ y.Hydrator.isHydrating = !0, this.queue = this.buildQueue(o), y.Hydrator.popContext = () => this.queue.shift();
356
+ },
357
+ end() {
358
+ y.Hydrator.isHydrating = !1, this.queue = [], y.Hydrator.popContext = () => null;
359
+ },
360
+ buildQueue(o) {
361
+ const e = document.createTreeWalker(o, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);
362
+ let n = { markers: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map(), binds: /* @__PURE__ */ new Map() };
363
+ const t = [n], i = [];
364
+ for (; e.nextNode(); ) {
365
+ const r = e.currentNode;
366
+ if (r.nodeType === 8) {
367
+ const u = r.nodeValue || "";
368
+ if (u.startsWith("cellui-marker:") || u.startsWith("cellui-computed-marker:"))
369
+ n.markers.set(parseInt(u.split(":")[1], 10), r);
370
+ else if (u.startsWith("cellui-open:")) {
371
+ const a = { markers: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map(), binds: /* @__PURE__ */ new Map() };
372
+ t.push(a), n = a;
373
+ } else u.startsWith("cellui-close:") && (i.push(n), t.pop(), n = t[t.length - 1]);
374
+ } else if (r.nodeType === 1) {
375
+ const u = r;
376
+ for (let a = 0; a < u.attributes.length; a++) {
377
+ const s = u.attributes[a];
378
+ s.name.startsWith("data-cellui-on-") ? (n.events.set(parseInt(s.name.split("-").pop(), 10), u), u.removeAttribute(s.name), a--) : s.name.startsWith("data-cellui-bind-") && (n.binds.set(parseInt(s.name.split("-").pop(), 10), u), u.removeAttribute(s.name), a--);
379
+ }
380
+ }
381
+ }
382
+ return i.push(t[0]), i;
383
+ }
384
+ };
385
+ function L(o, e) {
386
+ M.start(o), e(), M.end();
387
+ }
388
+ function D(o, e) {
389
+ if (typeof document > "u") {
390
+ const a = typeof o == "function" ? !!o() : !!o.value;
391
+ let s;
392
+ return typeof e == "function" ? s = a ? e : void 0 : s = a ? e.true : e.false, s ? s() : { __cellui_ssr_template: !0, html: "", toString() {
393
+ return "";
394
+ } };
395
+ }
396
+ const n = document.createDocumentFragment(), t = document.createComment("when-anchor");
397
+ n.appendChild(t);
398
+ let i = [], r = !0, u;
399
+ return typeof o == "function" ? u = S(o()) : u = o, u.bindNode(t, (a, s) => {
400
+ const d = !!s;
401
+ let f;
402
+ if (typeof e == "function" ? f = d ? e : void 0 : f = d ? e.true : e.false, i.forEach((l) => {
403
+ if (l.nodeType === 1 && typeof l.getAnimations == "function") {
404
+ const p = l.getAnimations();
405
+ if (p.length > 0) {
406
+ Promise.all(p.map((h) => h.finished)).then(() => {
407
+ l.parentNode && !i.includes(l) && l.parentNode.removeChild(l);
408
+ }).catch(() => {
409
+ l.parentNode && !i.includes(l) && l.parentNode.removeChild(l);
410
+ });
411
+ return;
412
+ }
413
+ }
414
+ l.parentNode?.removeChild(l);
415
+ }), i = [], f) {
416
+ const l = f();
417
+ if (l instanceof DocumentFragment ? i = Array.from(l.childNodes) : i = [l], r)
418
+ i.forEach((p) => n.appendChild(p));
419
+ else if (a.parentNode) {
420
+ let p = a.nextSibling;
421
+ i.forEach((h) => {
422
+ a.parentNode.insertBefore(h, p);
423
+ });
424
+ }
425
+ }
426
+ r = !1;
427
+ }), n;
428
+ }
429
+ function j(o, e, n) {
430
+ if (typeof document > "u")
431
+ return { __cellui_ssr_template: !0, html: o.value.map((d, f) => {
432
+ const c = n(d, f);
433
+ return c ? c.html : "";
434
+ }).join(""), toString() {
435
+ return this.html;
436
+ } };
437
+ const t = document.createDocumentFragment(), i = document.createComment("each-anchor");
438
+ t.appendChild(i);
439
+ let r = /* @__PURE__ */ new Map(), u = !0;
440
+ return o.bindNode(i, (a, s) => {
441
+ const d = /* @__PURE__ */ new Map(), f = a.parentNode, c = (h, m) => typeof e == "function" ? e(h, m) : String(h[e]), l = new Set(s.map((h, m) => c(h, m)));
442
+ r.forEach((h, m) => {
443
+ l.has(m) || h.forEach((g) => {
444
+ if (g.nodeType === 1 && typeof g.getAnimations == "function") {
445
+ const N = g.getAnimations();
446
+ if (N.length > 0) {
447
+ Promise.all(N.map((b) => b.finished)).then(() => {
448
+ g.parentNode && !r.has(m) && g.parentNode.removeChild(g);
449
+ }).catch(() => {
450
+ g.parentNode && !r.has(m) && g.parentNode.removeChild(g);
451
+ });
452
+ return;
453
+ }
454
+ }
455
+ g.parentNode?.removeChild(g);
456
+ });
457
+ });
458
+ let p = a;
459
+ s.forEach((h, m) => {
460
+ const g = c(h, m);
461
+ let N = [];
462
+ if (r.has(g))
463
+ N = r.get(g);
464
+ else {
465
+ const b = n(h, m);
466
+ b instanceof DocumentFragment ? N = Array.from(b.childNodes) : N = [b];
467
+ }
468
+ d.set(g, N), u ? N.forEach((b) => {
469
+ t.appendChild(b), p = b;
470
+ }) : f && N.forEach((b) => {
471
+ const C = p.nextSibling;
472
+ b !== C && f.insertBefore(b, C), p = b;
473
+ });
474
+ }), r = d, u = !1;
475
+ }), t;
476
+ }
477
+ function O(o, e, n) {
478
+ const t = document.createDocumentFragment(), i = document.createComment("match-anchor");
479
+ t.appendChild(i);
480
+ let r = [], u = !0;
481
+ return o.bindNode(i, (a, s) => {
482
+ const d = e[s] || n;
483
+ if (r.forEach((f) => f.parentNode?.removeChild(f)), r = [], d) {
484
+ const f = d();
485
+ if (f instanceof DocumentFragment ? r = Array.from(f.childNodes) : r = [f], u)
486
+ r.forEach((c) => t.appendChild(c));
487
+ else if (a.parentNode) {
488
+ let c = a.nextSibling;
489
+ r.forEach((l) => {
490
+ a.parentNode.insertBefore(l, c);
491
+ });
492
+ }
493
+ }
494
+ u = !1;
495
+ }), t;
496
+ }
497
+ export {
498
+ y as CellUI,
499
+ w as Signal,
500
+ $ as Substrate,
501
+ A as ambient,
502
+ F as bind,
503
+ W as createSubstrate,
504
+ j as each,
505
+ x as effect,
506
+ L as hydrate,
507
+ O as match,
508
+ I as mount,
509
+ B as serverView,
510
+ S as signal,
511
+ V as view,
512
+ D as when
513
+ };
@@ -0,0 +1,6 @@
1
+ (function(g,y){typeof exports=="object"&&typeof module<"u"?y(exports):typeof define=="function"&&define.amd?define(["exports"],y):(g=typeof globalThis<"u"?globalThis:g||self,y(g.CellUI={}))})(this,(function(g){"use strict";let y=null;class w{_value;_subscribers=new Set;_weakSubscribers=new Set;constructor(e){this._value=e}get value(){return y&&this.track(y),this._value}set value(e){if(this._value!==e){this._value=e,this._subscribers.forEach(n=>n(e));for(const n of this._weakSubscribers){const t=n.ref.deref();t?n.updater(t,e):this._weakSubscribers.delete(n)}}}subscribe(e){return this.track(e),e(this._value),()=>this._subscribers.delete(e)}track(e){return this._subscribers.add(e),()=>this._subscribers.delete(e)}bindNode(e,n){this._weakSubscribers.add({ref:new WeakRef(e),updater:n}),n(e,this._value)}}const E=o=>{const e=new w(o);if(typeof o=="object"&&o!==null){const n=new Map;return e.subscribe(t=>{t&&typeof t=="object"&&n.forEach((i,r)=>{t[r]!==i.value&&(i.value=t[r])})}),new Proxy(e,{get(t,i){if(i in t||typeof i=="symbol"||i==="constructor"||t.hasOwnProperty(i))return Reflect.get(t,i);if(!n.has(i)){const r=t.value?t.value[i]:void 0,u=E(r),a=Object.getOwnPropertyDescriptor(w.prototype,"value").set;Object.defineProperty(u,"value",{get(){return y&&u.track(y),u._value},set(s){if(u._value!==s&&(a.call(u,s),t.value&&typeof t.value=="object")){const d=Array.isArray(t.value)?[...t.value]:{...t.value};d[i]=s,Object.getOwnPropertyDescriptor(w.prototype,"value").set.call(t,d)}}}),n.set(i,u)}return y&&n.get(i)?.track(y),n.get(i)}})}return e};function C(o){const e=()=>{y=e;try{o()}finally{y=null}};e()}const k=new Map;function M(o,e){return k.has(o)||k.set(o,E(e)),k.get(o)}class x{zone;registry=new Map;constructor(e){this.zone=e}connect(e,n){if(e.startsWith("global:")){const t=e.slice(7);return M(t,n)}return this.registry.has(e)||this.registry.set(e,E(n)),this.registry.get(e)}infuse(e,n){return this.connect(e,n)}extract(e){return this.connect(e)}destroy(){this.registry.clear()}}function W(o){return new x(o)}const I={track:o=>{window.dispatchEvent(new CustomEvent("cellui:mount",{detail:{timestamp:Date.now(),target:o}}))},panic:(o,e)=>{console.error("[CellUI Shield] Fatal render error:",e);const n=e instanceof Error?e.message:String(e);o.innerHTML=`
2
+ <div style="padding: 20px; border: 2px solid #ff4444; border-radius: 8px; background: #fff0f0; color: #ff4444; font-family: monospace;">
3
+ <h3 style="margin-top: 0;">CellUI Render Error</h3>
4
+ <pre style="white-space: pre-wrap; word-break: break-word;">${n}</pre>
5
+ </div>
6
+ `,window.dispatchEvent(new CustomEvent("cellui:panic",{detail:{error:e,target:o}}))}},v=new WeakMap;let T=null;function $(){T||typeof window>"u"||(T=new MutationObserver(o=>{for(const e of o)for(const n of Array.from(e.removedNodes)){const t=v.get(n);if(t&&(t.forEach(i=>{try{i()}catch(r){console.error("[CellUI] Error in onDispose callback:",r)}}),v.delete(n)),n.nodeType===1&&typeof document<"u"){const i=document.createTreeWalker(n,NodeFilter.SHOW_ELEMENT);let r=i.nextNode();for(;r;){const u=v.get(r);u&&(u.forEach(a=>{try{a()}catch(s){console.error("[CellUI] Error in onDispose callback:",s)}}),v.delete(r)),r=i.nextNode()}}}}),T.observe(document.body,{childList:!0,subtree:!0}))}const _={Shield:I,onDispose:(o,e)=>{$(),v.has(o)||v.set(o,[]),v.get(o).push(e)},bind:o=>({__cellui_directive:"bind",signal:o}),initSubstrate:()=>($(),new x("__cellui_root__")),Hydrator:{isHydrating:!1,popContext:()=>null},dispose:o=>{const e=v.get(o);e&&(e.forEach(i=>i()),v.delete(o));const n=document.createTreeWalker(o,NodeFilter.SHOW_ELEMENT);let t=n.nextNode();for(;t;){const i=v.get(t);i&&(i.forEach(r=>r()),v.delete(t)),t=n.nextNode()}window.dispatchEvent(new CustomEvent("cellui:unmount",{detail:{target:o}}))}},V=_.bind;function F(o,...e){const n=document.createElement("template");if(_.Hydrator.isHydrating){const a=_.Hydrator.popContext();return a&&e.forEach((s,d)=>{if(typeof s=="function"&&a.events.has(d)){const f=a.events.get(d),c=o[d].match(/on([a-z]+)=/);c&&f.addEventListener(c[1],s)}else if(s&&typeof s=="object"&&s.__cellui_directive==="bind"){const f=s.signal,c=a.binds.get(d);if(c){f.bindNode(c,(h,p)=>{c.type==="checkbox"||c.type==="radio"?h.checked=!!p:h.value=String(p)});const l=h=>{const p=h.target;p.type==="checkbox"?f.value=p.checked:f.value=p.value},m=c.type==="checkbox"||c.type==="radio"||c.tagName==="SELECT"?"change":"input";c.addEventListener(m,l)}}else if(s instanceof w){const f=a.markers.get(d);if(f){const c=f.nextSibling;if(c&&c.nodeType===3){const l=String(s.value);c.nodeValue.length>l.length&&c.splitText(l.length),s.bindNode(c,(m,h)=>{m.nodeValue=String(h)})}else{const l=document.createTextNode("");f.parentNode.insertBefore(l,f.nextSibling),s.bindNode(l,(m,h)=>{m.nodeValue=String(h)})}}}else if(typeof s=="function"&&a.markers.has(d)){const f=a.markers.get(d);if(f){const c=f.nextSibling;if(c&&c.nodeType===3){const l=String(s());c.nodeValue.length>l.length&&c.splitText(l.length),C(()=>{c.nodeValue=String(s())})}else{const l=document.createTextNode("");f.parentNode.insertBefore(l,f.nextSibling),C(()=>{l.nodeValue=String(s())})}}}}),null}n.innerHTML=o.reduce((a,s,d)=>a+s+(d<e.length?`__nex_${d}__`:""),"");const t=n.content.cloneNode(!0);t.querySelectorAll("*").forEach(a=>{Array.from(a.attributes).forEach(s=>{const d=s.value.match(/__nex_(\d+)__/)||s.name.match(/__nex_(\d+)__/);if(d){const f=parseInt(d[1],10),c=e[f];if(typeof c=="function"&&s.name.startsWith("on")){const l=s.name.slice(2).toLowerCase();a.addEventListener(l,c),a.removeAttribute(s.name)}else if(c&&typeof c=="object"&&c.__cellui_directive==="bind"){const l=c.signal,m=a.getAttribute("type");m==="checkbox"||m==="radio"?l.bindNode(a,(p,b)=>{p.checked=!!b}):l.bindNode(a,(p,b)=>{p.value=String(b)});const h=m==="checkbox"||m==="radio"||a.tagName==="SELECT"?"change":"input";a.addEventListener(h,p=>{const b=p.target;m==="checkbox"?l.value=b.checked:l.value=b.value}),a.removeAttribute(s.name)}else if(c instanceof w){const l=s.name;c.bindNode(a,(m,h)=>{m.setAttribute(l,String(h))})}else a.setAttribute(s.name,s.value.replace(/__nex_\d+__/,String(c)))}})});const r=document.createTreeWalker(t,4);let u=r.nextNode();for(;u;){const a=u.nodeValue?.match(/__nex_(\d+)__/);if(a){const s=parseInt(a[1],10),d=e[s],f=u.nodeValue.split(`__nex_${s}__`);u.nodeValue=f[0];const c=document.createTextNode(""),l=document.createTextNode(f.slice(1).join(`__nex_${s}__`));u.parentNode.insertBefore(c,u.nextSibling),u.parentNode.insertBefore(l,c.nextSibling),d instanceof w?d.bindNode(c,(m,h)=>{m.nodeValue=String(h)}):d&&typeof d=="object"&&d.__cellui_directive==="bind"?c.nodeValue="":typeof d=="function"?C(()=>{c.nodeValue=String(d())}):d instanceof Node?c.replaceWith(d):c.nodeValue=String(d),u=l}else u=r.nextNode()}return t}async function B(o,e){const n=typeof o=="string"?document.querySelector(o):o;if(!n)throw new Error(`[CellUI] Mount target not found: ${o}`);_.initSubstrate();const t=window.requestIdleCallback||(i=>setTimeout(i,0));return new Promise(i=>{t(()=>{try{const r=e();n.replaceChildren(r),_.Shield.track(n)}catch(r){_.Shield.panic(n,r)}i(()=>{_.dispose(n),n.innerHTML=""})})})}function j(o,...e){let n="";for(let t=0;t<o.length;t++){let i=o[t];if(t>0&&typeof e[t-1]=="function"&&/on[a-z]+=["']?$/.test(o[t-1])&&(i=i.replace(/^["']/,"")),t<e.length){const r=e[t];if(typeof r=="function"&&/on[a-z]+=["']?$/.test(i))i=i.replace(/\s*on[a-z]+=["']?$/,""),n+=i+` data-cellui-on-${t}=""`;else if(n+=i,r instanceof w)n+=`<!--cellui-marker:${t}-->${r.value}`;else if(r&&typeof r=="object"&&r.__cellui_directive==="bind"){const u=r.signal;n+=` value="${u.value}" data-cellui-bind-${t}=""`}else typeof r=="function"?n+=`<!--cellui-computed-marker:${t}-->${r()}`:r&&typeof r=="object"&&r.__cellui_ssr_template?n+=`<!--cellui-open:${t}-->${r.html}<!--cellui-close:${t}-->`:r instanceof Array?n+=`<!--cellui-list-open:${t}-->${r.join("")}<!--cellui-list-close:${t}-->`:n+=String(r)}else n+=i}return{__cellui_ssr_template:!0,html:n,toString(){return this.html}}}const A={queue:[],start(o){_.Hydrator.isHydrating=!0,this.queue=this.buildQueue(o),_.Hydrator.popContext=()=>this.queue.shift()},end(){_.Hydrator.isHydrating=!1,this.queue=[],_.Hydrator.popContext=()=>null},buildQueue(o){const e=document.createTreeWalker(o,NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_ELEMENT);let n={markers:new Map,events:new Map,binds:new Map};const t=[n],i=[];for(;e.nextNode();){const r=e.currentNode;if(r.nodeType===8){const u=r.nodeValue||"";if(u.startsWith("cellui-marker:")||u.startsWith("cellui-computed-marker:"))n.markers.set(parseInt(u.split(":")[1],10),r);else if(u.startsWith("cellui-open:")){const a={markers:new Map,events:new Map,binds:new Map};t.push(a),n=a}else u.startsWith("cellui-close:")&&(i.push(n),t.pop(),n=t[t.length-1])}else if(r.nodeType===1){const u=r;for(let a=0;a<u.attributes.length;a++){const s=u.attributes[a];s.name.startsWith("data-cellui-on-")?(n.events.set(parseInt(s.name.split("-").pop(),10),u),u.removeAttribute(s.name),a--):s.name.startsWith("data-cellui-bind-")&&(n.binds.set(parseInt(s.name.split("-").pop(),10),u),u.removeAttribute(s.name),a--)}}}return i.push(t[0]),i}};function L(o,e){A.start(o),e(),A.end()}function D(o,e){if(typeof document>"u"){const a=typeof o=="function"?!!o():!!o.value;let s;return typeof e=="function"?s=a?e:void 0:s=a?e.true:e.false,s?s():{__cellui_ssr_template:!0,html:"",toString(){return""}}}const n=document.createDocumentFragment(),t=document.createComment("when-anchor");n.appendChild(t);let i=[],r=!0,u;return typeof o=="function"?u=E(o()):u=o,u.bindNode(t,(a,s)=>{const d=!!s;let f;if(typeof e=="function"?f=d?e:void 0:f=d?e.true:e.false,i.forEach(l=>{if(l.nodeType===1&&typeof l.getAnimations=="function"){const m=l.getAnimations();if(m.length>0){Promise.all(m.map(h=>h.finished)).then(()=>{l.parentNode&&!i.includes(l)&&l.parentNode.removeChild(l)}).catch(()=>{l.parentNode&&!i.includes(l)&&l.parentNode.removeChild(l)});return}}l.parentNode?.removeChild(l)}),i=[],f){const l=f();if(l instanceof DocumentFragment?i=Array.from(l.childNodes):i=[l],r)i.forEach(m=>n.appendChild(m));else if(a.parentNode){let m=a.nextSibling;i.forEach(h=>{a.parentNode.insertBefore(h,m)})}}r=!1}),n}function O(o,e,n){if(typeof document>"u")return{__cellui_ssr_template:!0,html:o.value.map((d,f)=>{const c=n(d,f);return c?c.html:""}).join(""),toString(){return this.html}};const t=document.createDocumentFragment(),i=document.createComment("each-anchor");t.appendChild(i);let r=new Map,u=!0;return o.bindNode(i,(a,s)=>{const d=new Map,f=a.parentNode,c=(h,p)=>typeof e=="function"?e(h,p):String(h[e]),l=new Set(s.map((h,p)=>c(h,p)));r.forEach((h,p)=>{l.has(p)||h.forEach(b=>{if(b.nodeType===1&&typeof b.getAnimations=="function"){const S=b.getAnimations();if(S.length>0){Promise.all(S.map(N=>N.finished)).then(()=>{b.parentNode&&!r.has(p)&&b.parentNode.removeChild(b)}).catch(()=>{b.parentNode&&!r.has(p)&&b.parentNode.removeChild(b)});return}}b.parentNode?.removeChild(b)})});let m=a;s.forEach((h,p)=>{const b=c(h,p);let S=[];if(r.has(b))S=r.get(b);else{const N=n(h,p);N instanceof DocumentFragment?S=Array.from(N.childNodes):S=[N]}d.set(b,S),u?S.forEach(N=>{t.appendChild(N),m=N}):f&&S.forEach(N=>{const H=m.nextSibling;N!==H&&f.insertBefore(N,H),m=N})}),r=d,u=!1}),t}function R(o,e,n){const t=document.createDocumentFragment(),i=document.createComment("match-anchor");t.appendChild(i);let r=[],u=!0;return o.bindNode(i,(a,s)=>{const d=e[s]||n;if(r.forEach(f=>f.parentNode?.removeChild(f)),r=[],d){const f=d();if(f instanceof DocumentFragment?r=Array.from(f.childNodes):r=[f],u)r.forEach(c=>t.appendChild(c));else if(a.parentNode){let c=a.nextSibling;r.forEach(l=>{a.parentNode.insertBefore(l,c)})}}u=!1}),t}g.CellUI=_,g.Signal=w,g.Substrate=x,g.ambient=M,g.bind=V,g.createSubstrate=W,g.each=O,g.effect=C,g.hydrate=L,g.match=R,g.mount=B,g.serverView=j,g.signal=E,g.view=F,g.when=D,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})}));
package/dist/core.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { Signal } from './signal';
2
+ import { Substrate } from './substrate';
3
+ export declare const Shield: {
4
+ track: (container: Element) => void;
5
+ panic: (container: Element, error: unknown) => void;
6
+ };
7
+ export declare const CellUI: {
8
+ Shield: {
9
+ track: (container: Element) => void;
10
+ panic: (container: Element, error: unknown) => void;
11
+ };
12
+ onDispose: (node: Node, callback: () => void) => void;
13
+ bind: (signal: Signal<any>) => {
14
+ __cellui_directive: string;
15
+ signal: Signal<any>;
16
+ };
17
+ initSubstrate: () => Substrate;
18
+ Hydrator: {
19
+ isHydrating: boolean;
20
+ popContext: () => any;
21
+ };
22
+ dispose: (container: Element) => void;
23
+ };
24
+ export declare const bind: (signal: Signal<any>) => {
25
+ __cellui_directive: string;
26
+ signal: Signal<any>;
27
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/each.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { Signal } from './signal';
2
+ export declare function each<T>(listSignal: Signal<T[]>, keyProp: keyof T | ((item: T, index: number) => string | number), renderFn: (item: T, index: number) => Node | DocumentFragment): DocumentFragment | any;
@@ -0,0 +1,12 @@
1
+ export interface MarkerContext {
2
+ markers: Map<number, Comment>;
3
+ events: Map<number, Element>;
4
+ binds: Map<number, Element>;
5
+ }
6
+ export declare const CellUIHydration: {
7
+ queue: MarkerContext[];
8
+ start(container: Element): void;
9
+ end(): void;
10
+ buildQueue(container: Element): MarkerContext[];
11
+ };
12
+ export declare function hydrate(container: Element, componentFn: () => any): void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ export { Signal, signal, effect } from './signal';
2
+ export { CellUI, bind } from './core';
3
+ export { ambient } from './ambient';
4
+ export { createSubstrate, Substrate } from './substrate';
5
+ export { view, mount } from './view';
6
+ export { serverView } from './server/index';
7
+ export { hydrate } from './hydrate';
8
+ export { when } from './when';
9
+ export { each } from './each';
10
+ export { match } from './match';
@@ -0,0 +1,2 @@
1
+ import { Signal } from './signal';
2
+ export declare function match<T extends string | number | symbol>(condition: Signal<T>, cases: Record<T, () => Node | DocumentFragment>, defaultCase?: () => Node | DocumentFragment): DocumentFragment;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A theoretical stringifier that enables CellUI to render HTML on a Node.js server.
3
+ * Returns a static HTML string with deterministic CellUI hydration markers instead of a DocumentFragment.
4
+ */
5
+ export declare function serverView(strings: TemplateStringsArray, ...values: any[]): any;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ export type Subscriber<T> = (val: T) => void;
2
+ export declare class Signal<T> {
3
+ protected _value: T;
4
+ protected _subscribers: Set<Subscriber<T>>;
5
+ protected _weakSubscribers: Set<{
6
+ ref: WeakRef<Node>;
7
+ updater: (node: Node, val: T) => void;
8
+ }>;
9
+ constructor(initialValue: T);
10
+ get value(): T;
11
+ set value(newValue: T);
12
+ subscribe(fn: Subscriber<T>): () => boolean;
13
+ track(fn: Subscriber<T>): () => boolean;
14
+ bindNode(node: Node, updater: (node: Node, val: T) => void): void;
15
+ }
16
+ export type DeepSignal<T> = Signal<T> & (T extends object ? {
17
+ [K in keyof T]: DeepSignal<T[K]>;
18
+ } : {});
19
+ export declare const signal: <T>(val: T) => DeepSignal<T>;
20
+ export declare function effect(fn: () => void): void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { DeepSignal } from './signal';
2
+ export declare class Substrate {
3
+ zone: string;
4
+ private registry;
5
+ constructor(zone: string);
6
+ connect<T>(key: string, initialValue?: T): DeepSignal<T>;
7
+ infuse<T>(key: string, initialValue: T): DeepSignal<T>;
8
+ extract<T>(key: string): DeepSignal<T>;
9
+ destroy(): void;
10
+ }
11
+ export declare function createSubstrate(zoneName: string): Substrate;
package/dist/view.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function view(strings: TemplateStringsArray, ...values: any[]): DocumentFragment;
2
+ export declare function mount(selector: string | HTMLElement, component: () => DocumentFragment): Promise<() => void>;
@@ -0,0 +1 @@
1
+ export {};
package/dist/when.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Signal } from './signal';
2
+ export declare function when(condition: Signal<any> | (() => any), views: (() => Node | DocumentFragment) | {
3
+ true?: () => Node | DocumentFragment;
4
+ false?: () => Node | DocumentFragment;
5
+ }): DocumentFragment | any;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@cmj/cellui",
3
+ "version": "0.1.3",
4
+ "description": "A minimalist, fine-grained reactive UI framework without Virtual DOM.",
5
+ "type": "module",
6
+ "main": "./dist/cellui.umd.cjs",
7
+ "module": "./dist/cellui.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/cellui.js",
13
+ "require": "./dist/cellui.umd.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "dev": "vite example",
21
+ "build": "tsc && vite build",
22
+ "test": "vitest run"
23
+ },
24
+ "keywords": [
25
+ "signals",
26
+ "reactivity",
27
+ "framework",
28
+ "ui"
29
+ ],
30
+ "author": "",
31
+ "license": "ISC",
32
+ "devDependencies": {
33
+ "@types/jsdom": "^21.1.7",
34
+ "jsdom": "^28.1.0",
35
+ "typescript": "^5.9.3",
36
+ "vite": "^7.3.1",
37
+ "vite-plugin-dts": "^4.5.3",
38
+ "vitest": "^4.0.18"
39
+ }
40
+ }