shablon 0.0.1-rc.6 → 0.0.1-rc.8

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
@@ -174,8 +174,6 @@ data.activity = "rest"
174
174
  Watch registers a callback function that fires on initialization and
175
175
  every time any of its evaluated `store` reactive properties change.
176
176
 
177
- Note that for reactive getters, initially the watch `trackedFunc` will be invoked twice because we register a second internal watcher to cache the getter value.
178
-
179
177
  It returns a "watcher" object that could be used to `unwatch()` the registered listener.
180
178
 
181
179
  _Optionally also accepts a second callback function that is excluded from the evaluated
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.1-rc.6",
2
+ "version": "0.0.1-rc.8",
3
3
  "name": "shablon",
4
4
  "description": "No-build JavaScript framework for Single-page applications",
5
5
  "author": "Gani Georgiev",
package/src/state.js CHANGED
@@ -12,7 +12,7 @@ let pathsSubsSym = Symbol();
12
12
  let unwatchedSym = Symbol();
13
13
  let onRemoveSym = Symbol();
14
14
  let skipSym = Symbol();
15
- let evictedSym = Symbol();
15
+ let detachedSym = Symbol();
16
16
 
17
17
  let pathSeparator = "/";
18
18
 
@@ -234,28 +234,26 @@ function createProxy(obj, pathWatcherIds) {
234
234
  // if not invoked inside a watch function, call the original
235
235
  // getter to ensure that an up-to-date value is computed
236
236
  if (!activeWatcher) {
237
- return descriptors[prop]?.get?.call(obj);
237
+ return descriptors[prop].get.call(obj);
238
238
  }
239
239
 
240
240
  getterProp = prop;
241
241
 
242
242
  // replace with an internal property so that reactive statements can be cached
243
243
  prop = "@@" + prop;
244
- Object.defineProperty(obj, prop, { writable: true, enumerable: false });
245
244
  }
246
245
 
247
- // evicted child?
246
+ // detached child?
247
+ let isDetached;
248
248
  if (!obj[skipSym] && obj[parentSym]) {
249
249
  let props = [];
250
250
  let activeObj = obj;
251
251
 
252
- let isEvicted = false;
253
-
254
252
  // travel up to the root proxy
255
253
  // (aka. x.a.b*.c -> x)
256
254
  while (activeObj?.[parentSym]) {
257
- if (activeObj[evictedSym]) {
258
- isEvicted = true;
255
+ if (activeObj[detachedSym]) {
256
+ isDetached = true;
259
257
  }
260
258
 
261
259
  props.push(activeObj[parentSym][1]);
@@ -268,9 +266,9 @@ function createProxy(obj, pathWatcherIds) {
268
266
  // (we want: x.a.b(old).c -> x -> x.a.b(new).c)
269
267
  //
270
268
  // note: this technically could "leak" but for our case it should be fine
271
- // because the evicted object will become again garbage collectable
269
+ // because the detached object will become again garbage collectable
272
270
  // once the related watcher(s) are removed
273
- if (isEvicted) {
271
+ if (isDetached) {
274
272
  for (let i = props.length - 1; i >= 0; i--) {
275
273
  activeObj[skipSym] = true;
276
274
  let item = activeObj?.[props[i]];
@@ -321,16 +319,21 @@ function createProxy(obj, pathWatcherIds) {
321
319
 
322
320
  let propPaths = [currentPath];
323
321
 
324
- // always construct all parent paths ("x.a.b.c" => ["a", "a.b", "a.b.c"])
325
- // because a store child object can be passed as argument to a function
326
- // and in that case the parents proxy get trap will not be invoked,
327
- // and their path will not be registered
328
- if (obj[parentSym]) {
329
- let parts = currentPath.split(pathSeparator);
330
- while (parts.pop() && parts.length) {
331
- propPaths.push(parts.join(pathSeparator));
332
- }
333
- }
322
+ // ---
323
+ // NB! Disable for now because of the nonblocking and delayed
324
+ // nature of the current MutationObserver implementation for the `onunmount` hook
325
+ // leading to unexpected and delayed watch calls in methods like `Array.map`.
326
+ // ---
327
+ // if (isDetached) {
328
+ // // always construct all parent paths ("x.a.b.c" => ["a", "a.b", "a.b.c"])
329
+ // // because a store child object can be passed as argument to a function
330
+ // // and in that case the parents proxy get trap will not be invoked,
331
+ // // and their path will not be registered
332
+ // let parts = currentPath.split(pathSeparator);
333
+ // while (parts.pop() && parts.length) {
334
+ // propPaths.push(parts.join(pathSeparator));
335
+ // }
336
+ // }
334
337
 
335
338
  // initialize a watcher paths tracking set (if not already)
336
339
  activeWatcher[pathsSubsSym] = activeWatcher[pathsSubsSym] || new Set();
@@ -360,14 +363,24 @@ function createProxy(obj, pathWatcherIds) {
360
363
 
361
364
  let getFunc = descriptors[getterProp].get.bind(obj);
362
365
 
363
- let getWatcher = watch(getFunc, (result) => (receiver[prop] = result));
366
+ let getWatcher = watch(getFunc, (result) => {
367
+ if (!obj.hasOwnProperty(prop)) {
368
+ Object.defineProperty(obj, prop, {
369
+ writable: true,
370
+ enumerable: false,
371
+ value: result,
372
+ });
373
+ } else {
374
+ receiver[prop] = result;
375
+ }
376
+ });
364
377
 
365
378
  getWatcher[onRemoveSym] = () => {
366
379
  descriptors[getterProp]?.watchers?.delete(watcherId);
367
380
  };
368
381
 
369
382
  // update with the cached get value after the above watch initialization
370
- propVal = obj[prop]
383
+ propVal = obj[prop];
371
384
  }
372
385
  }
373
386
 
@@ -381,9 +394,9 @@ function createProxy(obj, pathWatcherIds) {
381
394
 
382
395
  let oldValue = obj[prop];
383
396
 
384
- // mark as "evicted" in case a proxy child object/array is being replaced
397
+ // mark as "detached" in case a proxy child object/array is being replaced
385
398
  if (oldValue?.[parentSym]) {
386
- oldValue[evictedSym] = true;
399
+ oldValue[detachedSym] = true;
387
400
  }
388
401
 
389
402
  // update the stored parent reference in case of index change (e.g. unshift)
package/src/template.js CHANGED
@@ -117,10 +117,12 @@ function tag(tagName, attrs = {}, ...children) {
117
117
  return;
118
118
  }
119
119
 
120
+ const result = val(el, attr);
121
+
120
122
  if (useSetAttr) {
121
- el.setAttribute(attr, val(el));
123
+ el.setAttribute(attr, result);
122
124
  } else {
123
- el[attr] = val(el);
125
+ el[attr] = result;
124
126
  }
125
127
  });
126
128
  }