@daz4126/helium 0.17.0 → 0.19.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 +37 -46
  2. package/package.json +1 -1
package/helium.js CHANGED
@@ -8,7 +8,11 @@ let HELIUM = null;
8
8
  window.helium = function() {
9
9
  let initFn;
10
10
  const ALL = Symbol("all");
11
- const he = (n,...a) => a.map(b => `|@${b}|data-he-${b}|`).join``.includes(`|${n.split(/[.:]/)[0]}|`);
11
+ const he = (n,...a) => {
12
+ const prefix = n.split(/[.:]/)[0];
13
+ if (prefix === ":" || prefix === "") return false;
14
+ return a.map(b => `|@${b}|data-he-${b}|`).join``.includes(`|${prefix}|`);
15
+ };
12
16
  const root = document.querySelector("[\\@helium]") || document.querySelector("[data-helium]") || document.body;
13
17
 
14
18
  // Initialize or reuse HELIUM object
@@ -104,7 +108,6 @@ function applyBinding(b,e={},elCtx=b.el){
104
108
  ? Idiomorph.morph(el, content,{morphStyle:'innerHTML'})
105
109
  : el.innerHTML = content;
106
110
  }
107
-
108
111
  if (prop==="class" && r && typeof r==="object")
109
112
  return Object.entries(r).forEach(([k,v]) =>
110
113
  k.split(/\s+/).forEach(c => el.classList.toggle(c,v)));
@@ -114,32 +117,39 @@ function applyBinding(b,e={},elCtx=b.el){
114
117
  .map(([k,v])=>`${k}:${v}`).join(";");
115
118
 
116
119
  if (prop in el) {
117
- if(el.type==="radio") el.checked = el.value===r;
120
+ if (el.type === "radio" && prop != "checked") el.checked = el.value===r;
118
121
  else el[prop] = prop==="textContent"?r:parseEx(r);
119
122
  return;
120
123
  }
121
124
 
122
125
  el.setAttribute(prop, parseEx(r));
123
126
  }
124
-
127
+
125
128
  const compile = (expr, withReturn = false) => {
126
- // Auto-detect if this should be a statement block
127
- const hasStatements = /[;\r\n]/.test(expr);
128
- const useReturn = withReturn && (!hasStatements || expr.trim().startsWith('{') && expr.trim().endsWith('}'));
129
- const key = `${useReturn}:${expr}`;
129
+ const key = `${withReturn}:${expr}`;
130
130
  if (HELIUM.fnCache.has(key)) return HELIUM.fnCache.get(key);
131
131
  try {
132
132
  const fn = new Function(
133
133
  "$","$data","$event","$el","$html","$get","$post","$put","$patch","$delete",
134
134
  ...Object.keys(state), ...[...HELIUM.refs.keys()],
135
- useReturn
135
+ withReturn
136
136
  ? `with($data){return(${expr.trim()})}`
137
137
  : `with($data){${expr.trim()}}`
138
138
  );
139
139
  HELIUM.fnCache.set(key, fn);
140
140
  return fn;
141
141
  } catch {
142
- return () => expr;
142
+ try {
143
+ const fn = new Function(
144
+ "$","$data","$event","$el","$html","$get","$post","$put","$patch","$delete",
145
+ ...Object.keys(state), ...[...HELIUM.refs.keys()],
146
+ `with($data){${expr.trim()}}`
147
+ );
148
+ HELIUM.fnCache.set(key, fn);
149
+ return fn;
150
+ } catch {
151
+ return () => expr;
152
+ }
143
153
  }
144
154
  };
145
155
 
@@ -215,15 +225,14 @@ function processElements(element) {
215
225
  }
216
226
  else if (name.startsWith(":") || name.startsWith("data-he-attr:")) {
217
227
  const fn = compile(value, true);
218
- deferredBindings.push(() => trackDependencies(fn, el).forEach(dep => addBinding(dep, {el, prop: name.slice(name.startsWith(":") ? 1 : 13), fn})));
228
+ deferredBindings.push({el, prop: name.slice(name.startsWith(":") ? 1 : 13), fn});
219
229
  }
220
230
  else if (he(name, "ref")) {
221
231
  HELIUM.refs.set("$" + value, el);
222
232
  }
223
233
  else if (he(name, "text", "html")) {
224
234
  const fn = compile(value, true);
225
- const b = {el, prop: he(name, "text") ? "textContent" : "innerHTML", fn};
226
- deferredBindings.push(() => trackDependencies(fn, el).forEach(dep => addBinding(dep, b)));
235
+ deferredBindings.push({el, prop: he(name, "text") ? "textContent" : "innerHTML", fn});
227
236
  }
228
237
  else if (he(name, "bind")) {
229
238
  const event = (isCheckbox || isRadio || isSelect) ? "change" : "input";
@@ -239,24 +248,17 @@ function processElements(element) {
239
248
  }
240
249
  else if (he(name, "hidden", "visible")) {
241
250
  const fn = compile(`${he(name, "hidden") ? "!" : ""}!(${value})`, true);
242
- deferredBindings.push(() => trackDependencies(fn, el).forEach(dep => addBinding(dep, {el, prop: "hidden", fn})));
251
+ deferredBindings.push({el, prop: "hidden", fn});
243
252
  }
244
253
  else if (he(name, "calculate")) {
245
254
  const calc = name.split(":")[1];
246
255
  const fn = compile(value, true);
247
- deferredBindings.push(() => trackDependencies(fn, el, true).forEach(key => addBinding(key, {el, calc, prop: null, fn})));
256
+ deferredBindings.push({el, calc, prop: null, fn});
248
257
  }
249
258
  else if (he(name, "effect")) {
250
259
  const keys = name.split(":").slice(1);
251
260
  const fn = compile(value, true);
252
- deferredBindings.push(() => {
253
- const tracked = keys.includes("*") ? [ALL] : trackDependencies(fn, el, true).concat(keys);
254
- tracked.forEach(key => addBinding(key, {el, prop: null, fn}));
255
- })
256
- }
257
- else if (he(name, "class")) {
258
- const fn = compile(value, true);
259
- deferredBindings.push(() => trackDependencies(fn, el).forEach(dep => addBinding(dep, {el, prop: "class", fn})));
261
+ deferredBindings.push({el, prop: null, fn, keys});
260
262
  }
261
263
  else if (he(name, "init")) {
262
264
  initFn = compile(value, true);
@@ -292,11 +294,11 @@ function processElements(element) {
292
294
  ...(getAttr("template") && { template: execFn(getAttr("template")),}),
293
295
  ...(getAttr("loading") && { loading: execFn(getAttr("loading"))}),
294
296
  };
295
- let paramsAttr = getAttr('params') || '{}';
296
- if (!paramsAttr.trim().startsWith("{") && paramsAttr.includes(":")) {
297
- const props = paramsAttr.split(":").map(s => s.trim());
298
- paramsAttr = props.reduceRight((acc, key, i) => `{ ${key}: ${i == 1 ? `'${el[acc]}'` : acc} }`);
299
- }
297
+ let paramsAttr = getAttr("params");
298
+ if (!paramsAttr && el.hasAttribute("name")) {
299
+ const keys = el.getAttribute("name").match(/\w+/g).map(key => `${key}:`).join``;
300
+ paramsAttr = keys + isCheckbox ? "checked" : "value";
301
+ } else paramsAttr ||= "{}";
300
302
  const params = exFn(paramsAttr);
301
303
  ajax(value, eventName.toUpperCase(), options, params);
302
304
  } else {
@@ -312,13 +314,13 @@ function processElements(element) {
312
314
  }
313
315
  }
314
316
  });
