@erickxavier/no-js 1.0.2 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erickxavier/no-js",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "The HTML-first reactive framework — build dynamic web apps with just HTML attributes, no JavaScript required",
5
5
  "main": "dist/cjs/no.js",
6
6
  "module": "dist/esm/no.js",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "build": "node build.js",
25
- "start": "npx serve .",
25
+ "start": "node docs/dev-server.js",
26
26
  "test": "jest",
27
27
  "test:watch": "jest --watch",
28
28
  "test:coverage": "jest --coverage",
package/src/animations.js CHANGED
@@ -77,15 +77,15 @@ export function _animateOut(el, animName, transitionName, callback, durationMs)
77
77
  const target = el.firstElementChild || el;
78
78
  target.classList.add(animName);
79
79
  if (durationMs) target.style.animationDuration = durationMs + "ms";
80
- target.addEventListener(
81
- "animationend",
82
- () => {
83
- target.classList.remove(animName);
84
- callback();
85
- },
86
- { once: true },
87
- );
88
- setTimeout(callback, fallback); // Fallback
80
+ let called = false;
81
+ const done = () => {
82
+ if (called) return;
83
+ called = true;
84
+ target.classList.remove(animName);
85
+ callback();
86
+ };
87
+ target.addEventListener("animationend", done, { once: true });
88
+ setTimeout(done, fallback); // Fallback
89
89
  return;
90
90
  }
91
91
  if (transitionName) {
@@ -97,7 +97,10 @@ export function _animateOut(el, animName, transitionName, callback, durationMs)
97
97
  requestAnimationFrame(() => {
98
98
  target.classList.remove(transitionName + "-leave");
99
99
  target.classList.add(transitionName + "-leave-to");
100
+ let called = false;
100
101
  const done = () => {
102
+ if (called) return;
103
+ called = true;
101
104
  target.classList.remove(
102
105
  transitionName + "-leave-active",
103
106
  transitionName + "-leave-to",
package/src/context.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // REACTIVE CONTEXT
3
3
  // ═══════════════════════════════════════════════════════════════════════
4
4
 
5
- import { _stores, _refs, _routerInstance } from "./globals.js";
5
+ import { _stores, _refs, _routerInstance, _currentEl } from "./globals.js";
6
6
  import { _i18n } from "./i18n.js";
7
7
 
8
8
  let _batchDepth = 0;
@@ -17,7 +17,10 @@ export function _endBatch() {
17
17
  if (_batchDepth === 0 && _batchQueue.size > 0) {
18
18
  const fns = [..._batchQueue];
19
19
  _batchQueue.clear();
20
- fns.forEach((fn) => fn());
20
+ fns.forEach((fn) => {
21
+ if (fn._el && !fn._el.isConnected) return;
22
+ fn();
23
+ });
21
24
  }
22
25
  }
23
26
 
@@ -32,9 +35,15 @@ export function createContext(data = {}, parent = null) {
32
35
  notifying = true;
33
36
  try {
34
37
  if (_batchDepth > 0) {
35
- listeners.forEach((fn) => _batchQueue.add(fn));
38
+ for (const fn of listeners) {
39
+ if (fn._el && !fn._el.isConnected) { listeners.delete(fn); continue; }
40
+ _batchQueue.add(fn);
41
+ }
36
42
  } else {
37
- listeners.forEach((fn) => fn());
43
+ for (const fn of listeners) {
44
+ if (fn._el && !fn._el.isConnected) { listeners.delete(fn); continue; }
45
+ fn();
46
+ }
38
47
  }
39
48
  } finally {
40
49
  notifying = false;
@@ -48,13 +57,27 @@ export function createContext(data = {}, parent = null) {
48
57
  if (key === "__listeners") return listeners;
49
58
  if (key === "$watch")
50
59
  return (fn) => {
60
+ if (_currentEl) fn._el = _currentEl;
51
61
  listeners.add(fn);
52
62
  return () => listeners.delete(fn);
53
63
  };
54
64
  if (key === "$notify") return notify;
55
65
  if (key === "$set")
56
66
  return (k, v) => {
57
- proxy[k] = v;
67
+ const parts = k.split(".");
68
+ if (parts.length === 1) {
69
+ proxy[k] = v;
70
+ } else {
71
+ let obj = proxy;
72
+ for (let i = 0; i < parts.length - 1; i++) {
73
+ obj = obj[parts[i]];
74
+ if (obj == null) return;
75
+ }
76
+ const lastKey = parts[parts.length - 1];
77
+ const old = obj[lastKey];
78
+ obj[lastKey] = v;
79
+ if (old !== v) notify();
80
+ }
58
81
  };
59
82
  if (key === "$parent") return parent;
60
83
  if (key === "$refs") return _refs;
@@ -112,7 +112,7 @@ registerDirective("model", {
112
112
  _execStatement(`${expr} = __val`, ctx, { __val: val });
113
113
  });
114
114
 
115
- ctx.$watch(update);
115
+ _watchExpr(expr, ctx, update);
116
116
  update();
117
117
  },
118
118
  });
@@ -71,7 +71,7 @@ registerDirective("if", {
71
71
  }
72
72
  }
73
73
 
74
- ctx.$watch(update);
74
+ _watchExpr(expr, ctx, update);
75
75
  update();
76
76
  },
77
77
  });
@@ -120,7 +120,7 @@ registerDirective("else-if", {
120
120
  el.innerHTML = "";
121
121
  }
122
122
  }
123
- ctx.$watch(update);
123
+ _watchExpr(expr, ctx, update);
124
124
  update();
125
125
  },
126
126
  });
@@ -166,7 +166,7 @@ registerDirective("else", {
166
166
  _clearDeclared(el);
167
167
  processTree(el);
168
168
  }
169
- ctx.$watch(update);
169
+ _watchExpr("", ctx, update);
170
170
  update();
171
171
  },
172
172
  });
@@ -282,7 +282,7 @@ registerDirective("switch", {
282
282
  }
283
283
  }
284
284
 
285
- ctx.$watch(update);
285
+ _watchExpr(expr, ctx, update);
286
286
  update();
287
287
  },
288
288
  });