malinajs 0.6.50 → 0.7.1-alpha

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/runtime.js CHANGED
@@ -9,22 +9,32 @@ const configure = (option) => {
9
9
  const isFunction = fn => typeof fn == 'function';
10
10
 
11
11
 
12
- const isObject = d => typeof d == 'object';
13
-
14
-
15
12
  const safeCall = fn => {
16
13
  try {
17
- return isFunction(fn) && fn();
14
+ return fn?.();
18
15
  } catch (e) {
19
16
  __app_onerror(e);
20
17
  }
21
18
  };
22
19
 
20
+ function WatchObject(fn, cb) {
21
+ this.fn = fn;
22
+ this.cb = cb;
23
+ this.value = NaN;
24
+ this.ro = false;
25
+ this.cmp = null;
26
+ }
27
+
28
+
29
+ const cd_watchObject = (fn, cb, option) => {
30
+ let w = new WatchObject(fn, cb);
31
+ option && Object.assign(w, option);
32
+ return w;
33
+ };
34
+
35
+
23
36
  function $watch(cd, fn, callback, w) {
24
- if(!w) w = {};
25
- w.fn = fn;
26
- w.cb = callback;
27
- if(!('value' in w)) w.value = NaN;
37
+ w = cd_watchObject(fn, callback, w);
28
38
  cd.watchers.push(w);
29
39
  return w;
30
40
  }
@@ -32,6 +42,7 @@ function $watchReadOnly(cd, fn, callback) {
32
42
  return $watch(cd, fn, callback, {ro: true});
33
43
  }
34
44
  function addEvent(cd, el, event, callback) {
45
+ if(!callback) return;
35
46
  el.addEventListener(event, callback);
36
47
  cd_onDestroy(cd, () => {
37
48
  el.removeEventListener(event, callback);
@@ -50,7 +61,6 @@ function $ChangeDetector(parent) {
50
61
  this.watchers = [];
51
62
  this._d = [];
52
63
  this.prefix = [];
53
- this.$$ = parent?.$$;
54
64
  }
55
65
  $ChangeDetector.prototype.new = function() {
56
66
  var cd = new $ChangeDetector(this);
@@ -59,15 +69,37 @@ $ChangeDetector.prototype.new = function() {
59
69
  };
60
70
 
61
71
  $ChangeDetector.prototype.destroy = function(option) {
62
- if(option !== false && this.parent) $$removeItem(this.parent.children, this);
63
- this.watchers.length = 0;
64
- this.prefix.length = 0;
65
- this._d.map(safeCall);
66
- this._d.length = 0;
67
- this.children.map(cd => cd.destroy(false));
68
- this.children.length = 0;
72
+ cd_destroy$1(this, option);
73
+ };
74
+
75
+ const cd_component = cd => {
76
+ while(cd.parent) cd = cd.parent;
77
+ return cd.component;
69
78
  };
70
79
 
80
+ const cd_new = () => new $ChangeDetector();
81
+
82
+ const cd_attach = (parent, cd) => {
83
+ if(cd) {
84
+ cd.parent = parent;
85
+ parent.children.push(cd);
86
+ }
87
+ };
88
+
89
+ let destroyResults = null;
90
+
91
+ const cd_destroy$1 = (cd, option) => {
92
+ if(option !== false && cd.parent) $$removeItem(cd.parent.children, cd);
93
+ cd.watchers.length = 0;
94
+ cd.prefix.length = 0;
95
+ cd._d.forEach(fn => {
96
+ let p = safeCall(fn);
97
+ p && destroyResults && destroyResults.push(p);
98
+ });
99
+ cd._d.length = 0;
100
+ cd.children.map(cd => cd.destroy(false));
101
+ cd.children.length = 0;
102
+ };
71
103
 
72
104
  const isArray = (a) => Array.isArray(a);
73
105
 
@@ -95,8 +127,8 @@ function $$compareArray(w, value) {
95
127
  const compareDeep = (a, b, lvl) => {
96
128
  if(lvl < 0 || !a || !b) return a !== b;
97
129
  if(a === b) return false;
98
- let o0 = isObject(a);
99
- let o1 = isObject(b);
130
+ let o0 = typeof(a) == 'object';
131
+ let o1 = typeof(b) == 'object';
100
132
  if(!(o0 && o1)) return a !== b;
101
133
 
102
134
  let a0 = isArray(a);
@@ -126,7 +158,7 @@ const compareDeep = (a, b, lvl) => {
126
158
  function cloneDeep(d, lvl) {
127
159
  if(lvl < 0 || !d) return d;
128
160
 
129
- if(isObject(d)) {
161
+ if(typeof(d) == 'object') {
130
162
  if(d instanceof Date) return d;
131
163
  if(d instanceof Element) return d;
132
164
  if(isArray(d)) return d.map(i => cloneDeep(i, lvl-1));
@@ -205,8 +237,6 @@ function $digest($cd) {
205
237
  let templatecache = {};
206
238
  let templatecacheSvg = {};
207
239
 
208
- let $$uniqIndex = 1;
209
-
210
240
  const childNodes = 'childNodes';
211
241
  const firstChild = 'firstChild';
212
242
 
@@ -216,37 +246,41 @@ const insertAfter = (label, node) => {
216
246
  label.parentNode.insertBefore(node, label.nextSibling);
217
247
  };
218
248
 
219
- const createTextNode = (text) => {
220
- let f = document.createDocumentFragment();
221
- f.append(text);
222
- return f;
223
- };
249
+ const createTextNode = (text) => document.createTextNode(text);
224
250
 
225
- const $$htmlToFragment = (html) => {
226
- if(templatecache[html]) return templatecache[html].cloneNode(true);
251
+ const $$htmlToFragment = (html, option) => {
252
+ let result = templatecache[html];
253
+ if(!result) {
254
+ let t = document.createElement('template');
255
+ t.innerHTML = html.replace(/<>/g, '<!---->');
256
+ result = t.content;
257
+ if(!(option & 2) && result.firstChild == result.lastChild) result = result.firstChild;
258
+ templatecache[html] = result;
259
+ }
227
260
 
228
- let t = document.createElement('template');
229
- t.innerHTML = html.replace(/<>/g, '<!---->');
230
- let result = t.content;
231
- templatecache[html] = result.cloneNode(true);
232
- return result;
261
+ return option & 1 ? result.cloneNode(true) : result;
233
262
  };
234
263
 
235
- const $$htmlToFragmentClean = (html) => {
236
- if(templatecache[html]) return templatecache[html].cloneNode(true);
264
+ const $$htmlToFragmentClean = (html, option) => {
265
+ let result = templatecache[html];
266
+ if(!result) {
267
+ let t = document.createElement('template');
268
+ t.innerHTML = html.replace(/<>/g, '<!---->');
269
+ result = t.content;
270
+
271
+ let it = document.createNodeIterator(result, 128);
272
+ let n;
273
+ while(n = it.nextNode()) {
274
+ if(!n.nodeValue) n.parentNode.replaceChild(document.createTextNode(''), n);
275
+ }
276
+ if(!(option & 2) && result.firstChild == result.lastChild) result = result.firstChild;
277
+ templatecache[html] = result;
278
+ }
237
279
 
238
- let t = document.createElement('template');
239
- t.innerHTML = html.replace(/<>/g, '<!---->');
240
- let result = t.content;
241
-
242
- let it = document.createNodeIterator(result, 128);
243
- let n;
244
- while(n = it.nextNode()) {
245
- if(!n.nodeValue) n.parentNode.replaceChild(document.createTextNode(''), n);
246
- } templatecache[html] = result.cloneNode(true);
247
- return result;
280
+ return option & 1 ? result.cloneNode(true) : result;
248
281
  };
249
282
 
283
+
250
284
  function svgToFragment(content) {
251
285
  if(templatecacheSvg[content]) return templatecacheSvg[content].cloneNode(true);
252
286
  let t = document.createElement('template');
@@ -258,15 +292,21 @@ function svgToFragment(content) {
258
292
  templatecacheSvg[content] = result.cloneNode(true);
259
293
  return result;
260
294
  }
261
- function $$removeElements(el, last) {
295
+
296
+ const iterNodes = (el, last, fn) => {
262
297
  let next;
263
298
  while(el) {
264
299
  next = el.nextSibling;
265
- el.remove();
300
+ fn(el);
266
301
  if(el == last) break;
267
302
  el = next;
268
303
  }
269
- }
304
+ };
305
+
306
+
307
+ const $$removeElements = (el, last) => iterNodes(el, last, n => n.remove());
308
+
309
+
270
310
  function removeElementsBetween(el, stop) {
271
311
  let next;
272
312
  el = el.nextSibling;
@@ -285,22 +325,11 @@ const getFinalLabel = n => {
285
325
  };
286
326
 
287
327
 
288
- let _tick_list = [];
289
- let _tick_planned = {};
290
- function $tick(fn, uniq) {
291
- if(uniq) {
292
- if(_tick_planned[uniq]) return;
293
- _tick_planned[uniq] = true;
294
- }
295
- _tick_list.push(fn);
296
- if(_tick_planned.$tick) return;
297
- _tick_planned.$tick = true;
298
- setTimeout(() => {
299
- _tick_planned = {};
300
- let list = _tick_list;
301
- _tick_list = [];
302
- list.map(safeCall);
303
- }, 0);
328
+ const resolvedPromise = Promise.resolve();
329
+
330
+ function $tick(fn) {
331
+ fn && resolvedPromise.then(fn);
332
+ return resolvedPromise;
304
333
  }
305
334
 
306
335
  function $makeEmitter(option) {
@@ -335,72 +364,38 @@ const $onDestroy = fn => current_component._d.push(fn);
335
364
  const $onMount = fn => current_component._m.push(fn);
336
365
 
337
366
 
338
- const $insertElementByOption = ($label, $option, $element) => {
339
- if ($option.$l) {
340
- insertAfter($label, $element);
341
- } else {
342
- $label.appendChild($element);
343
- }
344
- };
345
-
346
-
347
- const $readOnlyBase = {
348
- a: ($component) => {
349
- $component.$cd = {
350
- _d: $component._d,
351
- watchers: [],
352
- prefix: [],
353
- new: () => $component.$cd,
354
- destroy: noop,
355
- $$: $component
356
- };
357
- },
358
- b: ($component) => {
359
- let watchers = $component.$cd.watchers;
360
- let prefix = $component.$cd.prefix;
361
- while(watchers.length || prefix.length) {
362
- let wl = watchers.slice();
363
- watchers.length = 0;
364
- prefix.forEach(safeCall);
365
- prefix.length = 0;
366
- wl.forEach(w => w.cb(w.fn()));
367
- }
368
- }
369
- };
370
-
371
-
372
367
  const $base = {
373
368
  a: ($component) => {
374
- let $cd = new $ChangeDetector();
375
- $cd.$$ = $component;
369
+ let $cd = cd_new();
370
+ $cd.component = $component;
376
371
  $onDestroy(() => $cd.destroy());
377
372
 
378
- let id = `a${$$uniqIndex++}`;
379
- let process;
373
+ let planned;
380
374
  let apply = r => {
381
- if (process) return r;
375
+ if(planned) return r;
376
+ planned = true;
382
377
  $tick(() => {
383
378
  try {
384
- process = true;
385
379
  $digest($cd);
386
380
  } finally {
387
- process = false;
381
+ planned = false;
388
382
  }
389
- }, id);
383
+ });
390
384
  return r;
391
385
  };
392
386
 
393
387
  $component.$cd = $cd;
394
388
  $component.apply = apply;
395
389
  $component.push = apply;
396
- apply();
397
390
  },
398
- b: noop
391
+ b: ($component) => {
392
+ safeCall(() => $digest($component.$cd));
393
+ }
399
394
  };
400
395
 
401
396
 
402
397
  const makeComponent = (init, $base) => {
403
- return ($element, $option={}) => {
398
+ return ($option={}) => {
404
399
  let prev = current_component;
405
400
  $context = $option.context || {};
406
401
  let $component = current_component = {
@@ -411,29 +406,29 @@ const makeComponent = (init, $base) => {
411
406
  _d: [],
412
407
  _m: []
413
408
  };
414
- $base.a($component);
409
+ $base?.a($component);
415
410
 
416
411
  try {
417
- $insertElementByOption($element, $option, init($option, $component.apply));
418
- $base.b($component);
412
+ $component.$dom = init($option, $component.apply);
413
+ $base?.b($component);
419
414
  } finally {
420
415
  current_component = prev;
421
416
  $context = null;
422
417
  }
423
418
 
424
- $tick(() => $component._d.push(...$component._m.map(safeCall)));
419
+ $component._d.push(...$component._m.map(safeCall));
425
420
  return $component;
426
421
  };
427
422
  };
428
423
 
429
424
 
430
- const callComponent = (cd, context, component, label, option, propFn, cmp, setter, classFn) => {
431
- option.$l = 1;
425
+ const callComponent = (context, component, option={}, propFn, cmp, setter, classFn) => {
432
426
  option.context = {...context};
433
- let $component, parentWatch, childWatch;
427
+ let $component, parentWatch, childWatch, cd;
434
428
 
435
429
  if(propFn) {
436
430
  if(cmp) {
431
+ cd = cd_new();
437
432
  parentWatch = $watch(cd, propFn, value => {
438
433
  option.props = value;
439
434
  if($component) {
@@ -447,30 +442,71 @@ const callComponent = (cd, context, component, label, option, propFn, cmp, sette
447
442
  }
448
443
 
449
444
  if(classFn) {
445
+ cd = cd || cd_new();
450
446
  fire($watch(cd, classFn, value => {
451
447
  option.$class = value;
452
448
  $component?.apply?.();
453
449
  }, {ro: true, value: {}, cmp: keyComparator}));
454
450
  }
455
451
 
456
- $component = safeCall(() => component(label, option));
457
- if($component) {
458
- cd_onDestroy(cd, $component.destroy);
452
+ let anchors = option.anchor;
453
+ if(anchors) {
454
+ for(let name in anchors) {
455
+ let a = anchors[name];
456
+ let fn = a.$;
457
+ if(fn) {
458
+ cd = cd || cd_new();
459
+ anchors[name] = el => {
460
+ let $cd = cd_new();
461
+ cd_attach(cd, $cd);
462
+ fn($cd, el);
463
+ return () => cd_destroy$1($cd);
464
+ };
465
+ }
466
+ }
467
+ }
459
468
 
460
- if(setter && $component.exportedProps) {
469
+ $component = safeCall(() => component(option));
470
+ if(setter && $component?.exportedProps) {
461
471
  childWatch = $watch($component.$cd, $component.exportedProps, value => {
462
- setter(value);
463
- cd.$$.apply();
472
+ setter(value);
473
+ cd_component(cd).apply();
464
474
  }, {ro: true, idle: true, value: parentWatch.value, cmp});
465
- }
466
475
  }
467
- return $component;
476
+ return {
477
+ $cd: cd,
478
+ $dom: $component.$dom,
479
+ destroy: $component.destroy,
480
+ $component
481
+ };
482
+ };
483
+
484
+
485
+ const attachDynComponent = (parentCD, label, exp, bind) => {
486
+ let active, $cd, $dom, destroy, finalLabel = getFinalLabel(label);
487
+ cd_onDestroy(parentCD, () => destroy?.());
488
+ $watch(parentCD, exp, (component) => {
489
+ destroy?.();
490
+ if($cd) cd_destroy$1($cd);
491
+ if(active) removeElementsBetween(label, finalLabel);
492
+
493
+ if(component) {
494
+ ({$cd, $dom, destroy} = bind(component));
495
+ cd_attach(parentCD, $cd);
496
+ insertAfter(label, $dom);
497
+ active = true;
498
+ } else {
499
+ destroy = null;
500
+ $cd = null;
501
+ active = false;
502
+ }
503
+ });
468
504
  };
469
505
 
470
506
 
471
507
  const autoSubscribe = (...list) => {
472
508
  list.forEach(i => {
473
- if(isFunction(i.subscribe)) {
509
+ if(i.subscribe) {
474
510
  let unsub = i.subscribe(current_component.apply);
475
511
  if(isFunction(unsub)) cd_onDestroy(current_component, unsub);
476
512
  }
@@ -491,16 +527,21 @@ const addClass = (el, className) => el.classList.add(className);
491
527
 
492
528
 
493
529
  const bindClass = (cd, element, fn, className) => {
494
- $watchReadOnly(cd, fn, value => {
530
+ $watch(cd, fn, value => {
495
531
  if(value) addClass(element, className);
496
532
  else element.classList.remove(className);
497
- });
533
+ }, {ro: true, value: false});
498
534
  };
499
535
 
500
536
 
501
537
  const setClassToElement = (element, value) => bindAttributeBase(element, 'class', value);
502
538
 
503
539
 
540
+ const bindClassExp = (cd, element, fn) => {
541
+ $watch(cd, fn, value => setClassToElement(element, value), {ro: true, value: ''});
542
+ };
543
+
544
+
504
545
  const bindText = (cd, element, fn) => {
505
546
  $watchReadOnly(cd, () => '' + fn(), value => {
506
547
  element.textContent = value;
@@ -522,10 +563,7 @@ const bindAttributeBase = (element, name, value) => {
522
563
 
523
564
 
524
565
  const bindAttribute = (cd, element, name, fn) => {
525
- $watchReadOnly(cd, () => {
526
- let v = fn();
527
- return v == null ? v : '' + v;
528
- }, value => bindAttributeBase(element, name, value));
566
+ $watchReadOnly(cd, () => '' + fn(), value => bindAttributeBase(element, name, value));
529
567
  };
530
568
 
531
569
 
@@ -536,7 +574,7 @@ const bindAction = (cd, element, action, fn, subscribe) => {
536
574
  value = fn();
537
575
  handler = action.apply(null, [element].concat(value));
538
576
  } else handler = action(element);
539
- if(handler?.destroy) cd_onDestroy(cd, handler.destroy);
577
+ cd_onDestroy(cd, handler?.destroy);
540
578
  subscribe?.(cd, fn, handler, value);
541
579
  });
542
580
  };
@@ -565,8 +603,8 @@ const makeClassResolver = ($option, classMap, metaClass, mainName) => {
565
603
  if(!$option.$class) $option.$class = {};
566
604
  if(!mainName && metaClass.main) mainName = 'main';
567
605
  return (line, defaults) => {
568
- let result = [];
569
- if(defaults) result.push(defaults);
606
+ let result = {};
607
+ if(defaults) result[defaults] = 1;
570
608
  line.trim().split(/\s+/).forEach(name => {
571
609
  let meta;
572
610
  if(name[0] == '$') {
@@ -577,19 +615,21 @@ const makeClassResolver = ($option, classMap, metaClass, mainName) => {
577
615
  if(h) {
578
616
  let className = ($option.$class[name === mainName ? '$$main' : name] || '').trim();
579
617
  if(className) {
580
- result.push(className);
618
+ result[className] = 1;
581
619
  } else if(h !== true) {
582
- result.push(name, h);
620
+ result[name] = 1;
621
+ result[h] = 1;
583
622
  }
584
623
  }
585
624
  let h2 = classMap[name];
586
625
  if(h2) {
587
- result.push(name, h2);
626
+ result[name] = 1;
627
+ result[h2] = 1;
588
628
  } else if(!h) {
589
- result.push(name);
629
+ result[name] = 1;
590
630
  }
591
631
  });
592
- return result.join(' ');
632
+ return Object.keys(result).join(' ');
593
633
  }
594
634
  };
595
635
 
@@ -602,60 +642,11 @@ const makeExternalProperty = ($component, name, getter, setter) => {
602
642
  };
603
643
 
604
644
 
605
- const attachSlotBase = ($context, $cd, slotName, label, props, placeholder) => {
606
- let $slot = $cd.$$.$option.slots?.[slotName];
607
- if($slot) $slot($cd, label, $context, props);
608
- else placeholder?.();
609
- };
645
+ const eachDefaultKey = (item, index, array) => typeof array[0] === 'object' ? item : index;
610
646
 
611
647
 
612
- const attachSlot = ($context, $cd, slotName, label, props, placeholder, cmp) => {
613
- let $slot = $cd.$$.$option.slots?.[slotName];
614
- if($slot) {
615
- let resultProps = {}, push;
616
- if(props) {
617
- let setter = (k) => {
618
- return v => {
619
- resultProps[k] = v;
620
- push?.();
621
- }
622
- };
623
- for(let k in props) {
624
- let v = props[k];
625
- if(isFunction(v)) {
626
- fire($watch($cd, v, setter(k), {ro: true, cmp}));
627
- } else resultProps[k] = v;
628
- }
629
- }
630
- push = $slot($cd, label, $context, resultProps);
631
- } else placeholder?.();
632
- };
633
-
634
-
635
- const makeSlot = (parentCD, fn) => {
636
- return (callerCD, label, $context, props) => {
637
- let $cd = parentCD.new();
638
- cd_onDestroy(callerCD, () => $cd.destroy());
639
- let r = fn($cd, $context, callerCD, props || {});
640
- insertAfter(label, r.el || r);
641
- $cd.$$.apply?.();
642
- return r.push;
643
- };
644
- };
645
-
646
-
647
- const makeSlotStatic = (fn) => {
648
- return (callerCD, label) => {
649
- insertAfter(label, fn());
650
- }
651
- };
652
-
653
-
654
- const eachDefaultKey = (item, index, array) => isObject(array[0]) ? item : index;
655
-
656
-
657
- const attachAnchor = ($option, $cd, name, el) => {
658
- let fn = $option.anchor?.[name];
648
+ const attachAnchor = ($option, $cd, el, name) => {
649
+ let fn = $option.anchor?.[name || 'default'];
659
650
  if(fn) cd_onDestroy($cd, fn(el));
660
651
  };
661
652
 
@@ -690,35 +681,35 @@ const spreadAttributes = (cd, el, fn) => {
690
681
  };
691
682
 
692
683
 
693
- const attchExportedFragment = ($parentCD, $childCD, name, label, props, events, template, innerFn) => {
694
- let fn = $childCD.$$.exported[name];
695
- if(fn) {
696
- let slot;
697
- if(template) {
698
- slot = (childCD, label) => {
699
- const $parentElement = $$htmlToFragment(template);
700
- if(innerFn) {
701
- let $cd = $parentCD.new();
702
- cd_onDestroy(childCD, () => $cd.destroy());
703
- innerFn($cd, $parentElement);
704
- $cd.$$.apply?.();
705
- }
706
- insertAfter(label, $parentElement);
707
- };
708
- }
709
-
710
- if(isFunction(props)) props = props($parentCD, $childCD);
711
- fn($parentCD, $childCD, label, props, events, slot);
684
+ const callExportedFragment = (childComponent, name, slot, events, props, cmp) => {
685
+ let $cd, r;
686
+ if(cmp) {
687
+ $cd = cd_new();
688
+ let fn = props, result;
689
+ props = () => result;
690
+ let w = $watch($cd, fn, (props) => {
691
+ result = props;
692
+ r?.push();
693
+ }, {value: {}, cmp});
694
+ fire(w);
712
695
  }
696
+ let fn = childComponent.exported[name];
697
+ r = fn(props, events, slot);
698
+ r.$cd = $cd;
699
+ return r;
713
700
  };
714
701
 
715
702
 
716
- const exportFragment = ($component, name, fn) => {
717
- $component.exported[name] = ($parentCD, $childCD, label, props, events, slot) => {
718
- let $cd = $childCD.new();
719
- cd_onDestroy($parentCD, () => $cd.destroy());
720
- fn($cd, label, props, events, slot);
721
- $component.apply();
703
+ const exportFragment = (childCD, name, fn) => {
704
+ cd_component(childCD).exported[name] = (props, events, slot) => {
705
+ let {$cd, $dom} = fn(props, events || {}, slot);
706
+ cd_attach(childCD, $cd);
707
+ let apply = cd_component(childCD).apply;
708
+ return {
709
+ $dom,
710
+ destroy: () => $cd.destroy(),
711
+ push: () => apply?.()
712
+ };
722
713
  };
723
714
  };
724
715
 
@@ -729,18 +720,6 @@ const prefixPush = ($cd, fn) => {
729
720
  };
730
721
 
731
722
 
732
- const observeProps = (cmp, fn) => {
733
- return (cd, target) => {
734
- let result;
735
- fire($watch(cd, fn, value => {
736
- result = value;
737
- target.$$.apply();
738
- }, {ro: true, value: {}, cmp}));
739
- return () => result;
740
- }
741
- };
742
-
743
-
744
723
  const unwrapProps = (cd, props, fn) => {
745
724
  if(props) {
746
725
  if(isFunction(props)) prefixPush(cd, () => fn(props()));
@@ -748,112 +727,241 @@ const unwrapProps = (cd, props, fn) => {
748
727
  }
749
728
  };
750
729
 
730
+
731
+ const makeBlock = (fr, fn) => {
732
+ return (v) => {
733
+ let $dom = fr.cloneNode(true), $cd = cd_new();
734
+ fn($cd, $dom, v);
735
+ return {$cd, $dom};
736
+ }
737
+ };
738
+
739
+
740
+ const makeBlockBound = (parentCD, fr, fn) => {
741
+ return () => {
742
+ let $dom = fr.cloneNode(true), $cd = cd_new();
743
+ fn($cd, $dom);
744
+ cd_attach(parentCD, $cd);
745
+ return {
746
+ $dom,
747
+ destroy: () => cd_destroy$1($cd)
748
+ };
749
+ }
750
+ };
751
+
752
+
753
+ const makeStaticBlock = (fr, fn) => {
754
+ return () => {
755
+ let $dom = fr.cloneNode(true);
756
+ fn?.($dom);
757
+ return {$dom};
758
+ }
759
+ };
760
+
761
+ const attachBlock = (cdo, label, block) => {
762
+ if(!block) return;
763
+ cd_onDestroy(cdo, block.destroy);
764
+ cd_attach(cdo, block.$cd);
765
+ insertAfter(label, block.$dom);
766
+ };
767
+
768
+
769
+ const mergeEvents = (...callbacks) => {
770
+ callbacks = callbacks.filter(i => i);
771
+ return (e) => callbacks.forEach(cb => cb(e));
772
+ };
773
+
774
+
775
+ const makeRootEvent = (root) => {
776
+ let events = {}, nodes = [];
777
+
778
+ if(root.nodeType == 11) {
779
+ let n = root.firstElementChild;
780
+ while(n) {
781
+ nodes.push(n);
782
+ n = n.nextElementSibling;
783
+ }
784
+ } else nodes = [root];
785
+
786
+ $onDestroy(() => {
787
+ for(let eventName in events) {
788
+ nodes.forEach(n => n.removeEventListener(eventName, events[eventName]));
789
+ }
790
+ });
791
+ return (target, eventName, callback) => {
792
+ const key = `_$$${eventName}`;
793
+ if(!events[eventName]) {
794
+ let handler = events[eventName] = ($event) => {
795
+ let top = $event.currentTarget;
796
+ let el = $event.target;
797
+ while(el) {
798
+ el[key]?.($event);
799
+ if(el == top || $event.cancelBubble) break;
800
+ el = el.parentNode;
801
+ }
802
+ };
803
+ nodes.forEach(n => n.addEventListener(eventName, handler));
804
+ } target[key] = callback;
805
+ }
806
+ };
807
+
751
808
  function $$htmlBlock($cd, tag, fn) {
752
809
  let lastElement;
753
810
  let create = (html) => {
754
811
  let fr;
755
812
  if(tag.parentElement instanceof SVGElement) fr = svgToFragment(html);
756
- else fr = $$htmlToFragment(html);
813
+ else fr = $$htmlToFragment(html, 3);
757
814
  lastElement = fr.lastChild;
758
815
  insertAfter(tag, fr);
759
816
  };
760
817
  let destroy = () => {
761
818
  if(!lastElement) return;
762
- let next, el = tag.nextSibling;
763
- while(el) {
764
- next = el.nextSibling;
765
- el.remove();
766
- if(el == lastElement) break;
767
- el = next;
768
- }
769
-
819
+ $$removeElements(tag.nextSibling, lastElement);
770
820
  lastElement = null;
771
821
  };
772
- $watch($cd, fn, (html) => {
773
- destroy();
774
- if(html) create(html);
775
- }, {ro: true});
822
+ if($cd) {
823
+ $watch($cd, fn, (html) => {
824
+ destroy();
825
+ if(html) create(html);
826
+ }, {ro: true});
827
+ } else create(fn());
776
828
  }
777
829
 
778
- function $$ifBlock($cd, $parentElement, fn, tpl, build, tplElse, buildElse) {
779
- let childCD;
780
- let first, last;
781
-
782
- function create(fr, builder) {
783
- childCD = $cd.new();
784
- let tpl = fr.cloneNode(true);
785
- builder(childCD, tpl);
786
- first = tpl[firstChild];
787
- last = tpl.lastChild;
788
- insertAfter($parentElement, tpl);
789
- }
790
- function destroy() {
791
- if(!childCD) return;
792
- childCD.destroy();
793
- childCD = null;
794
- $$removeElements(first, last);
830
+ function ifBlock(parentCD, label, fn, build, buildElse) {
831
+ let first, last, $cd, destroy;
832
+ cd_onDestroy(parentCD, () => destroy?.());
833
+
834
+ function createBlock(builder) {
835
+ let $dom;
836
+ ({$cd, destroy, $dom} = builder());
837
+ cd_attach(parentCD, $cd);
838
+ if($dom.nodeType == 11) {
839
+ first = $dom[firstChild];
840
+ last = $dom.lastChild;
841
+ } else first = last = $dom;
842
+ insertAfter(label, $dom);
843
+ }
844
+ function destroyBlock() {
845
+ if(!first) return;
846
+ destroyResults = [];
847
+ destroy?.();
848
+ destroy = null;
849
+ if($cd) {
850
+ cd_destroy$1($cd);
851
+ $cd = null;
852
+ }
853
+ if(destroyResults.length) {
854
+ let f = first, l = last;
855
+ Promise.allSettled(destroyResults).then(() => {
856
+ $$removeElements(f, l);
857
+ });
858
+ } else $$removeElements(first, last);
795
859
  first = last = null;
860
+ destroyResults = null;
796
861
  }
797
- $watch($cd, fn, (value) => {
862
+ $watch(parentCD, fn, (value) => {
798
863
  if(value) {
799
- destroy();
800
- create(tpl, build);
864
+ destroyBlock();
865
+ createBlock(build);
801
866
  } else {
802
- destroy();
803
- if(buildElse) create(tplElse, buildElse);
867
+ destroyBlock();
868
+ if(buildElse) createBlock(buildElse);
804
869
  }
805
870
  });
806
871
  }
807
872
 
808
- function $$awaitBlock($cd, label, relation, fn, $$apply, build_main, tpl_main, build_then, tpl_then, build_catch, tpl_catch) {
809
- let promise, childCD;
810
- let first, last, status = 0;
873
+ function ifBlockReadOnly(component, label, fn, build, buildElse) {
874
+ function createBlock(builder) {
875
+ let {destroy, $dom} = builder();
876
+ cd_onDestroy(component, destroy);
877
+ insertAfter(label, $dom);
878
+ }
879
+ if(fn()) createBlock(build);
880
+ else if(buildElse) createBlock(buildElse);
881
+ }
811
882
 
812
- function remove() {
813
- if(!childCD) return;
814
- childCD.destroy();
815
- childCD = null;
883
+ function $$awaitBlock(parentCD, label, relation, fn, build_main, build_then, build_catch) {
884
+ let first, last, $cd, destroy, promise, status = 0;
885
+ cd_onDestroy(parentCD, () => destroy?.());
886
+
887
+ function destroyBlock() {
888
+ if(!first) return;
889
+ destroy?.();
890
+ destroy = null;
891
+ if($cd) {
892
+ cd_destroy($cd);
893
+ $cd = null;
894
+ }
816
895
  $$removeElements(first, last);
817
896
  first = last = null;
818
897
  }
819
- function render(build, tpl, value) {
820
- if(childCD) remove();
821
- if(!tpl) return;
822
- childCD = $cd.new();
823
- let fr = tpl.cloneNode(true);
824
- build(childCD, fr, value);
825
- $$apply();
826
- first = fr[firstChild];
827
- last = fr.lastChild;
828
- insertAfter(label, fr);
829
- }
830
- $watch($cd, relation, () => {
898
+ function render(builder, value) {
899
+ destroyBlock();
900
+
901
+ let $dom;
902
+ ({$cd, destroy, $dom} = builder(value));
903
+ cd_attach(parentCD, $cd);
904
+ if($dom.nodeType == 11) {
905
+ first = $dom[firstChild];
906
+ last = $dom.lastChild;
907
+ } else first = last = $dom;
908
+ insertAfter(label, $dom);
909
+ cd_component(parentCD).apply();
910
+ }
911
+ $watch(parentCD, relation, () => {
831
912
  let p = fn();
832
- if(status !== 1) render(build_main, tpl_main);
913
+ if(status !== 1) render(build_main);
833
914
  status = 1;
834
915
  if(p && p instanceof Promise) {
835
916
  promise = p;
836
917
  promise.then(value => {
837
918
  status = 2;
838
919
  if(promise !== p) return;
839
- render(build_then, tpl_then, value);
920
+ render(build_then, value);
840
921
  }).catch(value => {
841
922
  status = 3;
842
923
  if(promise !== p) return;
843
- render(build_catch, tpl_catch, value);
924
+ render(build_catch, value);
844
925
  });
845
926
  }
846
- }, {ro: true, cmp: $$deepComparator(1)});
927
+ }, {ro: true, value: [], cmp: keyComparator});
847
928
  }
848
929
 
849
- function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind) {
850
- let $cd = $parentCD.new();
930
+ const makeEachBlock = (fr, fn) => {
931
+ return (item, index) => {
932
+ let $dom = fr.cloneNode(true), $cd = cd_new();
933
+ let rebind = fn($cd, $dom, item, index);
934
+ return {$cd, $dom, rebind};
935
+ }
936
+ };
937
+
938
+
939
+ const makeStaticEachBlock = (fr, fn) => {
940
+ return (item, index) => {
941
+ let $dom = fr.cloneNode(true);
942
+ let rebind = fn($dom, item, index);
943
+ return {$dom, rebind};
944
+ }
945
+ };
946
+
947
+
948
+ const makeEachSingleBlock = (fn) => {
949
+ return (item, index) => {
950
+ let [rebind, component] = fn(item, index);
951
+ let {$cd, destroy, $dom} = component;
952
+ return {$cd, destroy, $dom, rebind};
953
+ }
954
+ };
955
+
956
+
957
+ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, bind) {
958
+ let eachCD = cd_new();
959
+ cd_attach($parentCD, eachCD);
851
960
 
852
961
  let mapping = new Map();
853
- let lastNode;
854
- let tplLength = itemTemplate[childNodes].length;
962
+ let lastNode, vi = 0;
855
963
 
856
- $watch($cd, fn, (array) => {
964
+ $watch(eachCD, fn, (array) => {
857
965
  if(!array) array = [];
858
966
  if(typeof(array) == 'number') array = [...Array(array)].map((_,i) => i + 1);
859
967
  else if(!isArray(array)) array = [];
@@ -870,47 +978,76 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
870
978
 
871
979
  if(mapping.size) {
872
980
  let ctx, count = 0;
981
+ vi++;
873
982
  for(let i=0;i<array.length;i++) {
874
983
  ctx = mapping.get(getKey(array[i], i, array));
875
984
  if(ctx) {
876
- ctx.a = true;
985
+ ctx.a = vi;
877
986
  count++;
878
987
  }
879
988
  }
880
989
 
881
990
  if(!count && lastNode) {
882
- if(onlyChild) label.textContent = '';
883
- else $$removeElements(label.nextSibling, lastNode);
884
- $cd.children.forEach(cd => cd.destroy(false));
885
- $cd.children.length = 0;
991
+ destroyResults = [];
992
+ eachCD.children.forEach(cd => cd_destroy$1(cd, false));
993
+ eachCD.children.length = 0;
994
+ mapping.forEach(ctx => ctx.destroy?.());
886
995
  mapping.clear();
887
- } else {
888
- $cd.children = [];
996
+
997
+ if(destroyResults.length) {
998
+ let removedNodes = [];
999
+ iterNodes(onlyChild ? label.firstChild : label.nextSibling, lastNode, n => {
1000
+ n.$$removing = true;
1001
+ removedNodes.push(n);
1002
+ });
1003
+ Promise.allSettled(destroyResults).then(() => removedNodes.forEach(n => n.remove()));
1004
+ } else {
1005
+ if(onlyChild) label.textContent = '';
1006
+ else $$removeElements(label.nextSibling, lastNode);
1007
+ }
1008
+
1009
+ destroyResults = null;
1010
+ } else if(count < mapping.size) {
1011
+ eachCD.children = [];
1012
+ destroyResults = [];
1013
+ let removedNodes = [];
889
1014
  mapping.forEach(ctx => {
890
- if(ctx.a) {
891
- ctx.a = false;
892
- $cd.children.push(ctx.cd);
1015
+ if(ctx.a == vi) {
1016
+ ctx.$cd && eachCD.children.push(ctx.$cd);
893
1017
  return;
894
1018
  }
895
- $$removeElements(ctx.first, ctx.last);
896
- ctx.cd.destroy(false);
1019
+ ctx.$cd && cd_destroy$1(ctx.$cd, false);
1020
+ ctx.destroy?.();
1021
+ iterNodes(ctx.first, ctx.last, n => {
1022
+ n.$$removing = true;
1023
+ removedNodes.push(n);
1024
+ });
897
1025
  });
1026
+
1027
+ if(destroyResults.length) {
1028
+ Promise.allSettled(destroyResults).then(() => removedNodes.forEach(n => n.remove()));
1029
+ } else {
1030
+ removedNodes.forEach(n => n.remove());
1031
+ }
1032
+ destroyResults = null;
898
1033
  }
899
1034
  }
900
1035
 
901
- let i, item, next_ctx, ctx, nextEl;
1036
+ let i, item, next_ctx, ctx, nextEl, key;
902
1037
  for(i=0;i<array.length;i++) {
903
1038
  item = array[i];
1039
+ key = getKey(item, i, array);
904
1040
  if(next_ctx) {
905
1041
  ctx = next_ctx;
906
1042
  next_ctx = null;
907
- } else ctx = mapping.get(getKey(item, i, array));
1043
+ } else ctx = mapping.get(key);
908
1044
  if(ctx) {
909
1045
  nextEl = i == 0 && onlyChild ? parentNode[firstChild] : prevNode.nextSibling;
1046
+ while(nextEl && nextEl.$$removing) nextEl = nextEl.nextSibling;
910
1047
  if(nextEl != ctx.first) {
911
1048
  let insert = true;
912
1049
 
913
- if(tplLength == 1 && (i + 1 < array.length) && prevNode?.nextSibling) {
1050
+ if(ctx.first == ctx.last && (i + 1 < array.length) && prevNode?.nextSibling) {
914
1051
  next_ctx = mapping.get(getKey(array[i + 1], i + 1, array));
915
1052
  if(next_ctx && prevNode.nextSibling.nextSibling === next_ctx.first) {
916
1053
  parentNode.replaceChild(ctx.first, prevNode.nextSibling);
@@ -929,22 +1066,58 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
929
1066
  }
930
1067
  }
931
1068
  }
932
- ctx.rebind(i, item);
1069
+ ctx.rebind?.(i, item);
933
1070
  } else {
934
- let tpl = itemTemplate.cloneNode(true);
935
- let childCD = $cd.new();
936
- ctx = {cd: childCD};
937
- bind(ctx, tpl, item, i);
938
- ctx.first = tpl[firstChild];
939
- ctx.last = tpl.lastChild;
940
- parentNode.insertBefore(tpl, prevNode?.nextSibling);
1071
+ let $dom;
1072
+ ({$dom, ...ctx} = bind(item, i));
1073
+ cd_attach(eachCD, ctx.$cd);
1074
+ if($dom.nodeType == 11) {
1075
+ ctx.first = $dom[firstChild];
1076
+ ctx.last = $dom.lastChild;
1077
+ } else ctx.first = ctx.last = $dom;
1078
+ parentNode.insertBefore($dom, prevNode?.nextSibling);
941
1079
  }
942
1080
  prevNode = ctx.last;
943
- newMapping.set(getKey(item, i, array), ctx);
1081
+ newMapping.set(key, ctx);
944
1082
  } lastNode = prevNode;
945
1083
  mapping.clear();
946
1084
  mapping = newMapping;
947
1085
  }, {ro: true, cmp: $$compareArray});
948
1086
  }
949
1087
 
950
- export { $$addEventForComponent, $$awaitBlock, $$cloneDeep, $$compareArray, $$compareDeep, $$deepComparator, $$eachBlock, $$htmlBlock, $$htmlToFragment, $$htmlToFragmentClean, $$ifBlock, $$removeElements, $$removeItem, $ChangeDetector, $base, $context, $digest, $insertElementByOption, $makeEmitter, $onDestroy, $onMount, $readOnlyBase, $tick, $watch, $watchReadOnly, __app_onerror, __bindActionSubscribe, addClass, addEvent, addStyles, attachAnchor, attachSlot, attachSlotBase, attchExportedFragment, autoSubscribe, bindAction, bindAttribute, bindAttributeBase, bindClass, bindInput, bindStyle, bindText, callComponent, cd_onDestroy, childNodes, cloneDeep, configure, createTextNode, current_component, eachDefaultKey, exportFragment, fire, firstChild, getFinalLabel, insertAfter, isArray, isFunction, keyComparator, makeClassResolver, makeComponent, makeExternalProperty, makeSlot, makeSlotStatic, noop, observeProps, prefixPush, removeElementsBetween, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };
1088
+ const invokeSlotBase = ($component, slotName, $context, props, placeholder) => {
1089
+ let $slot = $component.$option.slots?.[slotName || 'default'];
1090
+ return $slot ? $slot($component, $context, props) : placeholder?.();
1091
+ };
1092
+
1093
+
1094
+ const invokeSlot = ($component, slotName, $context, propsFn, placeholder, cmp) => {
1095
+ let $slot = $component.$option.slots?.[slotName || 'default'];
1096
+
1097
+ if($slot) {
1098
+ let push, w, result;
1099
+ w = cd_watchObject(propsFn, value => push?.(value), {ro: true, value: {}, cmp});
1100
+ fire(w);
1101
+ ({push, ...result} = $slot($component, $context, w.value));
1102
+ if(push) {
1103
+ result.$cd = cd_new();
1104
+ result.$cd.watchers.push(w);
1105
+ }
1106
+ return result;
1107
+ } else return placeholder?.();
1108
+ };
1109
+
1110
+
1111
+ const makeSlot = (parentCD, fr, fn) => {
1112
+ return (callerComponent, $context, props) => {
1113
+ let $dom = fr.cloneNode(true), $cd = cd_new();
1114
+ cd_attach(parentCD, $cd);
1115
+ return {
1116
+ $dom,
1117
+ destroy: () => cd_destroy$1($cd),
1118
+ push: fn($cd, $dom, $context, callerComponent, props)
1119
+ };
1120
+ };
1121
+ };
1122
+
1123
+ export { $$addEventForComponent, $$awaitBlock, $$cloneDeep, $$compareArray, $$compareDeep, $$deepComparator, $$eachBlock, $$htmlBlock, $$htmlToFragment, $$htmlToFragmentClean, $$removeElements, $$removeItem, $base, $context, $digest, $makeEmitter, $onDestroy, $onMount, $tick, $watch, $watchReadOnly, __app_onerror, __bindActionSubscribe, addClass, addEvent, addStyles, attachAnchor, attachBlock, attachDynComponent, autoSubscribe, bindAction, bindAttribute, bindAttributeBase, bindClass, bindClassExp, bindInput, bindStyle, bindText, callComponent, callExportedFragment, cd_attach, cd_component, cd_destroy$1 as cd_destroy, cd_new, cd_onDestroy, cd_watchObject, childNodes, cloneDeep, configure, createTextNode, current_component, destroyResults, eachDefaultKey, exportFragment, fire, firstChild, getFinalLabel, ifBlock, ifBlockReadOnly, insertAfter, invokeSlot, invokeSlotBase, isArray, isFunction, iterNodes, keyComparator, makeBlock, makeBlockBound, makeClassResolver, makeComponent, makeEachBlock, makeEachSingleBlock, makeExternalProperty, makeRootEvent, makeSlot, makeStaticBlock, makeStaticEachBlock, mergeEvents, noop, prefixPush, removeElementsBetween, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };