@daz4126/helium 0.11.1 → 0.12.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 +56 -46
  2. package/package.json +1 -1
package/helium.js CHANGED
@@ -9,62 +9,65 @@ export default function helium(data = {}) {
9
9
  const $ = s => document.querySelector(s);
10
10
  const html = s => Object.assign(document.createElement("template"),{innerHTML:s.trim()}).content.firstChild
11
11
 
12
- const ajax=(u,m,o={},p={})=>{
13
- console.log("ajax: ", u,m,o.target,p)
14
- const fd=p instanceof FormData,t=document.querySelector('meta[name="csrf-token"]')?.content;
15
- fetch(u,{method:m,headers:{
16
- Accept:"text/vnd.turbo-stream.html,application/json,text/html",
17
- ...(!fd&&m!=="GET"&&{"Content-Type":"application/json"}),
18
- ...(t&&{"X-CSRF-Token":t})
19
- },body:m==="GET"?null:(fd?p:JSON.stringify(p)),credentials:"same-origin"})
20
- .then(r=>r.headers.get("content-type")?.includes("json")?r.json():r.text())
21
- .then(d=>{
22
- if(o.data)state[o.data]=d;
23
- if(o.target){
24
- const c=o.template?o.template(d):d;
25
- o.action?o.target[o.action=="replace"?"replaceWith":o.action](html(c)):o.target.innerHTML=c;
26
- }
27
- }).catch(e=>{
28
- console.error("AJAX:",e.message);
29
- })
30
- }
12
+ const update = (data,target,action,template) => {
13
+ const element = target instanceof Node ? target : (refs.get(target) || $(target));
14
+ if(element){
15
+ const content = html(template ? template(data) : data);
16
+ action ? element[action=="replace"?"replaceWith":action](content) : element.innerHTML = content;
17
+ return content
18
+ } else state[target] = data
19
+ }
20
+
21
+
22
+ const ajax = (u,m,o={},p={}) => {
23
+ if(o.loading) o.target = update(o.loading,o.target,o.action) || o.target;
24
+ const fd = p instanceof FormData, t = document.querySelector('meta[name="csrf-token"]')?.content;
25
+ fetch(u,{method:m,headers:{
26
+ Accept:"text/vnd.turbo-stream.html,application/json,text/html",
27
+ ...(!fd&&m!=="GET"&&{"Content-Type":"application/json"}),
28
+ ...(t&&{"X-CSRF-Token":t})
29
+ },body:m==="GET"?null:(fd?p:JSON.stringify(p)),credentials:"same-origin"})
30
+ .then(r=>r.headers.get("content-type")?.includes("json")?r.json():r.text())
31
+ .then(d=>o.loading?update(d,o.target,"replace",o.template):update(d,o.target,o.action,o.template))
32
+ .catch(e=>console.error("AJAX:",e.message));
33
+ }
31
34
 
32
35
  const get = (u,t) => ajax(u,"GET",t);
33
36
  const [post, put, patch, del] = ["POST","PUT","PATCH","DELETE"].map(m => (u, d, t) => ajax(u, m, t, d));
34
37
 
35
38
  const handler = {
36
- get: (t, p, r) => {const v = Reflect.get(t, p, r); return typeof v == "object" && v != null ? new Proxy(v, handler) : v},
37
- set: (t, p, v) => {const res = Reflect.set(t, p, v); bindings.get(p)?.forEach(applyBinding); return res}
39
+ get: (t,p,r) => {const v = Reflect.get(t,p,r); return typeof v==="object"&&v!==null ? new Proxy(v,handler) : v},
40
+ set: (t,p,v) => {const res = Reflect.set(t,p,v); bindings.get(p)?.forEach(applyBinding); return res}
38
41
  };
39
42
 
40
43
  const state = new Proxy(data, handler);
41
44
  let isUpdatingDOM = false;
42
45
 
43
46
  function applyBinding(b,e={},elCtx=b.el){
44
- const {el,prop,fn}=b;
45
- const r=fn($,state,e,elCtx,html,...Object.values(data),...[...refs.values()]);
46
- if(prop=="innerHTML"){isUpdatingDOM=1;el.innerHTML=Array.isArray(r)?r.join``:r;isUpdatingDOM=0}
47
- 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));
48
- else if(prop=="style"&&r&&typeof r=="object")el.style=Object.entries(r).filter(([,v])=>v).map(([k,v])=>`${k}:${v}`).join(";")
49
- else if(prop in el){if(el.type=="radio")el.checked=el.value==r;else el[prop]=prop=="textContent"?r:parseEx(r)}
50
- else el.setAttribute(prop,parseEx(r))
51
- }
47
+ const {el,prop,fn}=b;
48
+ const r=fn($,state,e,elCtx,html,...Object.values(data),...[...refs.values()]);
49
+ if(prop==="innerHTML"){isUpdatingDOM=1;el.innerHTML=Array.isArray(r)?r.join``:r;isUpdatingDOM=0}
50
+ 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));
51
+ else if(prop==="style"&&r&&typeof r==="object")el.style=Object.entries(r).filter(([,v])=>v).map(([k,v])=>`${k}:${v}`).join(";")
52
+ else if(prop in el){if(el.type==="radio")el.checked=el.value===r;else el[prop]=prop==="textContent"?r:parseEx(r)}
53
+ else el.setAttribute(prop,parseEx(r))
54
+ }
52
55
 
