spikijs 1.0.6 → 1.0.7

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/spiki.js CHANGED
@@ -1,459 +1,568 @@
1
1
  (function () {
2
2
  "use strict";
3
3
 
4
- var spiki = (function () {
5
- var registry = Object.create(null);
6
- var metaMap = new WeakMap();
7
- var targetMap = new WeakMap();
8
- var proxyMap = new WeakMap();
9
- var pathCache = new Map();
10
- var queue = new Set();
11
- var loopRE = /^\s*(.*?)\s+in\s+(.+)\s*$/;
12
-
13
- var activeEffect, isFlushing, globalStore;
14
- var shouldTrigger = true;
15
- var p = Promise.resolve();
16
-
4
+ var spiki = (() => {
5
+ // --- State & Storage ---
6
+ var componentRegistry = Object.create(null);
7
+ var eventMetadataMap = new WeakMap();
8
+ var dependencyMap = new WeakMap();
9
+ var proxyCache = new WeakMap();
10
+ var pathSplitCache = new Map();
11
+ var schedulerQueue = new Set();
12
+
13
+ var loopRegex = /^\s*(.*?)\s+in\s+(.+)\s*$/;
14
+
15
+ // --- Global State Variables ---
16
+ var currentActiveEffect;
17
+ var isFlushingQueue;
18
+ var globalStore;
19
+ var shouldTriggerEffects = true;
20
+ var resolvedPromise = Promise.resolve();
21
+
22
+ // -------------------------------------------------------------------------
17
23
  // 1. Array Interceptors
24
+ // -------------------------------------------------------------------------
18
25
  var arrayInstrumentations = {};
19
- ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (m) {
20
- arrayInstrumentations[m] = function () {
26
+ ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(methodName => {
27
+ arrayInstrumentations[methodName] = function () {
21
28
  var args = [];
22
- for (var _i = 0; _i < arguments.length; _i++) {
23
- args[_i] = arguments[_i];
29
+ for (var i = 0; i < arguments.length; i++) {
30
+ args[i] = arguments[i];
24
31
  }
25
- shouldTrigger = false;
32
+
33
+ shouldTriggerEffects = false;
26
34
  try {
27
- var res = Array.prototype[m].apply(this, args);
28
- return res;
35
+ var result = Array.prototype[methodName].apply(this, args);
36
+ return result;
29
37
  } finally {
30
- shouldTrigger = true;
31
- trigger(this, 'length');
38
+ shouldTriggerEffects = true;
39
+ triggerDependency(this, 'length');
32
40
  }
33
41
  };
34
42
  });
35
43
 
36
- // 2. Helpers
37
- var createScope = function (parent) {
38
- var proto = Object.create(parent);
44
+ // -------------------------------------------------------------------------
45
+ // 2. Helper Functions
46
+ // -------------------------------------------------------------------------
47
+
48
+ var createScope = (parentScope) => {
49
+ var proto = Object.create(parentScope);
39
50
  return new Proxy(proto, {
40
- set: function (target, key, value, receiver) {
41
- if (target.hasOwnProperty(key)) return Reflect.set(target, key, value, receiver);
51
+ set: (target, key, value, receiver) => {
52
+ if (target.hasOwnProperty(key)) {
53
+ return Reflect.set(target, key, value, receiver);
54
+ }
55
+
42
56
  var cursor = target;
43
57
  while (cursor && !Object.prototype.hasOwnProperty.call(cursor, key)) {
44
58
  cursor = Object.getPrototypeOf(cursor);
45
59
  }
60
+
46
61
  return Reflect.set(cursor || target, key, value);
47
62
  }
48
63
  });
49
64
  };
50
65
 
51
- var evaluate = function (scope, path) {
52
- if (typeof path !== 'string') return { val: path, ctx: scope };
66
+ var evaluatePath = (scope, path) => {
67
+ if (typeof path !== 'string') return { value: path, context: scope };
53
68
 
54
69
  if (path.indexOf('.') === -1) {
55
- return { val: scope ? scope[path] : undefined, ctx: scope };
70
+ return { value: scope ? scope[path] : undefined, context: scope };
56
71
  }
57
72
 
58
- var parts = pathCache.get(path);
73
+ var parts = pathSplitCache.get(path);
59
74
  if (!parts) {
60
- if (pathCache.size > 1000) pathCache.clear();
75
+ if (pathSplitCache.size > 1000) pathSplitCache.clear();
61
76
  parts = path.split('.');
62
- pathCache.set(path, parts);
77
+ pathSplitCache.set(path, parts);
63
78
  }
64
79
 
65
- var val = scope, ctx = scope;
80
+ var currentValue = scope;
81
+ var currentContext = scope;
82
+
66
83
  for (var i = 0; i < parts.length; i++) {
67
84
  var part = parts[i];
68
- if (val == null) {
69
- return { val: val, ctx: null };
85
+ if (currentValue == null) {
86
+ return { value: currentValue, context: null };
70
87
  }
71
- ctx = val;
72
- val = val[part];
88
+ currentContext = currentValue;
89
+ currentValue = currentValue[part];
73
90
  }
74
- return { val: val, ctx: ctx };
91
+ return { value: currentValue, context: currentContext };
75
92
  };
76
93
 
77
- var nextTick = function (fn) {
78
- return !queue.has(fn) && queue.add(fn) && !isFlushing && (isFlushing = true) &&
79
- p.then(function () {
80
- queue.forEach(function (j) { j(); });
81
- queue.clear();
82
- isFlushing = false;
83
- });
94
+ var nextTick = (fn) => {
95
+ return !schedulerQueue.has(fn) &&
96
+ schedulerQueue.add(fn) &&
97
+ !isFlushingQueue &&
98
+ (isFlushingQueue = true) &&
99
+ resolvedPromise.then(() => {
100
+ schedulerQueue.forEach(job => job());
101
+ schedulerQueue.clear();
102
+ isFlushingQueue = false;
103
+ });
84
104
  };
85
105
 
86
- // 3. Reactivity
87
- var track = function (t, k) {
88
- if (!activeEffect) return;
89
- var deps = targetMap.get(t);
90
- if (!deps) {
91
- deps = new Map();
92
- targetMap.set(t, deps);
106
+ // -------------------------------------------------------------------------
107
+ // 3. Reactivity System
108
+ // -------------------------------------------------------------------------
109
+
110
+ var trackDependency = (target, key) => {
111
+ if (!currentActiveEffect) return;
112
+
113
+ var depsMap = dependencyMap.get(target);
114
+ if (!depsMap) {
115
+ depsMap = new Map();
116
+ dependencyMap.set(target, depsMap);
93
117
  }
94
- var dep = deps.get(k);
95
- if (!dep) {
96
- dep = new Set();
97
- deps.set(k, dep);
118
+
119
+ var depSet = depsMap.get(key);
120
+ if (!depSet) {
121
+ depSet = new Set();
122
+ depsMap.set(key, depSet);
98
123
  }
99
- dep.add(activeEffect);
100
- activeEffect.d.add(dep);
124
+
125
+ depSet.add(currentActiveEffect);
126
+ currentActiveEffect.dependencies.add(depSet);
101
127
  };
102
128
 
103
- var trigger = function (t, k) {
104
- var depsMap, dep;
105
- if (shouldTrigger && (depsMap = targetMap.get(t)) && (dep = depsMap.get(k))) {
106
- dep.forEach(function (e) {
107
- e.x ? e.x(e) : e();
129
+ var triggerDependency = (target, key) => {
130
+ var depsMap, depSet;
131
+ if (shouldTriggerEffects && (depsMap = dependencyMap.get(target)) && (depSet = depsMap.get(key))) {
132
+ depSet.forEach(effectFn => {
133
+ effectFn.scheduler ? effectFn.scheduler(effectFn) : effectFn();
108
134
  });
109
135
  }
110
136
  };
111
137
 
112
- var effect = function (fn, scheduler) {
113
- var runner = function () {
114
- runner.d.forEach(function (d) { d.delete(runner); });
115
- runner.d.clear();
116
- var prev = activeEffect;
117
- activeEffect = runner;
118
- try { fn(); } finally { activeEffect = prev; }
138
+ var createEffect = (fn, scheduler) => {
139
+ var runner = () => {
140
+ runner.dependencies.forEach(depSet => depSet.delete(runner));
141
+ runner.dependencies.clear();
142
+
143
+ var previousEffect = currentActiveEffect;
144
+ currentActiveEffect = runner;
145
+ try {
146
+ fn();
147
+ } finally {
148
+ currentActiveEffect = previousEffect;
149
+ }
119
150
  };
120
- runner.d = new Set();
121
- runner.x = scheduler;
151
+
152
+ runner.dependencies = new Set();
153
+ runner.scheduler = scheduler;
122
154
  runner();
123
- return function () {
124
- runner.d.forEach(function (d) { d.delete(runner); });
125
- runner.d.clear();
126
- queue.delete(runner);
155
+
156
+ return () => {
157
+ runner.dependencies.forEach(depSet => depSet.delete(runner));
158
+ runner.dependencies.clear();
159
+ schedulerQueue.delete(runner);
127
160
  };
128
161
  };
129
162
 
130
- var reactive = function (obj) {
131
- if (!obj || typeof obj !== 'object' || obj._p || obj instanceof Node) return obj;
132
- var existing = proxyMap.get(obj);
133
- if (existing) return existing;
163
+ var makeReactive = (obj) => {
164
+ if (!obj || typeof obj !== 'object' || obj.__isProxy || obj instanceof Node) return obj;
165
+
166
+ var existingProxy = proxyCache.get(obj);
167
+ if (existingProxy) return existingProxy;
134
168
 
135
169
  var proxy = new Proxy(obj, {
136
- get: function (t, k, r) {
137
- if (k === '_p') return true;
138
- if (Array.isArray(t) && arrayInstrumentations.hasOwnProperty(k)) return arrayInstrumentations[k];
139
- track(t, k);
140
- var res = Reflect.get(t, k, r);
141
- return res && typeof res === 'object' && !(res instanceof Node) ? reactive(res) : res;
170
+ get: (target, key, receiver) => {
171
+ if (key === '__raw') return target;
172
+ if (key === '__isProxy') return true;
173
+
174
+ if (Array.isArray(target) && arrayInstrumentations.hasOwnProperty(key)) {
175
+ return arrayInstrumentations[key];
176
+ }
177
+
178
+ trackDependency(target, key);
179
+
180
+ var result = Reflect.get(target, key, receiver);
181
+ return result && typeof result === 'object' && !(result instanceof Node)
182
+ ? makeReactive(result)
183
+ : result;
142
184
  },
143
- set: function (t, k, v, r) {
144
- var old = t[k];
145
- var hadKey = Array.isArray(t) ? Number(k) < t.length : Object.prototype.hasOwnProperty.call(t, k);
146
- var res = Reflect.set(t, k, v, r);
147
- if (shouldTrigger) {
185
+ set: (target, key, value, receiver) => {
186
+ var oldValue = target[key];
187
+ var hadKey = Array.isArray(target)
188
+ ? Number(key) < target.length
189
+ : Object.prototype.hasOwnProperty.call(target, key);
190
+
191
+ var result = Reflect.set(target, key, value, receiver);
192
+
193
+ if (shouldTriggerEffects) {
148
194
  if (!hadKey) {
149
- trigger(t, k);
150
- if (Array.isArray(t)) trigger(t, 'length');
151
- } else if (old !== v) {
152
- trigger(t, k);
195
+ triggerDependency(target, key);
196
+ if (Array.isArray(target)) triggerDependency(target, 'length');
197
+ } else if (oldValue !== value) {
198
+ triggerDependency(target, key);
153
199
  }
154
200
  }
155
- return res;
201
+ return result;
156
202
  },
157
- deleteProperty: function (t, k) {
158
- var hadKey = Object.prototype.hasOwnProperty.call(t, k);
159
- var res = Reflect.deleteProperty(t, k);
160
- if (res && hadKey) {
161
- trigger(t, k);
162
- if (Array.isArray(t)) trigger(t, 'length');
203
+ deleteProperty: (target, key) => {
204
+ var hadKey = Object.prototype.hasOwnProperty.call(target, key);
205
+ var result = Reflect.deleteProperty(target, key);
206
+ if (result && hadKey) {
207
+ triggerDependency(target, key);
208
+ if (Array.isArray(target)) triggerDependency(target, 'length');
163
209
  }
164
- return res;
210
+ return result;
165
211
  }
166
212
  });
167
- proxyMap.set(obj, proxy);
213
+
214
+ proxyCache.set(obj, proxy);
168
215
  return proxy;
169
216
  };
170
217
 
171
- globalStore = reactive({});
218
+ globalStore = makeReactive({});
172
219
 
173
- // 4. DOM Ops
174
- var ops = {
175
- text: function (el, v) { el.textContent = (v !== null && v !== undefined) ? v : ''; },
176
- html: function (el, v) { el.innerHTML = (v !== null && v !== undefined) ? v : ''; },
177
- value: function (el, v) {
220
+ // -------------------------------------------------------------------------
221
+ // 4. DOM Operations
222
+ // -------------------------------------------------------------------------
223
+ var domOperations = {
224
+ text: (el, value) => {
225
+ el.textContent = (value !== null && value !== undefined) ? value : '';
226
+ },
227
+ html: (el, value) => {
228
+ el.innerHTML = (value !== null && value !== undefined) ? value : '';
229
+ },
230
+ value: (el, value) => {
178
231
  if (el.type === 'checkbox') {
179
- el.checked = !!v;
232
+ el.checked = !!value;
180
233
  } else if (el.type === 'radio' && el.name) {
181
- el.checked = el.value == v;
234
+ el.checked = el.value == value;
182
235
  } else {
183
- if (el.value != v) el.value = (v !== null && v !== undefined) ? v : '';
236
+ if (el.value != value) {
237
+ el.value = (value !== null && value !== undefined) ? value : '';
238
+ }
184
239
  }
185
240
  },
186
- attr: function (el, v, arg) {
187
- (v == null || v === false) ? el.removeAttribute(arg) : el.setAttribute(arg, v === true ? '' : v);
241
+ attr: (el, value, attributeName) => {
242
+ (value == null || value === false)
243
+ ? el.removeAttribute(attributeName)
244
+ : el.setAttribute(attributeName, value === true ? '' : value);
188
245
  },
189
- class: function (el, v) {
190
- if (typeof v === 'string') {
191
- v.split(/\s+/).forEach(function (c) {
192
- if (c) el.classList[c[0] === '!' ? 'remove' : 'add'](c[0] === '!' ? c.slice(1) : c);
246
+ class: (el, value) => {
247
+ if (typeof value === 'string') {
248
+ value.split(/\s+/).forEach(cls => {
249
+ if (cls) {
250
+ var isNegative = cls[0] === '!';
251
+ var className = isNegative ? cls.slice(1) : cls;
252
+ el.classList[isNegative ? 'remove' : 'add'](className);
253
+ }
193
254
  });
194
255
  }
195
256
  },
196
- init: function () { },
197
- destroy: function () { }
257
+ init: () => { },
258
+ destroy: () => { }
198
259
  };
199
260
 
200
- // 5. Engine
201
- var mount = function (root) {
202
- if (root._m) return;
203
- root._m = 1;
204
- var fac = registry[root.getAttribute('s-data')];
205
- if (!fac) return;
261
+ // -------------------------------------------------------------------------
262
+ // 5. Engine / Mounting Logic
263
+ // -------------------------------------------------------------------------
264
+ var mountComponent = (rootElement) => {
265
+ if (rootElement.__isMounted) return;
266
+ rootElement.__isMounted = 1;
267
+
268
+ var componentName = rootElement.getAttribute('s-data');
269
+ var componentFactory = componentRegistry[componentName];
270
+ if (!componentFactory) return;
206
271
 
207
- var state = reactive(fac());
272
+ var state = makeReactive(componentFactory());
208
273
  state.$refs = {};
209
- state.$root = root;
274
+ state.$root = rootElement;
210
275
  state.$store = globalStore;
211
276
 
212
- var rootK = [];
277
+ var cleanupCallbacks = [];
213
278
 
214
- var handleEvent = function (e) {
215
- var t = e.target;
216
- if (t._m && (e.type === 'input' || e.type === 'change')) {
217
- var path = t._m;
218
- var v = t.type === 'checkbox' ? t.checked : t.value;
219
- var evaluated = evaluate(t._s || state, path);
220
- var parentObj = evaluated.ctx;
279
+ var handleEvent = (e) => {
280
+ var target = e.target;
281
+
282
+ if (target.__modelPath && (e.type === 'input' || e.type === 'change')) {
283
+ var path = target.__modelPath;
284
+ var value = target.type === 'checkbox' ? target.checked : target.value;
285
+ var evaluation = evaluatePath(target.__scope || state, path);
286
+ var parentObject = evaluation.context;
221
287
 
222
288
  if (path.indexOf('.') === -1) {
223
- (t._s || state)[path] = v;
224
- } else if (parentObj) {
289
+ (target.__scope || state)[path] = value;
290
+ } else if (parentObject) {
225
291
  var parts = path.split('.');
226
- parentObj[parts[parts.length - 1]] = v;
292
+ parentObject[parts[parts.length - 1]] = value;
227
293
  }
228
294
  }
229
295
 
230
- var hn;
231
- while (t && t !== root.parentNode) {
232
- var meta = metaMap.get(t);
233
- if (meta && (hn = meta[e.type])) {
234
- var evRes = evaluate(t._s || state, hn);
235
- var fn = evRes.val;
236
- var ctx = evRes.ctx;
237
- if (typeof fn === 'function') fn.call(ctx, e);
296
+ var handlerName;
297
+ while (target && target !== rootElement.parentNode) {
298
+ var meta = eventMetadataMap.get(target);
299
+ if (meta && (handlerName = meta[e.type])) {
300
+ var evalResult = evaluatePath(target.__scope || state, handlerName);
301
+ var handlerFn = evalResult.value;
302
+ var handlerContext = evalResult.context;
303
+
304
+ if (typeof handlerFn === 'function') {
305
+ handlerFn.call(handlerContext, e);
306
+ }
238
307
  }
239
- t = t.parentNode;
308
+ target = target.parentNode;
240
309
  }
241
310
  };
242
311
 
243
- var walk = function (el, scope, kList) {
312
+ var walkDOM = (el, currentScope, cleanupList) => {
244
313
  if (el.nodeType !== 1 || el.hasAttribute('s-ignore')) return;
245
314
 
246
- if (el !== root && el.hasAttribute('s-data')) {
247
- var child = mount(el);
248
- if (child) kList.push(child.unmount);
315
+ if (el !== rootElement && el.hasAttribute('s-data')) {
316
+ var childComponent = mountComponent(el);
317
+ if (childComponent) cleanupList.push(childComponent.unmount);
249
318
  return;
250
319
  }
251
320
 
252
- var val;
253
- if ((val = el.getAttribute('s-if'))) {
321
+ var attributeValue;
322
+
323
+ if ((attributeValue = el.getAttribute('s-if'))) {
254
324
  var anchor = document.createTextNode('');
255
- var branchK = [];
325
+ var branchCleanups = [];
256
326
  el.replaceWith(anchor);
257
- var node;
258
-
259
- kList.push(function () { branchK.forEach(function (s) { s(); }); });
260
-
261
- return kList.push(effect(function () {
262
- var ev = evaluate(scope, val);
263
- var res = ev.val;
264
- var ctx = ev.ctx;
265
- var truthy = typeof res === 'function' ? res.call(ctx, el) : res;
266
-
267
- if (truthy) {
268
- if (!node) {
269
- node = el.cloneNode(true);
270
- node.removeAttribute('s-if');
271
- walk(node, scope, branchK);
272
- anchor.parentNode.insertBefore(node, anchor);
327
+ var activeNode;
328
+
329
+ cleanupList.push(() => {
330
+ branchCleanups.forEach(cb => cb());
331
+ });
332
+
333
+ return cleanupList.push(createEffect(() => {
334
+ var evaluation = evaluatePath(currentScope, attributeValue);
335
+ var result = evaluation.value;
336
+ var context = evaluation.context;
337
+
338
+ var isTruthy = typeof result === 'function' ? result.call(context, el) : result;
339
+
340
+ if (isTruthy) {
341
+ if (!activeNode) {
342
+ activeNode = el.cloneNode(true);
343
+ activeNode.removeAttribute('s-if');
344
+ walkDOM(activeNode, currentScope, branchCleanups);
345
+ anchor.parentNode.insertBefore(activeNode, anchor);
273
346
  }
274
- } else if (node) {
275
- branchK.forEach(function (s) { s(); });
276
- branchK.length = 0;
277
- node.remove();
278
- node = null;
347
+ } else if (activeNode) {
348
+ branchCleanups.forEach(cb => cb());
349
+ branchCleanups.length = 0;
350
+ activeNode.remove();
351
+ activeNode = null;
279
352
  }
280
353
  }, nextTick));
281
354
  }
282
355
 
283
- if (el.tagName === 'TEMPLATE' && (val = el.getAttribute('s-for'))) {
284
- var match = val.match(loopRE);
356
+ if (el.tagName === 'TEMPLATE' && (attributeValue = el.getAttribute('s-for'))) {
357
+ var match = attributeValue.match(loopRegex);
285
358
  if (!match) return;
286
- var lhs = match[1].replace(/[()]/g, '');
359
+
360
+ var leftHandSide = match[1].replace(/[()]/g, '');
287
361
  var listKey = match[2];
288
- var splitLhs = lhs.split(',');
289
- var alias = splitLhs[0].trim();
290
- var idx = splitLhs[1] ? splitLhs[1].trim() : null;
291
-
292
- var keyAttr = el.getAttribute('s-key');
293
- var anchor_1 = document.createTextNode('');
294
- el.replaceWith(anchor_1);
295
- var pool = new Map();
296
-
297
- kList.push(function () {
298
- pool.forEach(function (r) {
299
- r.k.forEach(function (s) { s(); });
362
+ var splitLhs = leftHandSide.split(',');
363
+ var itemAlias = splitLhs[0].trim();
364
+ var indexAlias = splitLhs[1] ? splitLhs[1].trim() : null;
365
+
366
+ var keyAttribute = el.getAttribute('s-key');
367
+ var anchorForLoop = document.createTextNode('');
368
+ el.replaceWith(anchorForLoop);
369
+
370
+ var nodePool = new Map();
371
+
372
+ cleanupList.push(() => {
373
+ nodePool.forEach(row => {
374
+ row.cleanups.forEach(cb => cb());
300
375
  });
301
376
  });
302
377
 
303
- return kList.push(effect(function () {
304
- var ev = evaluate(scope, listKey);
305
- var rawItems = ev.val;
378
+ return cleanupList.push(createEffect(() => {
379
+ var evaluation = evaluatePath(currentScope, listKey);
380
+ var rawItems = evaluation.value;
306
381
  var items = rawItems;
307
- if (Array.isArray(items)) track(items, 'length');
382
+
383
+ if (Array.isArray(items)) trackDependency(items, 'length');
308
384
 
309
- var cursor = anchor_1;
385
+ var domCursor = anchorForLoop;
310
386
  var iterable = Array.isArray(items) ? items : items ? Object.keys(items) : [];
311
- var nextPool = new Map();
387
+ var nextNodePool = new Map();
312
388
 
313
- iterable.forEach(function (raw, i) {
314
- var key = Array.isArray(items) ? i : raw;
315
- var item = Array.isArray(items) ? raw : items[raw];
389
+ iterable.forEach((rawItem, index) => {
390
+ var key = Array.isArray(items) ? index : rawItem;
391
+ var itemValue = Array.isArray(items) ? rawItem : items[rawItem];
316
392
 
317
- var rowKey;
318
- if (keyAttr && item) rowKey = item[keyAttr];
319
- else rowKey = (typeof item === 'object' && item) ? item : key + '_' + item;
393
+ var rowUniqueKey;
394
+ if (keyAttribute && itemValue) rowUniqueKey = itemValue[keyAttribute];
395
+ else rowUniqueKey = (typeof itemValue === 'object' && itemValue)
396
+ ? itemValue
397
+ : key + '_' + itemValue;
320
398
 
321
- var row = pool.get(rowKey);
399
+ var row = nodePool.get(rowUniqueKey);
322
400
 
323
- var defineAlias = function (targetObj) {
324
- Object.defineProperty(targetObj, alias, {
401
+ var defineAlias = (targetObj) => {
402
+ Object.defineProperty(targetObj, itemAlias, {
325
403
  configurable: true, enumerable: true,
326
- get: function () { return items[key]; },
327
- set: function (v) { items[key] = v; }
404
+ get: () => items[key],
405
+ set: (v) => { items[key] = v; }
328
406
  });
329
407
  };
330
408
 
331
409
  if (!row) {
332
410
  var clone = el.content.cloneNode(true);
333
- var s = createScope(scope);
334
- var rowK = [];
335
-
336
- defineAlias(s);
337
- if (idx) s[idx] = key;
338
-
339
- var nodes = [];
340
- var c = clone.firstChild;
341
- while (c) {
342
- nodes.push(c);
343
- var next = c.nextSibling;
344
- walk(c, s, rowK);
345
- c = next;
411
+ var rowScope = createScope(currentScope);
412
+ var rowCleanups = [];
413
+
414
+ defineAlias(rowScope);
415
+ if (indexAlias) rowScope[indexAlias] = key;
416
+
417
+ var rowNodes = [];
418
+ var childNode = clone.firstChild;
419
+ while (childNode) {
420
+ rowNodes.push(childNode);
421
+ var nextSibling = childNode.nextSibling;
422
+ walkDOM(childNode, rowScope, rowCleanups);
423
+ childNode = nextSibling;
346
424
  }
347
- row = { n: nodes, s: s, k: rowK };
425
+ row = { nodes: rowNodes, scope: rowScope, cleanups: rowCleanups };
348
426
  } else {
349
- defineAlias(row.s);
350
- if (idx) row.s[idx] = key;
427
+ defineAlias(row.scope);
428
+ if (indexAlias) row.scope[indexAlias] = key;
351
429
  }
352
430
 
353
- if (row.n[0] !== cursor.nextSibling) {
354
- var frag = document.createDocumentFragment();
355
- row.n.forEach(function (n) { frag.appendChild(n); });
356
- cursor.parentNode.insertBefore(frag, cursor.nextSibling);
431
+ if (row.nodes[0] !== domCursor.nextSibling) {
432
+ var fragment = document.createDocumentFragment();
433
+ row.nodes.forEach(n => fragment.appendChild(n));
434
+ domCursor.parentNode.insertBefore(fragment, domCursor.nextSibling);
357
435
  }
358
- cursor = row.n[row.n.length - 1];
359
- nextPool.set(rowKey, row);
360
- pool.delete(rowKey);
436
+
437
+ domCursor = row.nodes[row.nodes.length - 1];
438
+ nextNodePool.set(rowUniqueKey, row);
439
+ nodePool.delete(rowUniqueKey);
361
440
  });
362
- pool.forEach(function (row) {
363
- row.k.forEach(function (s) { s(); });
364
- row.n.forEach(function (n) { n.remove(); });
441
+
442
+ nodePool.forEach(row => {
443
+ row.cleanups.forEach(cb => cb());
444
+ row.nodes.forEach(n => n.remove());
365
445
  });
366
- pool = nextPool;
446
+ nodePool = nextNodePool;
367
447
  }, nextTick));
368
448
  }
369
449
 
370
- var attrs = el.attributes;
371
- for (var i = attrs.length - 1; i >= 0; i--) {
372
- (function (attr) {
450
+ var attributes = el.attributes;
451
+ for (var i = attributes.length - 1; i >= 0; i--) {
452
+ ((attr) => {
373
453
  var name = attr.name;
374
454
  var value = attr.value;
375
455
 
376
456
  if (name[0] === ':') {
377
- kList.push(effect(function () {
378
- var ev = evaluate(scope, value);
379
- var res = ev.val;
380
- var ctx = ev.ctx;
381
- ops[name.slice(1) === 'class' ? 'class' : 'attr'](el, typeof res === 'function' ? res.call(ctx, el) : res, name.slice(1));
457
+ cleanupList.push(createEffect(() => {
458
+ var evaluation = evaluatePath(currentScope, value);
459
+ var result = evaluation.value;
460
+ var context = evaluation.context;
461
+ var opName = name.slice(1) === 'class' ? 'class' : 'attr';
462
+
463
+ domOperations[opName](
464
+ el,
465
+ typeof result === 'function' ? result.call(context, el) : result,
466
+ name.slice(1)
467
+ );
382
468
  }, nextTick));
383
469
 
384
470
  } else if (name[0] === 's' && name[1] === '-') {
385
- var type = name.slice(2);
386
- if (type === 'ref') {
471
+ var directiveType = name.slice(2);
472
+
473
+ if (directiveType === 'ref') {
387
474
  state.$refs[value] = el;
388
- } else if (type === 'model') {
389
- kList.push(effect(function () {
390
- var ev = evaluate(scope, value);
391
- ops.value(el, ev.val);
475
+ } else if (directiveType === 'model') {
476
+ cleanupList.push(createEffect(() => {
477
+ var evaluation = evaluatePath(currentScope, value);
478
+ domOperations.value(el, evaluation.value);
392
479
  }, nextTick));
480
+
393
481
  if (/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)) {
394
- el._s = scope; el._m = value;
395
- var evt = (el.type === 'checkbox' || el.type === 'radio' || el.tagName === 'SELECT') ? 'change' : 'input';
396
- if (!root._e) root._e = new Set();
397
- if (!root._e.has(evt)) {
398
- root._e.add(evt);
399
- root.addEventListener(evt, handleEvent);
482
+ el.__scope = currentScope;
483
+ el.__modelPath = value;
484
+ var eventType = (el.type === 'checkbox' || el.type === 'radio' || el.tagName === 'SELECT')
485
+ ? 'change'
486
+ : 'input';
487
+
488
+ if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
489
+ if (!rootElement.__listeningEvents.has(eventType)) {
490
+ rootElement.__listeningEvents.add(eventType);
491
+ rootElement.addEventListener(eventType, handleEvent);
400
492
  }
401
493
  }
402
- } else if (ops[type]) {
403
- kList.push(effect(function () {
404
- var ev = evaluate(scope, value);
405
- var res = ev.val;
406
- var ctx = ev.ctx;
407
- ops[type](el, typeof res === 'function' ? res.call(ctx, el) : res);
494
+ } else if (domOperations[directiveType]) {
495
+ cleanupList.push(createEffect(() => {
496
+ var evaluation = evaluatePath(currentScope, value);
497
+ var result = evaluation.value;
498
+ var context = evaluation.context;
499
+ domOperations[directiveType](
500
+ el,
501
+ typeof result === 'function' ? result.call(context, el) : result
502
+ );
408
503
  }, nextTick));
409
504
  } else {
410
- el._s = scope;
411
- var meta = metaMap.get(el);
505
+ el.__scope = currentScope;
506
+ var meta = eventMetadataMap.get(el);
412
507
  if (!meta) {
413
508
  meta = {};
414
- metaMap.set(el, meta);
509
+ eventMetadataMap.set(el, meta);
415
510
  }
416
- meta[type] = value;
417
- if (!root._e) root._e = new Set();
418
- if (!root._e.has(type)) {
419
- root._e.add(type);
420
- root.addEventListener(type, handleEvent);
511
+ meta[directiveType] = value;
512
+
513
+ if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
514
+ if (!rootElement.__listeningEvents.has(directiveType)) {
515
+ rootElement.__listeningEvents.add(directiveType);
516
+ rootElement.addEventListener(directiveType, handleEvent);
421
517
  }
422
518
  }
423
519
  }
424
- })(attrs[i]);
520
+ })(attributes[i]);
425
521
  }
426
522
 
427
523
  var child = el.firstElementChild;
428
524
  while (child) {
429
525
  var next = child.nextElementSibling;
430
- walk(child, scope, kList);
526
+ walkDOM(child, currentScope, cleanupList);
431
527
  child = next;
432
528
  }
433
529
  };
434
530
 
435
- walk(root, state, rootK);
531
+ walkDOM(rootElement, state, cleanupCallbacks);
436
532
  if (state.init) state.init();
437
533
 
438
534
  return {
439
- unmount: function () {
535
+ unmount: () => {
440
536
  if (state.destroy) state.destroy.call(state);
441
- rootK.forEach(function (s) { s(); });
442
- if (root._e) root._e.forEach(function (k) { root.removeEventListener(k, handleEvent); });
443
- root._m = 0;
537
+ cleanupCallbacks.forEach(cb => cb());
538
+ if (rootElement.__listeningEvents) {
539
+ rootElement.__listeningEvents.forEach(evt => {
540
+ rootElement.removeEventListener(evt, handleEvent);
541
+ });
542
+ }
543
+ rootElement.__isMounted = 0;
444
544
  }
445
545
  };
446
546
  };
447
547
 
448
548
  return {
449
- data: function (n, f) { registry[n] = f; },
450
- start: function () {
451
- var els = document.querySelectorAll('[s-data]');
452
- for (var i = 0; i < els.length; i++) {
453
- mount(els[i]);
549
+ data: (name, factoryFn) => {
550
+ componentRegistry[name] = factoryFn;
551
+ },
552
+ start: () => {
553
+ var elements = document.querySelectorAll('[s-data]');
554
+ for (var i = 0; i < elements.length; i++) {
555
+ mountComponent(elements[i]);
454
556
  }
455
557
  },
456
- store: function (k, v) { return v === undefined ? globalStore[k] : (globalStore[k] = v); }
558
+ store: (key, value) => {
559
+ return value === undefined
560
+ ? globalStore[key]
561
+ : (globalStore[key] = value);
562
+ },
563
+ raw: (obj) => {
564
+ return (obj && obj.__raw) || obj;
565
+ }
457
566
  };
458
567
  })();
459
568