malinajs 0.6.49 → 0.7.0-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.
Files changed (4) hide show
  1. package/compile.js +1304 -1049
  2. package/malina.js +1305 -1050
  3. package/package.json +1 -1
  4. package/runtime.js +433 -301
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,32 @@ $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;
78
+ };
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
+ }
69
87
  };
70
88
 
89
+ const cd_destroy$1 = (cd, option) => {
90
+ if(option !== false && cd.parent) $$removeItem(cd.parent.children, cd);
91
+ cd.watchers.length = 0;
92
+ cd.prefix.length = 0;
93
+ cd._d.map(safeCall);
94
+ cd._d.length = 0;
95
+ cd.children.map(cd => cd.destroy(false));
96
+ cd.children.length = 0;
97
+ };
71
98
 
72
99
  const isArray = (a) => Array.isArray(a);
73
100
 
@@ -95,8 +122,8 @@ function $$compareArray(w, value) {
95
122
  const compareDeep = (a, b, lvl) => {
96
123
  if(lvl < 0 || !a || !b) return a !== b;
97
124
  if(a === b) return false;
98
- let o0 = isObject(a);
99
- let o1 = isObject(b);
125
+ let o0 = typeof(a) == 'object';
126
+ let o1 = typeof(b) == 'object';
100
127
  if(!(o0 && o1)) return a !== b;
101
128
 
102
129
  let a0 = isArray(a);
@@ -126,7 +153,7 @@ const compareDeep = (a, b, lvl) => {
126
153
  function cloneDeep(d, lvl) {
127
154
  if(lvl < 0 || !d) return d;
128
155
 
129
- if(isObject(d)) {
156
+ if(typeof(d) == 'object') {
130
157
  if(d instanceof Date) return d;
131
158
  if(d instanceof Element) return d;
132
159
  if(isArray(d)) return d.map(i => cloneDeep(i, lvl-1));
@@ -205,8 +232,6 @@ function $digest($cd) {
205
232
  let templatecache = {};
206
233
  let templatecacheSvg = {};
207
234
 
208
- let $$uniqIndex = 1;
209
-
210
235
  const childNodes = 'childNodes';
211
236
  const firstChild = 'firstChild';
212
237
 
@@ -216,37 +241,41 @@ const insertAfter = (label, node) => {
216
241
  label.parentNode.insertBefore(node, label.nextSibling);
217
242
  };
218
243
 
219
- const createTextNode = (text) => {
220
- let f = document.createDocumentFragment();
221
- f.append(text);
222
- return f;
223
- };
244
+ const createTextNode = (text) => document.createTextNode(text);
224
245
 
225
- const $$htmlToFragment = (html) => {
226
- if(templatecache[html]) return templatecache[html].cloneNode(true);
246
+ const $$htmlToFragment = (html, option) => {
247
+ let result = templatecache[html];
248
+ if(!result) {
249
+ let t = document.createElement('template');
250
+ t.innerHTML = html.replace(/<>/g, '<!---->');
251
+ result = t.content;
252
+ if(!(option & 2) && result.firstChild == result.lastChild) result = result.firstChild;
253
+ templatecache[html] = result;
254
+ }
227
255
 
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;
256
+ return option & 1 ? result.cloneNode(true) : result;
233
257
  };
234
258
 
235
- const $$htmlToFragmentClean = (html) => {
236
- if(templatecache[html]) return templatecache[html].cloneNode(true);
259
+ const $$htmlToFragmentClean = (html, option) => {
260
+ let result = templatecache[html];
261
+ if(!result) {
262
+ let t = document.createElement('template');
263
+ t.innerHTML = html.replace(/<>/g, '<!---->');
264
+ result = t.content;
265
+
266
+ let it = document.createNodeIterator(result, 128);
267
+ let n;
268
+ while(n = it.nextNode()) {
269
+ if(!n.nodeValue) n.parentNode.replaceChild(document.createTextNode(''), n);
270
+ }
271
+ if(!(option & 2) && result.firstChild == result.lastChild) result = result.firstChild;
272
+ templatecache[html] = result;
273
+ }
237
274
 
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;
275
+ return option & 1 ? result.cloneNode(true) : result;
248
276
  };
249
277
 
278
+
250
279
  function svgToFragment(content) {
251
280
  if(templatecacheSvg[content]) return templatecacheSvg[content].cloneNode(true);
252
281
  let t = document.createElement('template');
@@ -285,22 +314,11 @@ const getFinalLabel = n => {
285
314
  };
286
315
 
287
316
 
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);
317
+ const resolvedPromise = Promise.resolve();
318
+
319
+ function $tick(fn) {
320
+ fn && resolvedPromise.then(fn);
321
+ return resolvedPromise;
304
322
  }
305
323
 
306
324
  function $makeEmitter(option) {
@@ -335,72 +353,38 @@ const $onDestroy = fn => current_component._d.push(fn);
335
353
  const $onMount = fn => current_component._m.push(fn);
336
354
 
337
355
 
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
356
  const $base = {
373
357
  a: ($component) => {
374
- let $cd = new $ChangeDetector();
375
- $cd.$$ = $component;
358
+ let $cd = cd_new();
359
+ $cd.component = $component;
376
360
  $onDestroy(() => $cd.destroy());
377
361
 
378
- let id = `a${$$uniqIndex++}`;
379
- let process;
362
+ let planned;
380
363
  let apply = r => {
381
- if (process) return r;
364
+ if(planned) return r;
365
+ planned = true;
382
366
  $tick(() => {
383
367
  try {
384
- process = true;
385
368
  $digest($cd);
386
369
  } finally {
387
- process = false;
370
+ planned = false;
388
371
  }
389
- }, id);
372
+ });
390
373
  return r;
391
374
  };
392
375
 
393
376
  $component.$cd = $cd;
394
377
  $component.apply = apply;
395
378
  $component.push = apply;
396
- apply();
397
379
  },
398
- b: noop
380
+ b: ($component) => {
381
+ safeCall(() => $digest($component.$cd));
382
+ }
399
383
  };
400
384
 
401
385
 
402
386
  const makeComponent = (init, $base) => {
403
- return ($element, $option={}) => {
387
+ return ($option={}) => {
404
388
  let prev = current_component;
405
389
  $context = $option.context || {};
406
390
  let $component = current_component = {
@@ -411,29 +395,29 @@ const makeComponent = (init, $base) => {
411
395
  _d: [],
412
396
  _m: []
413
397
  };
414
- $base.a($component);
398
+ $base?.a($component);
415
399
 
416
400
  try {
417
- $insertElementByOption($element, $option, init($option, $component.apply));
418
- $base.b($component);
401
+ $component.$dom = init($option, $component.apply);
402
+ $base?.b($component);
419
403
  } finally {
420
404
  current_component = prev;
421
405
  $context = null;
422
406
  }
423
407
 
424
- $tick(() => $component._d.push(...$component._m.map(safeCall)));
408
+ $component._d.push(...$component._m.map(safeCall));
425
409
  return $component;
426
410
  };
427
411
  };
428
412
 
429
413
 
430
- const callComponent = (cd, context, component, label, option, propFn, cmp, setter, classFn) => {
431
- option.$l = 1;
414
+ const callComponent = (context, component, option={}, propFn, cmp, setter, classFn) => {
432
415
  option.context = {...context};
433
- let $component, parentWatch, childWatch;
416
+ let $component, parentWatch, childWatch, cd;
434
417
 
435
418
  if(propFn) {
436
419
  if(cmp) {
420
+ cd = cd_new();
437
421
  parentWatch = $watch(cd, propFn, value => {
438
422
  option.props = value;
439
423
  if($component) {
@@ -447,30 +431,71 @@ const callComponent = (cd, context, component, label, option, propFn, cmp, sette
447
431
  }
448
432
 
449
433
  if(classFn) {
434
+ cd = cd || cd_new();
450
435
  fire($watch(cd, classFn, value => {
451
436
  option.$class = value;
452
437
  $component?.apply?.();
453
438
  }, {ro: true, value: {}, cmp: keyComparator}));
454
439
  }
455
440
 
456
- $component = safeCall(() => component(label, option));
457
- if($component) {
458
- cd_onDestroy(cd, $component.destroy);
441
+ let anchors = option.anchor;
442
+ if(anchors) {
443
+ for(let name in anchors) {
444
+ let a = anchors[name];
445
+ let fn = a.$;
446
+ if(fn) {
447
+ cd = cd || cd_new();
448
+ anchors[name] = el => {
449
+ let $cd = cd_new();
450
+ cd_attach(cd, $cd);
451
+ fn($cd, el);
452
+ return () => cd_destroy$1($cd);
453
+ };
454
+ }
455
+ }
456
+ }
459
457
 
460
- if(setter && $component.exportedProps) {
458
+ $component = safeCall(() => component(option));
459
+ if(setter && $component?.exportedProps) {
461
460
  childWatch = $watch($component.$cd, $component.exportedProps, value => {
462
- setter(value);
463
- cd.$$.apply();
461
+ setter(value);
462
+ cd_component(cd).apply();
464
463
  }, {ro: true, idle: true, value: parentWatch.value, cmp});
465
- }
466
464
  }
467
- return $component;
465
+ return {
466
+ $cd: cd,
467
+ $dom: $component.$dom,
468
+ destroy: $component.destroy,
469
+ $component
470
+ };
471
+ };
472
+
473
+
474
+ const attachDynComponent = (parentCD, label, exp, bind) => {
475
+ let active, $cd, $dom, destroy, finalLabel = getFinalLabel(label);
476
+ cd_onDestroy(parentCD, () => destroy?.());
477
+ $watch(parentCD, exp, (component) => {
478
+ destroy?.();
479
+ if($cd) cd_destroy$1($cd);
480
+ if(active) removeElementsBetween(label, finalLabel);
481
+
482
+ if(component) {
483
+ ({$cd, $dom, destroy} = bind(component));
484
+ cd_attach(parentCD, $cd);
485
+ insertAfter(label, $dom);
486
+ active = true;
487
+ } else {
488
+ destroy = null;
489
+ $cd = null;
490
+ active = false;
491
+ }
492
+ });
468
493
  };
469
494
 
470
495
 
471
496
  const autoSubscribe = (...list) => {
472
497
  list.forEach(i => {
473
- if(isFunction(i.subscribe)) {
498
+ if(i.subscribe) {
474
499
  let unsub = i.subscribe(current_component.apply);
475
500
  if(isFunction(unsub)) cd_onDestroy(current_component, unsub);
476
501
  }
@@ -491,16 +516,21 @@ const addClass = (el, className) => el.classList.add(className);
491
516
 
492
517
 
493
518
  const bindClass = (cd, element, fn, className) => {
494
- $watchReadOnly(cd, fn, value => {
519
+ $watch(cd, fn, value => {
495
520
  if(value) addClass(element, className);
496
521
  else element.classList.remove(className);
497
- });
522
+ }, {ro: true, value: false});
498
523
  };
499
524
 
500
525
 
501
526
  const setClassToElement = (element, value) => bindAttributeBase(element, 'class', value);
502
527
 
503
528
 
529
+ const bindClassExp = (cd, element, fn) => {
530
+ $watch(cd, fn, value => setClassToElement(element, value), {ro: true, value: ''});
531
+ };
532
+
533
+
504
534
  const bindText = (cd, element, fn) => {
505
535
  $watchReadOnly(cd, () => '' + fn(), value => {
506
536
  element.textContent = value;
@@ -522,10 +552,7 @@ const bindAttributeBase = (element, name, value) => {
522
552
 
523
553
 
524
554
  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));
555
+ $watchReadOnly(cd, () => '' + fn(), value => bindAttributeBase(element, name, value));
529
556
  };
530
557
 
531
558
 
@@ -565,8 +592,8 @@ const makeClassResolver = ($option, classMap, metaClass, mainName) => {
565
592
  if(!$option.$class) $option.$class = {};
566
593
  if(!mainName && metaClass.main) mainName = 'main';
567
594
  return (line, defaults) => {
568
- let result = [];
569
- if(defaults) result.push(defaults);
595
+ let result = {};
596
+ if(defaults) result[defaults] = 1;
570
597
  line.trim().split(/\s+/).forEach(name => {
571
598
  let meta;
572
599
  if(name[0] == '$') {
@@ -577,19 +604,21 @@ const makeClassResolver = ($option, classMap, metaClass, mainName) => {
577
604
  if(h) {
578
605
  let className = ($option.$class[name === mainName ? '$$main' : name] || '').trim();
579
606
  if(className) {
580
- result.push(className);
607
+ result[className] = 1;
581
608
  } else if(h !== true) {
582
- result.push(name, h);
609
+ result[name] = 1;
610
+ result[h] = 1;
583
611
  }
584
612
  }
585
613
  let h2 = classMap[name];
586
614
  if(h2) {
587
- result.push(name, h2);
615
+ result[name] = 1;
616
+ result[h2] = 1;
588
617
  } else if(!h) {
589
- result.push(name);
618
+ result[name] = 1;
590
619
  }
591
620
  });
592
- return result.join(' ');
621
+ return Object.keys(result).join(' ');
593
622
  }
594
623
  };
595
624
 
@@ -602,60 +631,11 @@ const makeExternalProperty = ($component, name, getter, setter) => {
602
631
  };
603
632
 
604
633
 
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
- };
610
-
611
-
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;
634
+ const eachDefaultKey = (item, index, array) => typeof array[0] === 'object' ? item : index;
655
635
 
656
636
 
657
- const attachAnchor = ($option, $cd, name, el) => {
658
- let fn = $option.anchor?.[name];
637
+ const attachAnchor = ($option, $cd, el, name) => {
638
+ let fn = $option.anchor?.[name || 'default'];
659
639
  if(fn) cd_onDestroy($cd, fn(el));
660
640
  };
661
641
 
@@ -690,35 +670,35 @@ const spreadAttributes = (cd, el, fn) => {
690
670
  };
691
671
 
692
672
 
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);
673
+ const callExportedFragment = (childComponent, name, slot, events, props, cmp) => {
674
+ let $cd, r;
675
+ if(cmp) {
676
+ $cd = cd_new();
677
+ let fn = props, result;
678
+ props = () => result;
679
+ let w = $watch($cd, fn, (props) => {
680
+ result = props;
681
+ r?.push();
682
+ }, {value: {}, cmp});
683
+ fire(w);
712
684
  }
685
+ let fn = childComponent.exported[name];
686
+ r = fn(props, events, slot);
687
+ r.$cd = $cd;
688
+ return r;
713
689
  };
714
690
 
715
691
 
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();
692
+ const exportFragment = (childCD, name, fn) => {
693
+ cd_component(childCD).exported[name] = (props, events, slot) => {
694
+ let {$cd, $dom} = fn(props, events || {}, slot);
695
+ cd_attach(childCD, $cd);
696
+ let apply = cd_component(childCD).apply;
697
+ return {
698
+ $dom,
699
+ destroy: () => $cd.destroy(),
700
+ push: () => apply?.()
701
+ };
722
702
  };
723
703
  };
724
704
 
@@ -729,18 +709,6 @@ const prefixPush = ($cd, fn) => {
729
709
  };
730
710
 
731
711
 
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
712
  const unwrapProps = (cd, props, fn) => {
745
713
  if(props) {
746
714
  if(isFunction(props)) prefixPush(cd, () => fn(props()));
@@ -748,112 +716,238 @@ const unwrapProps = (cd, props, fn) => {
748
716
  }
749
717
  };
750
718
 
719
+
720
+ const makeBlock = (fr, fn) => {
721
+ return (v) => {
722
+ let $dom = fr.cloneNode(true), $cd = cd_new();
723
+ fn($cd, $dom, v);
724
+ return {$cd, $dom};
725
+ }
726
+ };
727
+
728
+
729
+ const makeBlockBound = (parentCD, fr, fn) => {
730
+ return () => {
731
+ let $dom = fr.cloneNode(true), $cd = cd_new();
732
+ fn($cd, $dom);
733
+ cd_attach(parentCD, $cd);
734
+ return {
735
+ $dom,
736
+ destroy: () => cd_destroy$1($cd)
737
+ };
738
+ }
739
+ };
740
+
741
+
742
+ const makeStaticBlock = (fr, fn) => {
743
+ return () => {
744
+ let $dom = fr.cloneNode(true);
745
+ fn?.($dom);
746
+ return {$dom};
747
+ }
748
+ };
749
+
750
+ const attachBlock = (cdo, label, block) => {
751
+ if(!block) return;
752
+ cd_onDestroy(cdo, block.destroy);
753
+ cd_attach(cdo, block.$cd);
754
+ insertAfter(label, block.$dom);
755
+ };
756
+
757
+
758
+ const mergeEvents = (...callbacks) => {
759
+ callbacks = callbacks.filter(i => i);
760
+ return (e) => callbacks.forEach(cb => cb(e));
761
+ };
762
+
763
+
764
+ const makeRootEvent = (root) => {
765
+ let events = {}, nodes = [];
766
+
767
+ if(root.nodeType == 11) {
768
+ let n = root.firstElementChild;
769
+ while(n) {
770
+ nodes.push(n);
771
+ n = n.nextElementSibling;
772
+ }
773
+ } else nodes = [root];
774
+
775
+ $onDestroy(() => {
776
+ for(let eventName in events) {
777
+ nodes.forEach(n => n.removeEventListener(eventName, events[eventName]));
778
+ }
779
+ });
780
+ return (target, eventName, callback) => {
781
+ let handler = events[eventName];
782
+ if(!handler) {
783
+ handler = events[eventName] = ($event) => {
784
+ let top = $event.currentTarget;
785
+ let el = $event.target;
786
+ while(el) {
787
+ if(el.__cb?.[eventName]) {
788
+ el.__cb[eventName]($event);
789
+ return;
790
+ }
791
+ if(el == top) break;
792
+ el = el.parentNode;
793
+ }
794
+ };
795
+ nodes.forEach(n => n.addEventListener(eventName, handler));
796
+ } if(!target.__cb) target.__cb = {};
797
+ target.__cb[eventName] = callback;
798
+ }
799
+ };
800
+
751
801
  function $$htmlBlock($cd, tag, fn) {
752
802
  let lastElement;
753
803
  let create = (html) => {
754
804
  let fr;
755
805
  if(tag.parentElement instanceof SVGElement) fr = svgToFragment(html);
756
- else fr = $$htmlToFragment(html);
806
+ else fr = $$htmlToFragment(html, 3);
757
807
  lastElement = fr.lastChild;
758
808
  insertAfter(tag, fr);
759
809
  };
760
810
  let destroy = () => {
761
811
  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
-
812
+ $$removeElements(tag.nextSibling, lastElement);
770
813
  lastElement = null;
771
814
  };
772
- $watch($cd, fn, (html) => {
773
- destroy();
774
- if(html) create(html);
775
- }, {ro: true});
815
+ if($cd) {
816
+ $watch($cd, fn, (html) => {
817
+ destroy();
818
+ if(html) create(html);
819
+ }, {ro: true});
820
+ } else create(fn());
776
821
  }
777
822
 
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;
823
+ function ifBlock(parentCD, label, fn, build, buildElse) {
824
+ let first, last, $cd, destroy;
825
+ cd_onDestroy(parentCD, () => destroy?.());
826
+
827
+ function createBlock(builder) {
828
+ let $dom;
829
+ ({$cd, destroy, $dom} = builder());
830
+ cd_attach(parentCD, $cd);
831
+ if($dom.nodeType == 11) {
832
+ first = $dom[firstChild];
833
+ last = $dom.lastChild;
834
+ } else first = last = $dom;
835
+ insertAfter(label, $dom);
836
+ }
837
+ function destroyBlock() {
838
+ if(!first) return;
839
+ destroy?.();
840
+ destroy = null;
841
+ if($cd) {
842
+ cd_destroy$1($cd);
843
+ $cd = null;
844
+ }
794
845
  $$removeElements(first, last);
795
846
  first = last = null;
796
847
  }
797
- $watch($cd, fn, (value) => {
848
+ $watch(parentCD, fn, (value) => {
798
849
  if(value) {
799
- destroy();
800
- create(tpl, build);
850
+ destroyBlock();
851
+ createBlock(build);
801
852
  } else {
802
- destroy();
803
- if(buildElse) create(tplElse, buildElse);
853
+ destroyBlock();
854
+ if(buildElse) createBlock(buildElse);
804
855
  }
805
856
  });
806
857
  }
807
858
 
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;
859
+ function ifBlockReadOnly(component, label, fn, build, buildElse) {
860
+ function createBlock(builder) {
861
+ let {destroy, $dom} = builder();
862
+ cd_onDestroy(component, destroy);
863
+ insertAfter(label, $dom);
864
+ }
865
+ if(fn()) createBlock(build);
866
+ else if(buildElse) createBlock(buildElse);
867
+ }
811
868
 
812
- function remove() {
813
- if(!childCD) return;
814
- childCD.destroy();
815
- childCD = null;
869
+ function $$awaitBlock(parentCD, label, relation, fn, build_main, build_then, build_catch) {
870
+ let first, last, $cd, destroy, promise, status = 0;
871
+ cd_onDestroy(parentCD, () => destroy?.());
872
+
873
+ function destroyBlock() {
874
+ if(!first) return;
875
+ destroy?.();
876
+ destroy = null;
877
+ if($cd) {
878
+ cd_destroy($cd);
879
+ $cd = null;
880
+ }
816
881
  $$removeElements(first, last);
817
882
  first = last = null;
818
883
  }
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, () => {
884
+ function render(builder, value) {
885
+ destroyBlock();
886
+
887
+ let $dom;
888
+ ({$cd, destroy, $dom} = builder(value));
889
+ cd_attach(parentCD, $cd);
890
+ if($dom.nodeType == 11) {
891
+ first = $dom[firstChild];
892
+ last = $dom.lastChild;
893
+ } else first = last = $dom;
894
+ insertAfter(label, $dom);
895
+ cd_component(parentCD).apply();
896
+ }
897
+ $watch(parentCD, relation, () => {
831
898
  let p = fn();
832
- if(status !== 1) render(build_main, tpl_main);
899
+ if(status !== 1) render(build_main);
833
900
  status = 1;
834
901
  if(p && p instanceof Promise) {
835
902
  promise = p;
836
903
  promise.then(value => {
837
904
  status = 2;
838
905
  if(promise !== p) return;
839
- render(build_then, tpl_then, value);
906
+ render(build_then, value);
840
907
  }).catch(value => {
841
908
  status = 3;
842
909
  if(promise !== p) return;
843
- render(build_catch, tpl_catch, value);
910
+ render(build_catch, value);
844
911
  });
845
912
  }
846
- }, {ro: true, cmp: $$deepComparator(1)});
913
+ }, {ro: true, value: [], cmp: keyComparator});
847
914
  }
848
915
 
849
- function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind) {
850
- let $cd = $parentCD.new();
916
+ const makeEachBlock = (fr, fn) => {
917
+ return (item, index) => {
918
+ let $dom = fr.cloneNode(true), $cd = cd_new();
919
+ let rebind = fn($cd, $dom, item, index);
920
+ return {$cd, $dom, rebind};
921
+ }
922
+ };
923
+
924
+
925
+ const makeStaticEachBlock = (fr, fn) => {
926
+ return (item, index) => {
927
+ let $dom = fr.cloneNode(true);
928
+ let rebind = fn($dom, item, index);
929
+ return {$dom, rebind};
930
+ }
931
+ };
932
+
933
+
934
+ const makeEachSingleBlock = (fn) => {
935
+ return (item, index) => {
936
+ let [rebind, component] = fn(item, index);
937
+ let {$cd, destroy, $dom} = component;
938
+ return {$cd, destroy, $dom, rebind};
939
+ }
940
+ };
941
+
942
+
943
+ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, bind) {
944
+ let eachCD = cd_new();
945
+ cd_attach($parentCD, eachCD);
851
946
 
852
947
  let mapping = new Map();
853
948
  let lastNode;
854
- let tplLength = itemTemplate[childNodes].length;
855
949
 
856
- $watch($cd, fn, (array) => {
950
+ $watch(eachCD, fn, (array) => {
857
951
  if(!array) array = [];
858
952
  if(typeof(array) == 'number') array = [...Array(array)].map((_,i) => i + 1);
859
953
  else if(!isArray(array)) array = [];
@@ -881,19 +975,21 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
881
975
  if(!count && lastNode) {
882
976
  if(onlyChild) label.textContent = '';
883
977
  else $$removeElements(label.nextSibling, lastNode);
884
- $cd.children.forEach(cd => cd.destroy(false));
885
- $cd.children.length = 0;
978
+ eachCD.children.forEach(cd => cd.destroy(false));
979
+ eachCD.children.length = 0;
980
+ mapping.forEach(ctx => ctx.destroy?.());
886
981
  mapping.clear();
887
- } else {
888
- $cd.children = [];
982
+ } else if(count < mapping.size) {
983
+ eachCD.children = [];
889
984
  mapping.forEach(ctx => {
890
985
  if(ctx.a) {
891
986
  ctx.a = false;
892
- $cd.children.push(ctx.cd);
987
+ ctx.$cd && eachCD.children.push(ctx.$cd);
893
988
  return;
894
989
  }
895
990
  $$removeElements(ctx.first, ctx.last);
896
- ctx.cd.destroy(false);
991
+ ctx.$cd?.destroy(false);
992
+ ctx.destroy?.();
897
993
  });
898
994
  }
899
995
  }
@@ -910,7 +1006,7 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
910
1006
  if(nextEl != ctx.first) {
911
1007
  let insert = true;
912
1008
 
913
- if(tplLength == 1 && (i + 1 < array.length) && prevNode?.nextSibling) {
1009
+ if(ctx.first == ctx.last && (i + 1 < array.length) && prevNode?.nextSibling) {
914
1010
  next_ctx = mapping.get(getKey(array[i + 1], i + 1, array));
915
1011
  if(next_ctx && prevNode.nextSibling.nextSibling === next_ctx.first) {
916
1012
  parentNode.replaceChild(ctx.first, prevNode.nextSibling);
@@ -929,15 +1025,16 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
929
1025
  }
930
1026
  }
931
1027
  }
932
- ctx.rebind(i, item);
1028
+ ctx.rebind?.(i, item);
933
1029
  } 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);
1030
+ let $dom;
1031
+ ({$dom, ...ctx} = bind(item, i));
1032
+ cd_attach(eachCD, ctx.$cd);
1033
+ if($dom.nodeType == 11) {
1034
+ ctx.first = $dom[firstChild];
1035
+ ctx.last = $dom.lastChild;
1036
+ } else ctx.first = ctx.last = $dom;
1037
+ parentNode.insertBefore($dom, prevNode?.nextSibling);
941
1038
  }
942
1039
  prevNode = ctx.last;
943
1040
  newMapping.set(getKey(item, i, array), ctx);
@@ -947,4 +1044,39 @@ function $$eachBlock($parentCD, label, onlyChild, fn, getKey, itemTemplate, bind
947
1044
  }, {ro: true, cmp: $$compareArray});
948
1045
  }
949
1046
 
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 };
1047
+ const invokeSlotBase = ($component, slotName, $context, props, placeholder) => {
1048
+ let $slot = $component.$option.slots?.[slotName || 'default'];
1049
+ return $slot ? $slot($component, $context, props) : placeholder?.();
1050
+ };
1051
+
1052
+
1053
+ const invokeSlot = ($component, slotName, $context, propsFn, placeholder, cmp) => {
1054
+ let $slot = $component.$option.slots?.[slotName || 'default'];
1055
+
1056
+ if($slot) {
1057
+ let push, w, result;
1058
+ w = cd_watchObject(propsFn, value => push?.(value), {ro: true, value: {}, cmp});
1059
+ fire(w);
1060
+ ({push, ...result} = $slot($component, $context, w.value));
1061
+ if(push) {
1062
+ result.$cd = cd_new();
1063
+ result.$cd.watchers.push(w);
1064
+ }
1065
+ return result;
1066
+ } else return placeholder?.();
1067
+ };
1068
+
1069
+
1070
+ const makeSlot = (parentCD, fr, fn) => {
1071
+ return (callerComponent, $context, props) => {
1072
+ let $dom = fr.cloneNode(true), $cd = cd_new();
1073
+ cd_attach(parentCD, $cd);
1074
+ return {
1075
+ $dom,
1076
+ destroy: () => cd_destroy$1($cd),
1077
+ push: fn($cd, $dom, $context, callerComponent, props)
1078
+ };
1079
+ };
1080
+ };
1081
+
1082
+ 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, eachDefaultKey, exportFragment, fire, firstChild, getFinalLabel, ifBlock, ifBlockReadOnly, insertAfter, invokeSlot, invokeSlotBase, isArray, isFunction, keyComparator, makeBlock, makeBlockBound, makeClassResolver, makeComponent, makeEachBlock, makeEachSingleBlock, makeExternalProperty, makeRootEvent, makeSlot, makeStaticBlock, makeStaticEachBlock, mergeEvents, noop, prefixPush, removeElementsBetween, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };