spikijs 1.0.7 → 1.0.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/package.json +1 -1
- package/spiki.esm.js +128 -88
- package/spiki.esm.min.js +1 -1
- package/spiki.js +128 -88
- package/spiki.min.js +1 -1
package/package.json
CHANGED
package/spiki.esm.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
var spiki = (() => {
|
|
2
|
-
//
|
|
2
|
+
// =========================================================================
|
|
3
|
+
// 1. STATE & STORAGE
|
|
4
|
+
// =========================================================================
|
|
3
5
|
var componentRegistry = Object.create(null);
|
|
4
6
|
var eventMetadataMap = new WeakMap();
|
|
5
|
-
var dependencyMap = new WeakMap();
|
|
6
|
-
var proxyCache = new WeakMap();
|
|
7
|
-
var pathSplitCache = new Map();
|
|
8
|
-
var schedulerQueue = new Set();
|
|
7
|
+
var dependencyMap = new WeakMap(); // Stores dependencies: Target -> Key -> Set<Effect>
|
|
8
|
+
var proxyCache = new WeakMap(); // Prevents double-wrapping objects
|
|
9
|
+
var pathSplitCache = new Map(); // Caches "user.name" -> ["user", "name"]
|
|
10
|
+
var schedulerQueue = new Set(); // Async task queue
|
|
9
11
|
|
|
10
|
-
var loopRegex = /^\s*(.*?)\s+in\s+(.+)\s*$/;
|
|
12
|
+
var loopRegex = /^\s*(.*?)\s+in\s+(.+)\s*$/; // Regex for "item in items"
|
|
11
13
|
|
|
12
|
-
//
|
|
14
|
+
// Global flags
|
|
13
15
|
var currentActiveEffect;
|
|
14
16
|
var isFlushingQueue;
|
|
15
17
|
var globalStore;
|
|
16
18
|
var shouldTriggerEffects = true;
|
|
17
19
|
var resolvedPromise = Promise.resolve();
|
|
18
20
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
21
|
+
// =========================================================================
|
|
22
|
+
// 2. ARRAY INSTRUMENTATION
|
|
23
|
+
// Intercepts array mutation methods to trigger reactivity
|
|
24
|
+
// =========================================================================
|
|
22
25
|
var arrayInstrumentations = {};
|
|
23
26
|
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(methodName => {
|
|
24
27
|
arrayInstrumentations[methodName] = function () {
|
|
@@ -38,10 +41,12 @@ var spiki = (() => {
|
|
|
38
41
|
};
|
|
39
42
|
});
|
|
40
43
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
+
// =========================================================================
|
|
45
|
+
// 3. HELPER FUNCTIONS
|
|
46
|
+
// =========================================================================
|
|
44
47
|
|
|
48
|
+
// Creates a child scope that inherits from parent.
|
|
49
|
+
// Writes bubble up to the object that actually owns the property.
|
|
45
50
|
var createScope = (parentScope) => {
|
|
46
51
|
var proto = Object.create(parentScope);
|
|
47
52
|
return new Proxy(proto, {
|
|
@@ -60,6 +65,7 @@ var spiki = (() => {
|
|
|
60
65
|
});
|
|
61
66
|
};
|
|
62
67
|
|
|
68
|
+
// Resolves "user.name" from the scope
|
|
63
69
|
var evaluatePath = (scope, path) => {
|
|
64
70
|
if (typeof path !== 'string') return { value: path, context: scope };
|
|
65
71
|
|
|
@@ -88,6 +94,7 @@ var spiki = (() => {
|
|
|
88
94
|
return { value: currentValue, context: currentContext };
|
|
89
95
|
};
|
|
90
96
|
|
|
97
|
+
// Microtask Scheduler
|
|
91
98
|
var nextTick = (fn) => {
|
|
92
99
|
return !schedulerQueue.has(fn) &&
|
|
93
100
|
schedulerQueue.add(fn) &&
|
|
@@ -100,9 +107,9 @@ var spiki = (() => {
|
|
|
100
107
|
});
|
|
101
108
|
};
|
|
102
109
|
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
110
|
+
// =========================================================================
|
|
111
|
+
// 4. REACTIVITY SYSTEM
|
|
112
|
+
// =========================================================================
|
|
106
113
|
|
|
107
114
|
var trackDependency = (target, key) => {
|
|
108
115
|
if (!currentActiveEffect) return;
|
|
@@ -134,6 +141,7 @@ var spiki = (() => {
|
|
|
134
141
|
|
|
135
142
|
var createEffect = (fn, scheduler) => {
|
|
136
143
|
var runner = () => {
|
|
144
|
+
// Clean up old dependencies before re-running
|
|
137
145
|
runner.dependencies.forEach(depSet => depSet.delete(runner));
|
|
138
146
|
runner.dependencies.clear();
|
|
139
147
|
|
|
@@ -148,7 +156,7 @@ var spiki = (() => {
|
|
|
148
156
|
|
|
149
157
|
runner.dependencies = new Set();
|
|
150
158
|
runner.scheduler = scheduler;
|
|
151
|
-
runner();
|
|
159
|
+
runner(); // Run immediately
|
|
152
160
|
|
|
153
161
|
return () => {
|
|
154
162
|
runner.dependencies.forEach(depSet => depSet.delete(runner));
|
|
@@ -175,6 +183,7 @@ var spiki = (() => {
|
|
|
175
183
|
trackDependency(target, key);
|
|
176
184
|
|
|
177
185
|
var result = Reflect.get(target, key, receiver);
|
|
186
|
+
// Deep reactivity
|
|
178
187
|
return result && typeof result === 'object' && !(result instanceof Node)
|
|
179
188
|
? makeReactive(result)
|
|
180
189
|
: result;
|
|
@@ -214,9 +223,9 @@ var spiki = (() => {
|
|
|
214
223
|
|
|
215
224
|
globalStore = makeReactive({});
|
|
216
225
|
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
226
|
+
// =========================================================================
|
|
227
|
+
// 5. DOM OPERATIONS
|
|
228
|
+
// =========================================================================
|
|
220
229
|
var domOperations = {
|
|
221
230
|
text: (el, value) => {
|
|
222
231
|
el.textContent = (value !== null && value !== undefined) ? value : '';
|
|
@@ -255,9 +264,9 @@ var spiki = (() => {
|
|
|
255
264
|
destroy: () => { }
|
|
256
265
|
};
|
|
257
266
|
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
267
|
+
// =========================================================================
|
|
268
|
+
// 6. MOUNTING & ENGINE
|
|
269
|
+
// =========================================================================
|
|
261
270
|
var mountComponent = (rootElement) => {
|
|
262
271
|
if (rootElement.__isMounted) return;
|
|
263
272
|
rootElement.__isMounted = 1;
|
|
@@ -273,28 +282,34 @@ var spiki = (() => {
|
|
|
273
282
|
|
|
274
283
|
var cleanupCallbacks = [];
|
|
275
284
|
|
|
285
|
+
// --- Global Event Delegation Handler ---
|
|
276
286
|
var handleEvent = (e) => {
|
|
277
287
|
var target = e.target;
|
|
278
288
|
|
|
289
|
+
// Handle s-model updates
|
|
279
290
|
if (target.__modelPath && (e.type === 'input' || e.type === 'change')) {
|
|
280
291
|
var path = target.__modelPath;
|
|
292
|
+
// Use tagged scope if available, else root state
|
|
293
|
+
var scope = target.__scope || state;
|
|
281
294
|
var value = target.type === 'checkbox' ? target.checked : target.value;
|
|
282
|
-
var evaluation = evaluatePath(
|
|
295
|
+
var evaluation = evaluatePath(scope, path);
|
|
283
296
|
var parentObject = evaluation.context;
|
|
284
297
|
|
|
285
298
|
if (path.indexOf('.') === -1) {
|
|
286
|
-
|
|
299
|
+
scope[path] = value;
|
|
287
300
|
} else if (parentObject) {
|
|
288
301
|
var parts = path.split('.');
|
|
289
302
|
parentObject[parts[parts.length - 1]] = value;
|
|
290
303
|
}
|
|
291
304
|
}
|
|
292
305
|
|
|
306
|
+
// Handle standard events (s-click, etc.)
|
|
293
307
|
var handlerName;
|
|
294
308
|
while (target && target !== rootElement.parentNode) {
|
|
295
309
|
var meta = eventMetadataMap.get(target);
|
|
296
310
|
if (meta && (handlerName = meta[e.type])) {
|
|
297
|
-
var
|
|
311
|
+
var targetScope = target.__scope || state;
|
|
312
|
+
var evalResult = evaluatePath(targetScope, handlerName);
|
|
298
313
|
var handlerFn = evalResult.value;
|
|
299
314
|
var handlerContext = evalResult.context;
|
|
300
315
|
|
|
@@ -306,17 +321,21 @@ var spiki = (() => {
|
|
|
306
321
|
}
|
|
307
322
|
};
|
|
308
323
|
|
|
324
|
+
// --- Core Recursive Walker ---
|
|
309
325
|
var walkDOM = (el, currentScope, cleanupList) => {
|
|
326
|
+
// 1. Fast Reject: Text nodes, Comments, or s-ignore
|
|
310
327
|
if (el.nodeType !== 1 || el.hasAttribute('s-ignore')) return;
|
|
311
328
|
|
|
329
|
+
// 2. Component Boundary Check
|
|
312
330
|
if (el !== rootElement && el.hasAttribute('s-data')) {
|
|
313
331
|
var childComponent = mountComponent(el);
|
|
314
332
|
if (childComponent) cleanupList.push(childComponent.unmount);
|
|
315
|
-
return;
|
|
333
|
+
return; // Stop recursion here, child handles itself
|
|
316
334
|
}
|
|
317
335
|
|
|
318
336
|
var attributeValue;
|
|
319
337
|
|
|
338
|
+
// 3. Structural Directive: s-if
|
|
320
339
|
if ((attributeValue = el.getAttribute('s-if'))) {
|
|
321
340
|
var anchor = document.createTextNode('');
|
|
322
341
|
var branchCleanups = [];
|
|
@@ -338,6 +357,7 @@ var spiki = (() => {
|
|
|
338
357
|
if (!activeNode) {
|
|
339
358
|
activeNode = el.cloneNode(true);
|
|
340
359
|
activeNode.removeAttribute('s-if');
|
|
360
|
+
// Recurse into the new branch
|
|
341
361
|
walkDOM(activeNode, currentScope, branchCleanups);
|
|
342
362
|
anchor.parentNode.insertBefore(activeNode, anchor);
|
|
343
363
|
}
|
|
@@ -350,6 +370,7 @@ var spiki = (() => {
|
|
|
350
370
|
}, nextTick));
|
|
351
371
|
}
|
|
352
372
|
|
|
373
|
+
// 4. Structural Directive: s-for
|
|
353
374
|
if (el.tagName === 'TEMPLATE' && (attributeValue = el.getAttribute('s-for'))) {
|
|
354
375
|
var match = attributeValue.match(loopRegex);
|
|
355
376
|
if (!match) return;
|
|
@@ -416,6 +437,7 @@ var spiki = (() => {
|
|
|
416
437
|
while (childNode) {
|
|
417
438
|
rowNodes.push(childNode);
|
|
418
439
|
var nextSibling = childNode.nextSibling;
|
|
440
|
+
// Recursive walk for new DOM nodes
|
|
419
441
|
walkDOM(childNode, rowScope, rowCleanups);
|
|
420
442
|
childNode = nextSibling;
|
|
421
443
|
}
|
|
@@ -444,82 +466,97 @@ var spiki = (() => {
|
|
|
444
466
|
}, nextTick));
|
|
445
467
|
}
|
|
446
468
|
|
|
469
|
+
// 5. Attribute Binding & Interactivity Check
|
|
447
470
|
var attributes = el.attributes;
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
);
|
|
465
|
-
}, nextTick));
|
|
466
|
-
|
|
467
|
-
} else if (name[0] === 's' && name[1] === '-') {
|
|
468
|
-
var directiveType = name.slice(2);
|
|
471
|
+
var isInteractive = false;
|
|
472
|
+
|
|
473
|
+
if (attributes && attributes.length > 0) {
|
|
474
|
+
// Reverse loop for safety
|
|
475
|
+
for (var i = attributes.length - 1; i >= 0; i--) {
|
|
476
|
+
((attr) => {
|
|
477
|
+
var name = attr.name;
|
|
478
|
+
var value = attr.value;
|
|
469
479
|
|
|
470
|
-
if (
|
|
471
|
-
state.$refs[value] = el;
|
|
472
|
-
} else if (directiveType === 'model') {
|
|
473
|
-
cleanupList.push(createEffect(() => {
|
|
474
|
-
var evaluation = evaluatePath(currentScope, value);
|
|
475
|
-
domOperations.value(el, evaluation.value);
|
|
476
|
-
}, nextTick));
|
|
477
|
-
|
|
478
|
-
if (/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)) {
|
|
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);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
} else if (domOperations[directiveType]) {
|
|
480
|
+
if (name[0] === ':') {
|
|
492
481
|
cleanupList.push(createEffect(() => {
|
|
493
482
|
var evaluation = evaluatePath(currentScope, value);
|
|
494
483
|
var result = evaluation.value;
|
|
495
484
|
var context = evaluation.context;
|
|
496
|
-
|
|
485
|
+
var opName = name.slice(1) === 'class' ? 'class' : 'attr';
|
|
486
|
+
|
|
487
|
+
domOperations[opName](
|
|
497
488
|
el,
|
|
498
|
-
typeof result === 'function' ? result.call(context, el) : result
|
|
489
|
+
typeof result === 'function' ? result.call(context, el) : result,
|
|
490
|
+
name.slice(1)
|
|
499
491
|
);
|
|
500
492
|
}, nextTick));
|
|
501
|
-
} else {
|
|
502
|
-
el.__scope = currentScope;
|
|
503
|
-
var meta = eventMetadataMap.get(el);
|
|
504
|
-
if (!meta) {
|
|
505
|
-
meta = {};
|
|
506
|
-
eventMetadataMap.set(el, meta);
|
|
507
|
-
}
|
|
508
|
-
meta[directiveType] = value;
|
|
509
493
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
494
|
+
} else if (name[0] === 's' && name[1] === '-') {
|
|
495
|
+
var directiveType = name.slice(2);
|
|
496
|
+
|
|
497
|
+
if (directiveType === 'ref') {
|
|
498
|
+
state.$refs[value] = el;
|
|
499
|
+
} else if (directiveType === 'model') {
|
|
500
|
+
isInteractive = true; // Flag for scope attachment
|
|
501
|
+
cleanupList.push(createEffect(() => {
|
|
502
|
+
var evaluation = evaluatePath(currentScope, value);
|
|
503
|
+
domOperations.value(el, evaluation.value);
|
|
504
|
+
}, nextTick));
|
|
505
|
+
|
|
506
|
+
if (/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)) {
|
|
507
|
+
el.__modelPath = value;
|
|
508
|
+
var eventType = (el.type === 'checkbox' || el.type === 'radio' || el.tagName === 'SELECT')
|
|
509
|
+
? 'change'
|
|
510
|
+
: 'input';
|
|
511
|
+
|
|
512
|
+
if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
|
|
513
|
+
if (!rootElement.__listeningEvents.has(eventType)) {
|
|
514
|
+
rootElement.__listeningEvents.add(eventType);
|
|
515
|
+
rootElement.addEventListener(eventType, handleEvent);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
} else if (domOperations[directiveType]) {
|
|
519
|
+
cleanupList.push(createEffect(() => {
|
|
520
|
+
var evaluation = evaluatePath(currentScope, value);
|
|
521
|
+
var result = evaluation.value;
|
|
522
|
+
var context = evaluation.context;
|
|
523
|
+
domOperations[directiveType](
|
|
524
|
+
el,
|
|
525
|
+
typeof result === 'function' ? result.call(context, el) : result
|
|
526
|
+
);
|
|
527
|
+
}, nextTick));
|
|
528
|
+
} else {
|
|
529
|
+
// Event Handlers
|
|
530
|
+
isInteractive = true; // Flag for scope attachment
|
|
531
|
+
var meta = eventMetadataMap.get(el);
|
|
532
|
+
if (!meta) {
|
|
533
|
+
meta = {};
|
|
534
|
+
eventMetadataMap.set(el, meta);
|
|
535
|
+
}
|
|
536
|
+
meta[directiveType] = value;
|
|
537
|
+
|
|
538
|
+
if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
|
|
539
|
+
if (!rootElement.__listeningEvents.has(directiveType)) {
|
|
540
|
+
rootElement.__listeningEvents.add(directiveType);
|
|
541
|
+
rootElement.addEventListener(directiveType, handleEvent);
|
|
542
|
+
}
|
|
514
543
|
}
|
|
515
544
|
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
545
|
+
})(attributes[i]);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// 6. Selective Scope Attachment
|
|
550
|
+
// Only attach scope to DOM elements that actually need it for events/models.
|
|
551
|
+
// This saves memory on static elements.
|
|
552
|
+
if (isInteractive) {
|
|
553
|
+
el.__scope = currentScope;
|
|
518
554
|
}
|
|
519
555
|
|
|
520
|
-
|
|
556
|
+
// 7. Recursive Traversal (Optimized Native Loop)
|
|
557
|
+
var child = el.firstChild;
|
|
521
558
|
while (child) {
|
|
522
|
-
var next = child.
|
|
559
|
+
var next = child.nextSibling;
|
|
523
560
|
walkDOM(child, currentScope, cleanupList);
|
|
524
561
|
child = next;
|
|
525
562
|
}
|
|
@@ -542,6 +579,9 @@ var spiki = (() => {
|
|
|
542
579
|
};
|
|
543
580
|
};
|
|
544
581
|
|
|
582
|
+
// =========================================================================
|
|
583
|
+
// 7. PUBLIC API
|
|
584
|
+
// =========================================================================
|
|
545
585
|
return {
|
|
546
586
|
data: (name, factoryFn) => {
|
|
547
587
|
componentRegistry[name] = factoryFn;
|
package/spiki.esm.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var spiki=(()=>{var n,r,
|
|
1
|
+
var spiki=(()=>{var n,r,A=Object,P=Array,T=Reflect,e=Promise,L=Map,N=Set,t=WeakMap,a=Node,k=document,$="length",C="value",S="push",M="forEach",u="indexOf",O="split",j="slice",R="call",W="get",q="set",z="add",B="delete",D="has",i="clear",F="prototype",H="hasOwnProperty",I="create",U="isArray",X="getAttribute",G="removeAttribute",J="hasAttribute",K="tagName",Q="type",V="name",v="checked",Y="parentNode",Z="nextSibling",ee="firstChild",re="replaceWith",te="insertBefore",ne="cloneNode",ae="remove",oe="createTextNode",se="addEventListener",ie="checkbox",le="function",ue="object",o="dependencies",ve="cleanups",fe="nodes",ce="context",s="scheduler",l=A[I](null),pe=new t,f=new t,c=new t,p=new L,d=new N,de=/^\s*(.*?)\s+in\s+(.+)\s*$/,y=!0,_=e.resolve(),h={};[S,"pop","shift","unshift","splice","sort","reverse"][M](t=>{h[t]=function(){for(var e=[],r=0;r<arguments[$];r++)e[r]=arguments[r];y=!1;try{return P[F][t].apply(this,e)}finally{y=!0,m(this,$)}}});var ye=(e,r)=>{if("string"!=typeof r)return{value:r,context:e};if(-1===r[u]("."))return{value:e?e[r]:void 0,context:e};var t=p[W](r);t||(1e3<p.size&&p[i](),t=r[O]("."),p[q](r,t));for(var n=e,a=e,o=0;o<t[$];o++){var s=t[o];if(null==n)return{value:n,context:null};n=(a=n)[s]}return{value:n,context:a}},_e=e=>!d[D](e)&&d[z](e)&&!r&&(r=!0)&&_.then(()=>{d[M](e=>e()),d[i](),r=!1}),he=(e,r)=>{var t;n&&((t=f[W](e))||(t=new L,f[q](e,t)),(e=t[W](r))||(e=new N,t[q](r,e)),e[z](n),n[o][z](e))},m=(e,r)=>{var t,n;y&&(t=f[W](e))&&(n=t[W](r))&&n[M](e=>{e[s]?e[s](e):e()})},me=(r,e)=>{var t=()=>{t[o][M](e=>e[B](t)),t[o][i]();var e=n;n=t;try{r()}finally{n=e}};return t[o]=new N,t[s]=e,t(),()=>{t[o][M](e=>e[B](t)),t[o][i](),d[B](t)}},g=e=>{if(!e||typeof e!=ue||e._p||e instanceof a)return e;var r=c[W](e);if(r)return r;r=new Proxy(e,{get:(e,r,t)=>{if("_r"===r)return e;if("_p"===r)return!0;if(P[U](e)&&h[H](r))return h[r];he(e,r);t=T[W](e,r,t);return!t||typeof t!=ue||t instanceof a?t:g(t)},set:(e,r,t,n)=>{var a=e[r],o=P[U](e)?Number(r)<e[$]:A[F][H][R](e,r),n=T[q](e,r,t,n);return y&&(o?a!==t&&m(e,r):(m(e,r),P[U](e)&&m(e,$))),n},deleteProperty:(e,r)=>{var t=A[F][H][R](e,r),n=T.deleteProperty(e,r);return n&&t&&(m(e,r),P[U](e)&&m(e,$)),n}});return c[q](e,r),r},ge=g({}),we={text:(e,r)=>{e.textContent=null!=r?r:""},html:(e,r)=>{e.innerHTML=null!=r?r:""},value:(e,r)=>{e[Q]===ie?e[v]=!!r:"radio"===e[Q]&&e[V]?e[v]=e[C]==r:e[C]!=r&&(e[C]=null!=r?r:"")},attr:(e,r,t)=>{null==r||!1===r?e[G](t):e.setAttribute(t,!0===r?"":r)},class:(t,e)=>{"string"==typeof e&&e[O](/\s+/)[M](e=>{var r;e&&(e=(r="!"===e[0])?e[j](1):e,t.classList[r?ae:z](e))})},init:()=>{},destroy:()=>{}},xe=w=>{if(!w._m){w._m=1;var e=w[X]("s-data"),e=l[e];if(e){var x=g(e());x.$refs={},x.$root=w,x.$store=ge;var r=[],b=e=>{var r,t,n,a,o,s=e.target;for(!s._t||"input"!==e[Q]&&"change"!==e[Q]||(a=s._t,r=s._s||x,t=s[Q]===ie?s[v]:s[C],n=ye(r,a)[ce],-1===a[u](".")?r[a]=t:n&&(n[(a=a[O]("."))[a[$]-1]]=t));s&&s!==w[Y];){var i,l=pe[W](s);l&&(o=l[e[Q]])&&(i=s._s||x,i=(l=ye(i,o))[C],l=l[ce],typeof i==le&&i[R](l,e)),s=s[Y]}},E=(d,y,o)=>{if(1===d.nodeType&&!d[J]("s-ignore"))if(d!==w&&d[J]("s-data")){var e=xe(d);e&&o[S](e.unmount)}else{var t;if(t=d[X]("s-if")){var n,a=k[oe](""),s=[];return d[re](a),o[S](()=>{s[M](e=>e())}),o[S](me(()=>{var e=ye(y,t),r=e[C],e=e[ce];(typeof r==le?r[R](e,d):r)?n||((n=d[ne](!0))[G]("s-if"),E(n,y,s),a[Y][te](n,a)):n&&(s[M](e=>e()),s[$]=0,n[ae](),n=null)},_e))}if("TEMPLATE"===d[K]&&(t=d[X]("s-for"))){var r=t.match(de);if(!r)return;var e=r[1].replace(/[()]/g,""),i=r[2],e=e[O](","),_=e[0].trim(),h=e[1]?e[1].trim():null,m=d[X]("s-key"),l=k[oe]("");d[re](l);var g=new L;return o[S](()=>{g[M](e=>{e[ve][M](e=>e())})}),o[S](me(()=>{var f=ye(y,i)[C];P[U](f)&&he(f,$);var c=l,e=P[U](f)?f:f?A.keys(f):[],p=new L;e[M]((e,r)=>{var t,n=P[U](f)?r:e,a=P[U](f)?e:f[e],o=m&&a?a[m]:typeof a==ue&&a?a:n+"_"+a,r=g[W](o),e=e=>{A.defineProperty(e,_,{configurable:!0,enumerable:!0,get:()=>f[n],set:e=>{f[n]=e}})};if(r)e(r.scope),h&&(r.scope[h]=n);else{var a=d.content[ne](!0),s=(e=>{e=A[I](e);return new Proxy(e,{set:(e,r,t,n)=>{if(e[H](r))return T[q](e,r,t,n);for(var a=e;a&&!A[F][H][R](a,r);)a=A.getPrototypeOf(a);return T[q](a||e,r,t)}})})(y),i=[];e(s),h&&(s[h]=n);for(var l=[],u=a[ee];u;){l[S](u);var v=u[Z];E(u,s,i),u=v}r={nodes:l,scope:s,cleanups:i}}r[fe][0]!==c[Z]&&(t=k.createDocumentFragment(),r[fe][M](e=>t.appendChild(e)),c[Y][te](t,c[Z])),c=r[fe][r[fe][$]-1],p[q](o,r),g[B](o)}),g[M](e=>{e[ve][M](e=>e()),e[fe][M](e=>e[ae]())}),g=p},_e))}var u=d.attributes,v=!1;if(u&&0<u[$])for(var f=u[$]-1;0<=f;f--)(e=>{var t,r,n=e[V],a=e[C];":"===n[0]?o[S](me(()=>{var e=ye(y,a),r=e[C],t=e[ce],e="class"===n[j](1)?"class":"attr";we[e](d,typeof r==le?r[R](t,d):r,n[j](1))},_e)):"s"===n[0]&&"-"===n[1]&&("ref"===(t=n[j](2))?x.$refs[a]=d:"model"===t?(v=!0,o[S](me(()=>{var e=ye(y,a);we[C](d,e[C])},_e)),/^(INPUT|SELECT|TEXTAREA)$/.test(d[K])&&(d._t=a,r=d[Q]===ie||"radio"===d[Q]||"SELECT"===d[K]?"change":"input",w._e||(w._e=new N),w._e[D](r)||(w._e[z](r),w[se](r,b)))):we[t]?o[S](me(()=>{var e=ye(y,a),r=e[C],e=e[ce];we[t](d,typeof r==le?r[R](e,d):r)},_e)):(v=!0,(r=pe[W](d))||(r={},pe[q](d,r)),r[t]=a,w._e||(w._e=new N),w._e[D](t)||(w._e[z](t),w[se](t,b))))})(u[f]);v&&(d._s=y);for(var c=d[ee];c;){var p=c[Z];E(c,y,o),c=p}}};return E(w,x,r),x.init&&x.init(),{unmount:()=>{x.destroy&&x.destroy[R](x),r[M](e=>e()),w._e&&w._e[M](e=>{w.removeEventListener(e,b)}),w._m=0}}}}};return{data:(e,r)=>{l[e]=r},start:()=>{for(var e=k.querySelectorAll("[s-data]"),r=0;r<e[$];r++)xe(e[r])},store:(e,r)=>void 0===r?ge[e]:ge[e]=r,raw:e=>e&&e._r||e}})();export default spiki;
|
package/spiki.js
CHANGED
|
@@ -2,26 +2,29 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var spiki = (() => {
|
|
5
|
-
//
|
|
5
|
+
// =========================================================================
|
|
6
|
+
// 1. STATE & STORAGE
|
|
7
|
+
// =========================================================================
|
|
6
8
|
var componentRegistry = Object.create(null);
|
|
7
9
|
var eventMetadataMap = new WeakMap();
|
|
8
|
-
var dependencyMap = new WeakMap();
|
|
9
|
-
var proxyCache = new WeakMap();
|
|
10
|
-
var pathSplitCache = new Map();
|
|
11
|
-
var schedulerQueue = new Set();
|
|
10
|
+
var dependencyMap = new WeakMap(); // Stores dependencies: Target -> Key -> Set<Effect>
|
|
11
|
+
var proxyCache = new WeakMap(); // Prevents double-wrapping objects
|
|
12
|
+
var pathSplitCache = new Map(); // Caches "user.name" -> ["user", "name"]
|
|
13
|
+
var schedulerQueue = new Set(); // Async task queue
|
|
12
14
|
|
|
13
|
-
var loopRegex = /^\s*(.*?)\s+in\s+(.+)\s*$/;
|
|
15
|
+
var loopRegex = /^\s*(.*?)\s+in\s+(.+)\s*$/; // Regex for "item in items"
|
|
14
16
|
|
|
15
|
-
//
|
|
17
|
+
// Global flags
|
|
16
18
|
var currentActiveEffect;
|
|
17
19
|
var isFlushingQueue;
|
|
18
20
|
var globalStore;
|
|
19
21
|
var shouldTriggerEffects = true;
|
|
20
22
|
var resolvedPromise = Promise.resolve();
|
|
21
23
|
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
24
|
+
// =========================================================================
|
|
25
|
+
// 2. ARRAY INSTRUMENTATION
|
|
26
|
+
// Intercepts array mutation methods to trigger reactivity
|
|
27
|
+
// =========================================================================
|
|
25
28
|
var arrayInstrumentations = {};
|
|
26
29
|
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(methodName => {
|
|
27
30
|
arrayInstrumentations[methodName] = function () {
|
|
@@ -41,10 +44,12 @@ var spiki = (() => {
|
|
|
41
44
|
};
|
|
42
45
|
});
|
|
43
46
|
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
+
// =========================================================================
|
|
48
|
+
// 3. HELPER FUNCTIONS
|
|
49
|
+
// =========================================================================
|
|
47
50
|
|
|
51
|
+
// Creates a child scope that inherits from parent.
|
|
52
|
+
// Writes bubble up to the object that actually owns the property.
|
|
48
53
|
var createScope = (parentScope) => {
|
|
49
54
|
var proto = Object.create(parentScope);
|
|
50
55
|
return new Proxy(proto, {
|
|
@@ -63,6 +68,7 @@ var spiki = (() => {
|
|
|
63
68
|
});
|
|
64
69
|
};
|
|
65
70
|
|
|
71
|
+
// Resolves "user.name" from the scope
|
|
66
72
|
var evaluatePath = (scope, path) => {
|
|
67
73
|
if (typeof path !== 'string') return { value: path, context: scope };
|
|
68
74
|
|
|
@@ -91,6 +97,7 @@ var spiki = (() => {
|
|
|
91
97
|
return { value: currentValue, context: currentContext };
|
|
92
98
|
};
|
|
93
99
|
|
|
100
|
+
// Microtask Scheduler
|
|
94
101
|
var nextTick = (fn) => {
|
|
95
102
|
return !schedulerQueue.has(fn) &&
|
|
96
103
|
schedulerQueue.add(fn) &&
|
|
@@ -103,9 +110,9 @@ var spiki = (() => {
|
|
|
103
110
|
});
|
|
104
111
|
};
|
|
105
112
|
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
113
|
+
// =========================================================================
|
|
114
|
+
// 4. REACTIVITY SYSTEM
|
|
115
|
+
// =========================================================================
|
|
109
116
|
|
|
110
117
|
var trackDependency = (target, key) => {
|
|
111
118
|
if (!currentActiveEffect) return;
|
|
@@ -137,6 +144,7 @@ var spiki = (() => {
|
|
|
137
144
|
|
|
138
145
|
var createEffect = (fn, scheduler) => {
|
|
139
146
|
var runner = () => {
|
|
147
|
+
// Clean up old dependencies before re-running
|
|
140
148
|
runner.dependencies.forEach(depSet => depSet.delete(runner));
|
|
141
149
|
runner.dependencies.clear();
|
|
142
150
|
|
|
@@ -151,7 +159,7 @@ var spiki = (() => {
|
|
|
151
159
|
|
|
152
160
|
runner.dependencies = new Set();
|
|
153
161
|
runner.scheduler = scheduler;
|
|
154
|
-
runner();
|
|
162
|
+
runner(); // Run immediately
|
|
155
163
|
|
|
156
164
|
return () => {
|
|
157
165
|
runner.dependencies.forEach(depSet => depSet.delete(runner));
|
|
@@ -178,6 +186,7 @@ var spiki = (() => {
|
|
|
178
186
|
trackDependency(target, key);
|
|
179
187
|
|
|
180
188
|
var result = Reflect.get(target, key, receiver);
|
|
189
|
+
// Deep reactivity
|
|
181
190
|
return result && typeof result === 'object' && !(result instanceof Node)
|
|
182
191
|
? makeReactive(result)
|
|
183
192
|
: result;
|
|
@@ -217,9 +226,9 @@ var spiki = (() => {
|
|
|
217
226
|
|
|
218
227
|
globalStore = makeReactive({});
|
|
219
228
|
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
229
|
+
// =========================================================================
|
|
230
|
+
// 5. DOM OPERATIONS
|
|
231
|
+
// =========================================================================
|
|
223
232
|
var domOperations = {
|
|
224
233
|
text: (el, value) => {
|
|
225
234
|
el.textContent = (value !== null && value !== undefined) ? value : '';
|
|
@@ -258,9 +267,9 @@ var spiki = (() => {
|
|
|
258
267
|
destroy: () => { }
|
|
259
268
|
};
|
|
260
269
|
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
270
|
+
// =========================================================================
|
|
271
|
+
// 6. MOUNTING & ENGINE
|
|
272
|
+
// =========================================================================
|
|
264
273
|
var mountComponent = (rootElement) => {
|
|
265
274
|
if (rootElement.__isMounted) return;
|
|
266
275
|
rootElement.__isMounted = 1;
|
|
@@ -276,28 +285,34 @@ var spiki = (() => {
|
|
|
276
285
|
|
|
277
286
|
var cleanupCallbacks = [];
|
|
278
287
|
|
|
288
|
+
// --- Global Event Delegation Handler ---
|
|
279
289
|
var handleEvent = (e) => {
|
|
280
290
|
var target = e.target;
|
|
281
291
|
|
|
292
|
+
// Handle s-model updates
|
|
282
293
|
if (target.__modelPath && (e.type === 'input' || e.type === 'change')) {
|
|
283
294
|
var path = target.__modelPath;
|
|
295
|
+
// Use tagged scope if available, else root state
|
|
296
|
+
var scope = target.__scope || state;
|
|
284
297
|
var value = target.type === 'checkbox' ? target.checked : target.value;
|
|
285
|
-
var evaluation = evaluatePath(
|
|
298
|
+
var evaluation = evaluatePath(scope, path);
|
|
286
299
|
var parentObject = evaluation.context;
|
|
287
300
|
|
|
288
301
|
if (path.indexOf('.') === -1) {
|
|
289
|
-
|
|
302
|
+
scope[path] = value;
|
|
290
303
|
} else if (parentObject) {
|
|
291
304
|
var parts = path.split('.');
|
|
292
305
|
parentObject[parts[parts.length - 1]] = value;
|
|
293
306
|
}
|
|
294
307
|
}
|
|
295
308
|
|
|
309
|
+
// Handle standard events (s-click, etc.)
|
|
296
310
|
var handlerName;
|
|
297
311
|
while (target && target !== rootElement.parentNode) {
|
|
298
312
|
var meta = eventMetadataMap.get(target);
|
|
299
313
|
if (meta && (handlerName = meta[e.type])) {
|
|
300
|
-
var
|
|
314
|
+
var targetScope = target.__scope || state;
|
|
315
|
+
var evalResult = evaluatePath(targetScope, handlerName);
|
|
301
316
|
var handlerFn = evalResult.value;
|
|
302
317
|
var handlerContext = evalResult.context;
|
|
303
318
|
|
|
@@ -309,17 +324,21 @@ var spiki = (() => {
|
|
|
309
324
|
}
|
|
310
325
|
};
|
|
311
326
|
|
|
327
|
+
// --- Core Recursive Walker ---
|
|
312
328
|
var walkDOM = (el, currentScope, cleanupList) => {
|
|
329
|
+
// 1. Fast Reject: Text nodes, Comments, or s-ignore
|
|
313
330
|
if (el.nodeType !== 1 || el.hasAttribute('s-ignore')) return;
|
|
314
331
|
|
|
332
|
+
// 2. Component Boundary Check
|
|
315
333
|
if (el !== rootElement && el.hasAttribute('s-data')) {
|
|
316
334
|
var childComponent = mountComponent(el);
|
|
317
335
|
if (childComponent) cleanupList.push(childComponent.unmount);
|
|
318
|
-
return;
|
|
336
|
+
return; // Stop recursion here, child handles itself
|
|
319
337
|
}
|
|
320
338
|
|
|
321
339
|
var attributeValue;
|
|
322
340
|
|
|
341
|
+
// 3. Structural Directive: s-if
|
|
323
342
|
if ((attributeValue = el.getAttribute('s-if'))) {
|
|
324
343
|
var anchor = document.createTextNode('');
|
|
325
344
|
var branchCleanups = [];
|
|
@@ -341,6 +360,7 @@ var spiki = (() => {
|
|
|
341
360
|
if (!activeNode) {
|
|
342
361
|
activeNode = el.cloneNode(true);
|
|
343
362
|
activeNode.removeAttribute('s-if');
|
|
363
|
+
// Recurse into the new branch
|
|
344
364
|
walkDOM(activeNode, currentScope, branchCleanups);
|
|
345
365
|
anchor.parentNode.insertBefore(activeNode, anchor);
|
|
346
366
|
}
|
|
@@ -353,6 +373,7 @@ var spiki = (() => {
|
|
|
353
373
|
}, nextTick));
|
|
354
374
|
}
|
|
355
375
|
|
|
376
|
+
// 4. Structural Directive: s-for
|
|
356
377
|
if (el.tagName === 'TEMPLATE' && (attributeValue = el.getAttribute('s-for'))) {
|
|
357
378
|
var match = attributeValue.match(loopRegex);
|
|
358
379
|
if (!match) return;
|
|
@@ -419,6 +440,7 @@ var spiki = (() => {
|
|
|
419
440
|
while (childNode) {
|
|
420
441
|
rowNodes.push(childNode);
|
|
421
442
|
var nextSibling = childNode.nextSibling;
|
|
443
|
+
// Recursive walk for new DOM nodes
|
|
422
444
|
walkDOM(childNode, rowScope, rowCleanups);
|
|
423
445
|
childNode = nextSibling;
|
|
424
446
|
}
|
|
@@ -447,82 +469,97 @@ var spiki = (() => {
|
|
|
447
469
|
}, nextTick));
|
|
448
470
|
}
|
|
449
471
|
|
|
472
|
+
// 5. Attribute Binding & Interactivity Check
|
|
450
473
|
var attributes = el.attributes;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
);
|
|
468
|
-
}, nextTick));
|
|
469
|
-
|
|
470
|
-
} else if (name[0] === 's' && name[1] === '-') {
|
|
471
|
-
var directiveType = name.slice(2);
|
|
474
|
+
var isInteractive = false;
|
|
475
|
+
|
|
476
|
+
if (attributes && attributes.length > 0) {
|
|
477
|
+
// Reverse loop for safety
|
|
478
|
+
for (var i = attributes.length - 1; i >= 0; i--) {
|
|
479
|
+
((attr) => {
|
|
480
|
+
var name = attr.name;
|
|
481
|
+
var value = attr.value;
|
|
472
482
|
|
|
473
|
-
if (
|
|
474
|
-
state.$refs[value] = el;
|
|
475
|
-
} else if (directiveType === 'model') {
|
|
476
|
-
cleanupList.push(createEffect(() => {
|
|
477
|
-
var evaluation = evaluatePath(currentScope, value);
|
|
478
|
-
domOperations.value(el, evaluation.value);
|
|
479
|
-
}, nextTick));
|
|
480
|
-
|
|
481
|
-
if (/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)) {
|
|
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);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
} else if (domOperations[directiveType]) {
|
|
483
|
+
if (name[0] === ':') {
|
|
495
484
|
cleanupList.push(createEffect(() => {
|
|
496
485
|
var evaluation = evaluatePath(currentScope, value);
|
|
497
486
|
var result = evaluation.value;
|
|
498
487
|
var context = evaluation.context;
|
|
499
|
-
|
|
488
|
+
var opName = name.slice(1) === 'class' ? 'class' : 'attr';
|
|
489
|
+
|
|
490
|
+
domOperations[opName](
|
|
500
491
|
el,
|
|
501
|
-
typeof result === 'function' ? result.call(context, el) : result
|
|
492
|
+
typeof result === 'function' ? result.call(context, el) : result,
|
|
493
|
+
name.slice(1)
|
|
502
494
|
);
|
|
503
495
|
}, nextTick));
|
|
504
|
-
} else {
|
|
505
|
-
el.__scope = currentScope;
|
|
506
|
-
var meta = eventMetadataMap.get(el);
|
|
507
|
-
if (!meta) {
|
|
508
|
-
meta = {};
|
|
509
|
-
eventMetadataMap.set(el, meta);
|
|
510
|
-
}
|
|
511
|
-
meta[directiveType] = value;
|
|
512
496
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
497
|
+
} else if (name[0] === 's' && name[1] === '-') {
|
|
498
|
+
var directiveType = name.slice(2);
|
|
499
|
+
|
|
500
|
+
if (directiveType === 'ref') {
|
|
501
|
+
state.$refs[value] = el;
|
|
502
|
+
} else if (directiveType === 'model') {
|
|
503
|
+
isInteractive = true; // Flag for scope attachment
|
|
504
|
+
cleanupList.push(createEffect(() => {
|
|
505
|
+
var evaluation = evaluatePath(currentScope, value);
|
|
506
|
+
domOperations.value(el, evaluation.value);
|
|
507
|
+
}, nextTick));
|
|
508
|
+
|
|
509
|
+
if (/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)) {
|
|
510
|
+
el.__modelPath = value;
|
|
511
|
+
var eventType = (el.type === 'checkbox' || el.type === 'radio' || el.tagName === 'SELECT')
|
|
512
|
+
? 'change'
|
|
513
|
+
: 'input';
|
|
514
|
+
|
|
515
|
+
if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
|
|
516
|
+
if (!rootElement.__listeningEvents.has(eventType)) {
|
|
517
|
+
rootElement.__listeningEvents.add(eventType);
|
|
518
|
+
rootElement.addEventListener(eventType, handleEvent);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
} else if (domOperations[directiveType]) {
|
|
522
|
+
cleanupList.push(createEffect(() => {
|
|
523
|
+
var evaluation = evaluatePath(currentScope, value);
|
|
524
|
+
var result = evaluation.value;
|
|
525
|
+
var context = evaluation.context;
|
|
526
|
+
domOperations[directiveType](
|
|
527
|
+
el,
|
|
528
|
+
typeof result === 'function' ? result.call(context, el) : result
|
|
529
|
+
);
|
|
530
|
+
}, nextTick));
|
|
531
|
+
} else {
|
|
532
|
+
// Event Handlers
|
|
533
|
+
isInteractive = true; // Flag for scope attachment
|
|
534
|
+
var meta = eventMetadataMap.get(el);
|
|
535
|
+
if (!meta) {
|
|
536
|
+
meta = {};
|
|
537
|
+
eventMetadataMap.set(el, meta);
|
|
538
|
+
}
|
|
539
|
+
meta[directiveType] = value;
|
|
540
|
+
|
|
541
|
+
if (!rootElement.__listeningEvents) rootElement.__listeningEvents = new Set();
|
|
542
|
+
if (!rootElement.__listeningEvents.has(directiveType)) {
|
|
543
|
+
rootElement.__listeningEvents.add(directiveType);
|
|
544
|
+
rootElement.addEventListener(directiveType, handleEvent);
|
|
545
|
+
}
|
|
517
546
|
}
|
|
518
547
|
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
548
|
+
})(attributes[i]);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// 6. Selective Scope Attachment
|
|
553
|
+
// Only attach scope to DOM elements that actually need it for events/models.
|
|
554
|
+
// This saves memory on static elements.
|
|
555
|
+
if (isInteractive) {
|
|
556
|
+
el.__scope = currentScope;
|
|
521
557
|
}
|
|
522
558
|
|
|
523
|
-
|
|
559
|
+
// 7. Recursive Traversal (Optimized Native Loop)
|
|
560
|
+
var child = el.firstChild;
|
|
524
561
|
while (child) {
|
|
525
|
-
var next = child.
|
|
562
|
+
var next = child.nextSibling;
|
|
526
563
|
walkDOM(child, currentScope, cleanupList);
|
|
527
564
|
child = next;
|
|
528
565
|
}
|
|
@@ -545,6 +582,9 @@ var spiki = (() => {
|
|
|
545
582
|
};
|
|
546
583
|
};
|
|
547
584
|
|
|
585
|
+
// =========================================================================
|
|
586
|
+
// 7. PUBLIC API
|
|
587
|
+
// =========================================================================
|
|
548
588
|
return {
|
|
549
589
|
data: (name, factoryFn) => {
|
|
550
590
|
componentRegistry[name] = factoryFn;
|
package/spiki.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e=(()=>{var n,
|
|
1
|
+
(()=>{"use strict";var e=(()=>{var n,r,A=Object,P=Array,T=Reflect,e=Promise,L=Map,N=Set,t=WeakMap,a=Node,k=document,$="length",C="value",S="push",M="forEach",u="indexOf",O="split",j="slice",R="call",W="get",q="set",z="add",B="delete",D="has",i="clear",F="prototype",H="hasOwnProperty",I="create",U="isArray",X="getAttribute",G="removeAttribute",J="hasAttribute",K="tagName",Q="type",V="name",v="checked",Y="parentNode",Z="nextSibling",ee="firstChild",re="replaceWith",te="insertBefore",ne="cloneNode",ae="remove",oe="createTextNode",se="addEventListener",ie="checkbox",le="function",ue="object",o="dependencies",ve="cleanups",fe="nodes",ce="context",s="scheduler",l=A[I](null),pe=new t,f=new t,c=new t,p=new L,d=new N,de=/^\s*(.*?)\s+in\s+(.+)\s*$/,y=!0,_=e.resolve(),h={};[S,"pop","shift","unshift","splice","sort","reverse"][M](t=>{h[t]=function(){for(var e=[],r=0;r<arguments[$];r++)e[r]=arguments[r];y=!1;try{return P[F][t].apply(this,e)}finally{y=!0,m(this,$)}}});var ye=(e,r)=>{if("string"!=typeof r)return{value:r,context:e};if(-1===r[u]("."))return{value:e?e[r]:void 0,context:e};var t=p[W](r);t||(1e3<p.size&&p[i](),t=r[O]("."),p[q](r,t));for(var n=e,a=e,o=0;o<t[$];o++){var s=t[o];if(null==n)return{value:n,context:null};n=(a=n)[s]}return{value:n,context:a}},_e=e=>!d[D](e)&&d[z](e)&&!r&&(r=!0)&&_.then(()=>{d[M](e=>e()),d[i](),r=!1}),he=(e,r)=>{var t;n&&((t=f[W](e))||(t=new L,f[q](e,t)),(e=t[W](r))||(e=new N,t[q](r,e)),e[z](n),n[o][z](e))},m=(e,r)=>{var t,n;y&&(t=f[W](e))&&(n=t[W](r))&&n[M](e=>{e[s]?e[s](e):e()})},me=(r,e)=>{var t=()=>{t[o][M](e=>e[B](t)),t[o][i]();var e=n;n=t;try{r()}finally{n=e}};return t[o]=new N,t[s]=e,t(),()=>{t[o][M](e=>e[B](t)),t[o][i](),d[B](t)}},w=e=>{if(!e||typeof e!=ue||e._p||e instanceof a)return e;var r=c[W](e);return r||(r=new Proxy(e,{get:(e,r,t)=>"_r"===r?e:"_p"===r||(P[U](e)&&h[H](r)?h[r]:(he(e,r),!(t=T[W](e,r,t))||typeof t!=ue||t instanceof a?t:w(t))),set:(e,r,t,n)=>{var a=e[r],o=P[U](e)?Number(r)<e[$]:A[F][H][R](e,r),n=T[q](e,r,t,n);return y&&(o?a!==t&&m(e,r):(m(e,r),P[U](e)&&m(e,$))),n},deleteProperty:(e,r)=>{var t=A[F][H][R](e,r),n=T.deleteProperty(e,r);return n&&t&&(m(e,r),P[U](e)&&m(e,$)),n}}),c[q](e,r),r)},g=w({}),we={text:(e,r)=>{e.textContent=null!=r?r:""},html:(e,r)=>{e.innerHTML=null!=r?r:""},value:(e,r)=>{e[Q]===ie?e[v]=!!r:"radio"===e[Q]&&e[V]?e[v]=e[C]==r:e[C]!=r&&(e[C]=null!=r?r:"")},attr:(e,r,t)=>{null==r||!1===r?e[G](t):e.setAttribute(t,!0===r?"":r)},class:(t,e)=>{"string"==typeof e&&e[O](/\s+/)[M](e=>{var r;e&&(e=(r="!"===e[0])?e[j](1):e,t.classList[r?ae:z](e))})},init:()=>{},destroy:()=>{}},ge=d=>{if(!d._m){d._m=1;var e=d[X]("s-data");if(e=l[e]){var x=w(e());x.$refs={},x.$root=d,x.$store=g;var r=[],b=e=>{var r,t,n,a,o,s=e.target;for(!s._t||"input"!==e[Q]&&"change"!==e[Q]||(a=s._t,r=s._s||x,t=s[Q]===ie?s[v]:s[C],n=ye(r,a)[ce],-1===a[u](".")?r[a]=t:n&&(n[(a=a[O]("."))[a[$]-1]]=t));s&&s!==d[Y];){var i,l=pe[W](s);l&&(o=l[e[Q]])&&(i=s._s||x,i=(l=ye(i,o))[C],l=l[ce],typeof i==le&&i[R](l,e)),s=s[Y]}},E=(y,_,o)=>{if(1===y.nodeType&&!y[J]("s-ignore"))if(y!==d&&y[J]("s-data"))(r=ge(y))&&o[S](r.unmount);else{var t;if(t=y[X]("s-if")){var n,a=k[oe](""),s=[];return y[re](a),o[S](()=>{s[M](e=>e())}),o[S](me(()=>{var e=(r=ye(_,t))[C],r=r[ce];(typeof e==le?e[R](r,y):e)?n||((n=y[ne](!0))[G]("s-if"),E(n,_,s),a[Y][te](n,a)):n&&(s[M](e=>e()),s[$]=0,n[ae](),n=null)},_e))}if("TEMPLATE"===y[K]&&(t=y[X]("s-for"))){var e=t.match(de);if(!e)return;var r=e[1].replace(/[()]/g,""),i=e[2],h=(r=r[O](","))[0].trim(),m=r[1]?r[1].trim():null,w=y[X]("s-key"),l=k[oe]("");y[re](l);var g=new L;return o[S](()=>{g[M](e=>{e[ve][M](e=>e())})}),o[S](me(()=>{var c=ye(_,i)[C];P[U](c)&&he(c,$);var p=l,e=P[U](c)?c:c?A.keys(c):[],d=new L;e[M]((e,r)=>{var t,n,a=P[U](c)?r:e,o=P[U](c)?e:c[e],s=w&&o?o[w]:typeof o==ue&&o?o:a+"_"+o,e=e=>{A.defineProperty(e,h,{configurable:!0,enumerable:!0,get:()=>c[a],set:e=>{c[a]=e}})};if(r=g[W](s))e(r.scope),m&&(r.scope[m]=a);else{var o=y.content[ne](!0),i=(n=_,n=A[I](n),new Proxy(n,{set:(e,r,t,n)=>{if(e[H](r))return T[q](e,r,t,n);for(var a=e;a&&!A[F][H][R](a,r);)a=A.getPrototypeOf(a);return T[q](a||e,r,t)}})),l=[];e(i),m&&(i[m]=a);for(var u=[],v=o[ee];v;){u[S](v);var f=v[Z];E(v,i,l),v=f}r={nodes:u,scope:i,cleanups:l}}r[fe][0]!==p[Z]&&(t=k.createDocumentFragment(),r[fe][M](e=>t.appendChild(e)),p[Y][te](t,p[Z])),p=r[fe][r[fe][$]-1],d[q](s,r),g[B](s)}),g[M](e=>{e[ve][M](e=>e()),e[fe][M](e=>e[ae]())}),g=d},_e))}var u=y.attributes,v=!1;if(u&&0<u[$])for(var f=u[$]-1;0<=f;f--)(e=>{var t,r,n=e[V],a=e[C];":"===n[0]?o[S](me(()=>{var e=(t=ye(_,a))[C],r=t[ce],t="class"===n[j](1)?"class":"attr";we[t](y,typeof e==le?e[R](r,y):e,n[j](1))},_e)):"s"===n[0]&&"-"===n[1]&&("ref"===(t=n[j](2))?x.$refs[a]=y:"model"===t?(v=!0,o[S](me(()=>{var e=ye(_,a);we[C](y,e[C])},_e)),/^(INPUT|SELECT|TEXTAREA)$/.test(y[K])&&(y._t=a,r=y[Q]===ie||"radio"===y[Q]||"SELECT"===y[K]?"change":"input",d._e||(d._e=new N),d._e[D](r)||(d._e[z](r),d[se](r,b)))):we[t]?o[S](me(()=>{var e=(r=ye(_,a))[C],r=r[ce];we[t](y,typeof e==le?e[R](r,y):e)},_e)):(v=!0,(r=pe[W](y))||(r={},pe[q](y,r)),r[t]=a,d._e||(d._e=new N),d._e[D](t)||(d._e[z](t),d[se](t,b))))})(u[f]);v&&(y._s=_);for(var c=y[ee];c;){var p=c[Z];E(c,_,o),c=p}}};return E(d,x,r),x.init&&x.init(),{unmount:()=>{x.destroy&&x.destroy[R](x),r[M](e=>e()),d._e&&d._e[M](e=>{d.removeEventListener(e,b)}),d._m=0}}}}};return{data:(e,r)=>{l[e]=r},start:()=>{for(var e=k.querySelectorAll("[s-data]"),r=0;r<e[$];r++)ge(e[r])},store:(e,r)=>void 0===r?g[e]:g[e]=r,raw:e=>e&&e._r||e}})();window.spiki=e})();
|