@daz4126/helium 0.13.0 → 0.14.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.
Files changed (2) hide show
  1. package/helium.js +63 -17
  2. package/package.json +1 -1
package/helium.js CHANGED
@@ -6,7 +6,7 @@ export default function helium(data = {}) {
6
6
  let initFn;
7
7
  const he = (n,...a) => a.map(b => `|@${b}|data-he-${b}|`).join``.includes(`|${n.split('.')[0]}|`);
8
8
  const root = document.querySelector("[\\@helium]") || document.querySelector("[data-helium]") || document.body;
9
- const [bindings, refs, listeners, processed] = [new Map(), new Map(), new WeakMap(), new WeakSet()];
9
+ const [bindings, refs, listeners, processed, parentKeys] = [new Map(), new Map(), new WeakMap(), new WeakSet(), new WeakMap()];
10
10
  const $ = s => document.querySelector(s);
11
11
  const html = s => Object.assign(document.createElement("template"),{innerHTML:s.trim()}).content.firstChild
12
12
 
@@ -17,8 +17,7 @@ export default function helium(data = {}) {
17
17
  action ? element[action=="replace"?"replaceWith":action](content) : element.innerHTML = content;
18
18
  return content
19
19
  } else state[target] = data
20
- }
21
-
20
+ }
22
21
 
23
22
  const ajax = (u,m,o={},p={}) => {
24
23
  if(o.loading) o.target = update(o.loading,o.target,o.action) || o.target;
@@ -43,22 +42,71 @@ const ajax = (u,m,o={},p={}) => {
43
42
  const get = (u,t) => ajax(u,"GET",t);
44
43
  const [post, put, patch, del] = ["POST","PUT","PATCH","DELETE"].map(m => (u, d, t) => ajax(u, m, t, d));
45
44
 
46
- const handler = {
47
- get: (t,p,r) => {const v = Reflect.get(t,p,r); return typeof v==="object"&&v!==null ? new Proxy(v,handler) : v},
48
- set: (t,p,v) => {const res = Reflect.set(t,p,v); bindings.get(p)?.forEach(applyBinding); return res}
49
- };
45
+ const handler = {
46
+ get: (t,p,r) => {
47
+ const v = Reflect.get(t,p,r);
48
+ if (typeof v==="object" && v!==null) {
49
+ const proxy = new Proxy(v, handler);
50
+ parentKeys.set(v, p);
51
+ return proxy;
52
+ }
53
+ return v;
54
+ },
55
+ set: (t,p,v) => {
56
+ const res = Reflect.set(t,p,v);
57
+ if (Array.isArray(t) && !isNaN(p)) {
58
+ const parentKey = parentKeys.get(t);
59
+ if (parentKey) bindings.get(parentKey)?.forEach(applyBinding);
60
+ }
61
+ bindings.get(p)?.forEach(applyBinding);
62
+ return res
63
+ }
64
+ };
50
65
 
51
66
  const state = new Proxy(data, handler);
52
- let isUpdatingDOM = false;
53
67
 
54
68
  function applyBinding(b,e={},elCtx=b.el){
55
69
  const {el,prop,fn}=b;
56
70
  const r=fn($,state,e,elCtx,html,...Object.values(data),...[...refs.values()]);
57
- if(prop==="innerHTML"){
58
- isUpdatingDOM=1;
59
- const content = el.innerHTML=Array.isArray(r)?r.join``:r
71
+ if(prop==="innerHTML" && Array.isArray(r) && el.children.length > 0){
72
+ const temp = html(`<${el.tagName.toLowerCase()}>${r.join``}</${el.tagName.toLowerCase()}>`);
73
+ const newChildren = [...temp.children];
74
+
75
+ const newItems = newChildren.map((child, idx) => ({
76
+ key: child.getAttribute("key") || child.dataset.key,
77
+ element: child,
78
+ index: idx
79
+ }));
80
+
81
+ const existingItems = [...el.children].map((child, idx) => ({
82
+ key: child.getAttribute("key") || child.dataset.key,
83
+ element: child,
84
+ index: idx
85
+ }));
86
+
87
+ for (let i = 0; i < Math.max(newItems.length, existingItems.length); i++) {
88
+ const existing = existingItems[i];
89
+ const newItem = newItems[i];
90
+
91
+ if (!newItem && existing) {
92
+ cleanup(existing.element);
93
+ existing.element.remove();
94
+ } else if (newItem && !existing) {
95
+ el.appendChild(newItem.element);
96
+ } else if (newItem && existing) {
97
+ if (existing.element.outerHTML !== newItem.element.outerHTML) {
98
+ if(typeof Idiomorph === "object") {
99
+ Idiomorph.morph(existing.element, newItem.element.outerHTML);
100
+ } else {
101
+ cleanup(existing.element);
102
+ existing.element.replaceWith(newItem.element);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ } else if(prop==="innerHTML"){
108
+ const content = Array.isArray(r)?r.join``:r
60
109
  typeof Idiomorph === "object" ? Idiomorph.morph(el, content,{morphStyle:'innerHTML'}) : el.innerHTML = content;
61
- isUpdatingDOM=0
62
110
  }
63
111
  else if(prop==="class"&&r&&typeof r==="object")for(const[k,v]of Object.entries(r))k.split(/\s+/).forEach(c=>el.classList.toggle(c,v));
64
112
  else if(prop==="style"&&r&&typeof r==="object")el.style=Object.entries(r).filter(([,v])=>v).map(([k,v])=>`${k}:${v}`).join(";")
@@ -95,15 +143,14 @@ const trackDependencies = (fn, el) => {
95
143
  };
96
144
 
97
145
  function processElements(element) {
146
+ let count = 0
98
147
  const newBindings = [];
99
- if (element.nodeType == 1) {
100
- if (processed.has(element)) return newBindings;
101
- processed.add(element);
102
- }
148
+ if (element.nodeType == 1 && processed.has(element)) return newBindings;
103
149
 
104
150
  const heElements=[element,...element.querySelectorAll("*")].filter(e=>[...e.attributes].some(a=>/^(@|:|data-he)/.test(a.name)))
105
151
 
106
152
  heElements.forEach(el => {
153
+ count++
107
154
  for (const {name, value} of el.attributes || []) {
108
155
  if (he(name,"text","html","bind")) {
109
156
  try {
@@ -211,7 +258,6 @@ const trackDependencies = (fn, el) => {
211
258
  return newBindings;
212
259
  }
213
260
  new MutationObserver(ms=>{
214
- if(isUpdatingDOM)return;
215
261
  for(const m of ms){
216
262
  m.removedNodes.forEach(n=>n.nodeType===1&&cleanup(n));
217
263
  m.addedNodes.forEach(n=>n.nodeType===1&&!processed.has(n)&&processElements(n).forEach(applyBinding));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daz4126/helium",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "main": "helium.js",
5
5
  "type": "module",
6
6
  "scripts": {