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