@potch/munifw 1.0.0 → 2.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/README.md CHANGED
@@ -26,7 +26,7 @@ Create an event bus. The bus consists of two methods, an `emit` and an `on` meth
26
26
  ```js
27
27
  function clock() {
28
28
  const start = Date.now();
29
- const [onUpdate, emitUpdate] = event();
29
+ const [emitUpdate, onUpdate] = event();
30
30
  setInterval(() => {
31
31
  emitUpdate(start - Date.now());
32
32
  }, 1000);
@@ -1 +1 @@
1
- const t="value",e=t=>"object"==typeof t,n=(t,e)=>[...t].map(e);export const using=(t,e)=>(e(),t());export const collect=(t,e,n=[])=>(using(t(t=>n.push(t)),e),n);export const event=(t=new Set)=>[(...e)=>n(t,t=>t(...e)),e=>(t.add(e),()=>t.delete(e))];const o=[];export const signal=(e,n=(t,e)=>t===e)=>{const[c,s]=event();return{set[t](t){n(e,t)||(e=t,c())},touch(){c()},get[t](){return o[0]&&o[0].add(this),e},peek:()=>e,watch:s}};export const[emitEffect,onEffect]=event();export const effect=(t,...e)=>{let c=0;o.push(new Set(e));const s=()=>{c||(c=1,t((...t)=>emitEffect(effect(...t))),c=0)};s();const r=n(o.at(-1),t=>t.watch(s));return o.pop(),()=>n(r,t=>t())};export const computed=(e,...n)=>{const o=signal();return o.teardown=effect(()=>o[t]=e(o[t]),...n),o};export const setProp=(n,o,c)=>{"ref"==o&&t in c?c[t]=n:e(c)&&t in c?emitEffect(effect(()=>setProp(n,o,c[t]))):"function"==typeof c||e(c)||o in n?n[o]&&e(n[o])?assign(n[o],c):n[o]=null===c?"":c:null!==c&&(0!=c||o.startsWith("data-")||o.startsWith("aria-"))?n.setAttribute(o,c):n.removeAttribute(o)};export const assign=(t,n)=>(n&&Object.entries(n).forEach(([n,o])=>{t.nodeType?setProp(t,n,o):e(t[n])&&e(o)?assign(t[n],o):t[n]=o}),t);export const dom=(t,n,...o)=>{let c;return"function"==typeof t?c=mount(()=>t(n,o)):(c=document.createElement(t),n&&e(n)&&!n.nodeType?assign(c,n):n&&o.unshift(n),c.append(...o.flat(1))),c};export const mount=(t,...e)=>{const n=[];let o;return emitEffect(effect(()=>{for(;n.length;)try{n.pop()()}catch(t){}collect(onEffect,()=>{const e=t();o&&e&&o.replaceWith(e),o=e},n)},...e)),o};export const on=(t,...e)=>(t.addEventListener(...e),()=>t.removeEventListener(...e));
1
+ const t="value",e=t=>"object"==typeof t,n=(t,e)=>[...t].map(e);export const using=(t,e)=>(e(),t());export const collect=(t,e,n=[])=>(using(t(t=>n.push(t)),e),n);export const event=(t=new Set)=>[(...e)=>n(t,t=>t(...e)),e=>(t.add(e),()=>t.delete(e))];const o=[];export const signal=(e,n=(t,e)=>t===e)=>{const[c,s]=event();return{set[t](t){n(e,t)||(e=t,c())},touch(){c()},get[t](){return o.at(-1)&&o.at(-1).add(this),e},peek:()=>e,watch:s}};export const[emitEffect,onEffect]=event();export const effect=(t,...e)=>{let c=0;o.push(new Set(e));const s=()=>{c||(c=1,t((...t)=>emitEffect(effect(...t))),c=0)};s();const r=n(o.at(-1),t=>t.watch(s));return o.pop(),()=>n(r,t=>t())};export const computed=(e,...n)=>{const o=signal();return o.teardown=effect(()=>o[t]=e(o[t]),...n),o};export const setProp=(n,o,c)=>{"ref"==o&&t in c?c[t]=n:e(c)&&t in c?emitEffect(effect(()=>setProp(n,o,c[t]))):"function"==typeof c||e(c)||o in n?n[o]&&e(n[o])?assign(n[o],c):n[o]=null===c?"":c:null!==c&&(0!=c||o.startsWith("data-")||o.startsWith("aria-"))?n.setAttribute(o,c):n.removeAttribute(o)};export const assign=(t,n)=>(n&&Object.entries(n).forEach(([n,o])=>{t.nodeType?setProp(t,n,o):e(t[n])&&e(o)?assign(t[n],o):t[n]=o}),t);export const dom=(t,n,...o)=>{let c;return"function"==typeof t?c=mount(()=>t(n,o)):(c=document.createElement(t),n&&e(n)&&!n.nodeType?assign(c,n):n&&o.unshift(n),c.append(...o.flat(1))),c};export const mount=(t,...e)=>{const n=[];let o;return emitEffect(effect(()=>{for(;n.length;)try{n.pop()()}catch(t){}collect(onEffect,()=>{const e=t()??document.createComment("");o&&o.replaceWith(e),o=e},n)},...e)),o};export const on=(t,...e)=>(t.addEventListener(...e),()=>t.removeEventListener(...e));
Binary file
package/dist/ssr.min.js CHANGED
@@ -1 +1 @@
1
- const e=/^(area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)$/,t="attributes",r="parentNode",i="childNodes",n=Object,s=(e,t)=>e[i].map(t),o={append(...e){e.map(e=>{e=e?.nodeType?e:a(3,{textContent:""+e}),this[i].push(e),e[r]=this})},replaceWith(e){const t=this[r];t&&(t[i]=s(t,t=>t==this?e:t),e[r]=t)},replaceChildren(...e){s(this,e=>e.remove()),this.append(...e)},setAttribute(e,r){this[t][e]=r},getAttribute(e){return this[t][e]},removeAttribute(e){delete this[t][e]},remove(){const e=this,t=e[r];t&&(t[i]=t[i].filter(t=>t!=e),e[r]=null)},get outerHTML(){const r=this,{tagName:i,nodeType:s}=r;return 1==s?"<"+i+n.entries(r[t]).map(e=>` ${e[0]}="${e[1]}"`).join("")+">"+r.innerHTML+(e.test(i)?"":`</${i}>`):3==s?r.textContent:""},get innerHTML(){return s(this,e=>e.outerHTML).join("")}},a=(e,t)=>n.assign(n.create(o),{nodeType:e},t);export default{createElement:e=>a(1,{tagName:e.toLowerCase(),[t]:{},[i]:[]}),find:(e,r)=>{let n,s=[e];do{if(n=s.pop(),n?.[t]?.id==r)return n;n&&s.push(...n[i])}while(s.length)}};
1
+ const e=/^(area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)$/,t="attributes",r="parentNode",n="childNodes",i=Object,a=(e,t)=>e[n].map(t),s={append(...e){e.map(e=>{e=e?.nodeType?e:o(3,{textContent:""+e}),this[n].push(e),e[r]=this})},replaceWith(e){const t=this[r];t&&(t[n]=a(t,t=>t==this?e:t),e[r]=t)},replaceChildren(...e){a(this,e=>e.remove()),this.append(...e)},setAttribute(e,r){this[t][e]=r},getAttribute(e){return this[t][e]},removeAttribute(e){delete this[t][e]},remove(){const e=this,t=e[r];t&&(t[n]=t[n].filter(t=>t!=e),e[r]=null)},get outerHTML(){const r=this,{tagName:n,nodeType:a}=r;return 1==a?"<"+n+i.entries(r[t]).map(e=>` ${e[0]}="${e[1]}"`).join("")+">"+r.innerHTML+(e.test(n)?"":`</${n}>`):3==a?r.textContent:8==a?`\x3c!--${r.data}--\x3e`:""},get innerHTML(){return a(this,e=>e.outerHTML).join("")}},o=(e,t)=>i.assign(i.create(s),{nodeType:e},t);export default{createElement:e=>o(1,{tagName:e.toLowerCase(),[t]:{},[n]:[]}),createComment:e=>o(8,{data:e}),find:(e,r)=>{let i,a=[e];do{if(i=a.pop(),i?.[t]?.id==r)return i;i&&a.push(...i[n])}while(a.length)}};
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@potch/munifw",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "A signal-driven framework for small applications",
5
5
  "main": "src/munifw.js",
6
6
  "scripts": {
@@ -14,6 +14,6 @@
14
14
  "devDependencies": {
15
15
  "onchange": "^7.1.0",
16
16
  "terser": "^5.29.1",
17
- "vitest": "^2.1.6"
17
+ "vitest": "^2.1.9"
18
18
  }
19
19
  }
package/sizes.md CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  file | original | minified | gzip
4
4
  :--- | ---: | ---: | ---:
5
- src/munifw.js | 5425 | 1662 | 823
6
- src/ssr.js | 2260 | 1027 | 611
5
+ src/munifw.js | 5380 | 1695 | 831
6
+ src/ssr.js | 2397 | 1088 | 649
package/src/munifw.js CHANGED
@@ -44,8 +44,8 @@ export const signal = (value, eq = (a, b) => a === b) => {
44
44
  },
45
45
  get [val]() {
46
46
  // if we're in an effect callback, register as a dep
47
- if (context[0]) {
48
- context[0].add(this);
47
+ if (context.at(-1)) {
48
+ context.at(-1).add(this);
49
49
  }
50
50
  return value;
51
51
  },
@@ -182,12 +182,9 @@ export const mount = (fn, ...explicitDependencies) => {
182
182
  collect(
183
183
  onEffect,
184
184
  () => {
185
- const newEl = fn();
185
+ const newEl = fn() ?? document.createComment("");
186
186
  if (currentEl) {
187
- // swap or remove new element
188
- if (newEl) {
189
- currentEl.replaceWith(newEl);
190
- }
187
+ currentEl.replaceWith(newEl);
191
188
  }
192
189
  currentEl = newEl;
193
190
  },
package/src/ssr.js CHANGED
@@ -65,6 +65,9 @@ const nodeMock = {
65
65
  if (nodeType == 3) {
66
66
  return self.textContent;
67
67
  }
68
+ if (nodeType == 8) {
69
+ return `<!--${self.data}-->`;
70
+ }
68
71
  return "";
69
72
  },
70
73
  get innerHTML() {
@@ -82,8 +85,11 @@ const createElement = (tagName) =>
82
85
  [cn]: [],
83
86
  });
84
87
 
88
+ const createComment = (data) => _node(8, { data });
89
+
85
90
  export default {
86
91
  createElement,
92
+ createComment,
87
93
  // used by ssr instead of getElementById
88
94
  find: (el, id) => {
89
95
  let current,
package/test/ssr.test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import ssr from "../src/ssr.js";
2
2
  vi.stubGlobal("document", ssr);
3
- import { dom } from "../src/munifw.js";
3
+ import { dom, mount, signal } from "../src/munifw.js";
4
4
 
5
5
  describe("createElement", () => {
6
6
  it("makes tags", () => {
@@ -23,6 +23,15 @@ describe("createElement", () => {
23
23
  });
24
24
  });
25
25
 
26
+ describe("createComment", () => {
27
+ it("creates", () => {
28
+ const c = ssr.createComment("foo");
29
+ expect(c.nodeType).toBe(8);
30
+ expect(c.data).toBe("foo");
31
+ expect(c.outerHTML).toBe("<!--foo-->");
32
+ });
33
+ });
34
+
26
35
  describe("nodeMock", () => {
27
36
  it("attributes", () => {
28
37
  const el = ssr.createElement("div");
@@ -62,3 +71,24 @@ describe("nodeMock", () => {
62
71
  expect(a.innerHTML).toBe("bar");
63
72
  });
64
73
  });
74
+
75
+ describe("mount", () => {
76
+ it("basic operation", () => {
77
+ const el = mount(() => dom("div"));
78
+ expect(el.outerHTML).toBe("<div></div>");
79
+ });
80
+ it("signal operation", () => {
81
+ const s = signal(1);
82
+ const el = dom(
83
+ "div",
84
+ mount(() => dom("span", s.value))
85
+ );
86
+ expect(el.outerHTML).toBe("<div><span>1</span></div>");
87
+ s.value = 2;
88
+ expect(el.outerHTML).toBe("<div><span>2</span></div>");
89
+ });
90
+ it("null operation", () => {
91
+ const el = mount(() => null);
92
+ expect(el.outerHTML).toBe("<!---->");
93
+ });
94
+ });