53
56
  const compile = (expr, withReturn = false) => {
54
57
  try {
55
- return new Function("$", "$data", "$event", "$el", "$html","$get", "$post", "$put","$patch","$delete",...Object.keys(data), ...[...refs.keys()],
56
- `with($data){${withReturn ? "return" : ""}(${expr.trim()})}`);
58
+ return new Function("$","$data","$event","$el","$html","$get","$post","$put","$patch","$delete",...Object.keys(data),...[...refs.keys()],
59
+ `with($data){${withReturn?"return":""}(${expr.trim()})}`);
57
60
  } catch {return () => expr}
58
61
  };
59
62
 
60
- const trackDependencies=fn=>{
61
- const s=new Set(),p=new Proxy(state,{get:(t,k)=>{if(typeof k=="string")s.add(k);const v=t[k];return v&&typeof v=="object"?new Proxy(v,this):v}});
62
- try{fn($,p,refs)}catch{};return[...s]
63
- }
63
+ const trackDependencies = fn => {
64
+ const s=new Set(),p=new Proxy(state,{get:(t,k)=>{if(typeof k==="string")s.add(k);const v=t[k];return v&&typeof v==="object"?new Proxy(v,this):v}});
65
+ try{fn($,p,refs)}catch{};return[...s]
66
+ }
64
67
 
65
68
  const cleanup = el => {
66
- [el, ...el.querySelectorAll('*')].forEach(e => {
67
- listeners.get(e)?.forEach(({receiver, event, handler}) => receiver.removeEventListener(event, handler));
69
+ [el,...el.querySelectorAll('*')].forEach(e => {
70
+ listeners.get(e)?.forEach(({receiver,event,handler}) => receiver.removeEventListener(event,handler));
68
71
  listeners.delete(e);
69
72
  });
70
73
  };
@@ -151,14 +154,21 @@ const trackDependencies=fn=>{
151
154
  }
152
155
  if (!mods.includes("outside") || !el.contains(e.target)) {
153
156
  if (isHttpMethod) {
154
- const options = exFn(el.getAttribute('data-he-options') || el.getAttribute('options') || '{}');
155
- let paramsAttr = el.getAttribute('data-he-params') || el.getAttribute('params') || '{}';
157
+ const getAttr = name => el.getAttribute(`data-he-${name}`) || el.getAttribute(`@${name}`);
158
+ const [target, action] = (getAttr('target') || "").split(":");
159
+ const options = {
160
+ ...exFn(getAttr('options') || '{}'),
161
+ ...(target && { target }),
162
+ ...(action && { action }),
163
+ ...execFn(getAttr('template')) && { template: execFn(getAttr('template')) },
164
+ ...getAttr('loading') && { loading: getAttr('loading') }
165
+ };
166
+ let paramsAttr = getAttr('params') || '{}';
156
167
  if (!paramsAttr.trim().startsWith("{") && paramsAttr.includes(":")) {
157
168
  const props = paramsAttr.split(":").map(s => s.trim());
158
169
  paramsAttr = props.reduceRight((acc, key, i) => `{ ${key}: ${i == 1 ? `'${el[acc]}'` : acc} }`);
159
170
  }
160
171
  const params = exFn(paramsAttr);
161
- console.log("params: ",params)
162
172
  ajax(value, eventName.toUpperCase(), options, params);
163
173
  } else {
164
174
  exFn(value);
@@ -176,12 +186,12 @@ const trackDependencies=fn=>{
176
186
  return newBindings;
177
187
  }
178
188
  new MutationObserver(ms=>{
179
- if(isUpdatingDOM)return;
180
- for(const m of ms){
181
- m.removedNodes.forEach(n=>n.nodeType==1&&cleanup(n));
182
- m.addedNodes.forEach(n=>n.nodeType==1&&!n.hasAttribute("data-he-p")&&processElements(n).forEach(applyBinding));
183
- }
184
- }).observe(root,{childList:1,subtree:1});
189
+ if(isUpdatingDOM)return;
190
+ for(const m of ms){
191
+ m.removedNodes.forEach(n=>n.nodeType===1&&cleanup(n));
192
+ m.addedNodes.forEach(n=>n.nodeType===1&&!n.hasAttribute("data-he-p")&&processElements(n).forEach(applyBinding));
193
+ }
194
+ }).observe(root,{childList:1,subtree:1});
185
195
  processElements(root);
186
196
  for (const [key, items] of bindings.entries()) items.forEach(applyBinding);
187
197
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daz4126/helium",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "main": "helium.js",
5
5
  "type": "module",
6
6
  "scripts": {