315
- deferredBindings.forEach(fn => fn());
317
+ deferredBindings.forEach(b => {
318
+ const tracked = b.keys?.includes("*") ? [ALL] : trackDependencies(b.fn, b.el, true).concat(b.keys);
319
+ tracked.forEach(key => addBinding(key, b));
320
+ })
316
321
  return newBindings;
317
322
  }
318
323
 
319
- // Disconnect old observer if it exists
320
- if (HELIUM.observer) HELIUM.observer.disconnect();
321
-
322
324
  // Create new observer
323
325
  HELIUM.observer = new MutationObserver(ms => {
324
326
  for (const m of ms) {
@@ -335,22 +337,11 @@ function processElements(element) {
335
337
 
336
338
  window.heliumTeardown = function() {
337
339
  if (HELIUM?.observer) HELIUM.observer.disconnect();
338
- HELIUM?.bindings?.clear();
339
- HELIUM?.refs?.clear();
340
- HELIUM?.parentKeys?.clear();
341
- HELIUM?.fnCache?.clear();
342
340
  HELIUM = null;
343
341
  }
344
342
 
345
343
  // Initialize on load
346
- document.addEventListener("DOMContentLoaded", () => helium());
347
-
344
+ document.addEventListener("DOMContentLoaded",_ => helium());
348
345
  // Turbo integration
349
- document.addEventListener("turbo:before-render", () => {
350
- if (HELIUM?.observer) HELIUM.observer.disconnect();
351
- window.heliumTeardown();
352
- });
353
-
354
- document.addEventListener("turbo:render", () => {
355
- helium();
356
- });
346
+ document.addEventListener("turbo:before-render",_ => window.heliumTeardown());
347
+ document.addEventListener("turbo:render",_ => helium());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daz4126/helium",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "main": "helium.js",
5
5
  "type": "module",
6
6
  "scripts": {