malinajs 0.6.49 → 0.7.0-a2

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