wallace 0.0.1

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.
@@ -0,0 +1,811 @@
1
+ const doc = document;
2
+ const throwAway = doc.createElement('template');
3
+
4
+ /**
5
+ * Create an element from html string
6
+ */
7
+ function makeEl(html) {
8
+ throwAway.innerHTML = html;
9
+ return throwAway.content.firstChild
10
+ }
11
+
12
+ /**
13
+ * Some utility functions
14
+ */
15
+ const und = x => x === undefined;
16
+ const isStr = x => typeof x === 'string';
17
+
18
+ /**
19
+ * A wrapper around a DOM element.
20
+ * All transformative methods return this (except transitions as they return promises)
21
+ * This means those methods can be chained.
22
+ */
23
+ function Wrapper(element) {
24
+ this.e = element;
25
+ this._pool = undefined;
26
+ }
27
+
28
+ Wrapper.prototype = {
29
+ /**
30
+ * Get element as 'e' from item, else return text node.
31
+ */
32
+ __ge: function(item) {
33
+ return item.e || doc.createTextNode(item)
34
+ },
35
+ /**
36
+ * Gets an attribute from the element. Cannot be chained.
37
+ */
38
+ getAtt: function(name) {
39
+ return this.e[name]
40
+ },
41
+ /**
42
+ * Gets the element's value. Cannot be chained.
43
+ */
44
+ getValue: function() {
45
+ return this.e.value
46
+ },
47
+ isChecked: function() {
48
+ return this.e.checked
49
+ },
50
+ /* Every method below must return 'this' so it can be chained */
51
+ append: function(item) {
52
+ this.e.appendChild(this.__ge(item));
53
+ return this
54
+ },
55
+ att: function(name, value) {
56
+ this.e.setAttribute(name, value);
57
+ return this
58
+ },
59
+ atts: function(atts) {
60
+ for (let name in atts) {
61
+ this.att(name, atts[name]);
62
+ }
63
+ return this
64
+ },
65
+ pool: function(pool) {
66
+ this._pool = pool;
67
+ return this
68
+ },
69
+ clear: function() {
70
+ this.e.innerHTML = '';
71
+ this.e.textContent = '';
72
+ this.e.value = '';
73
+ return this
74
+ },
75
+ checked: function(value) {
76
+ this.e.checked = !!value;
77
+ return this
78
+ },
79
+ child: function(wrapper) {
80
+ this.e.innerHTML = '';
81
+ this.e.appendChild(wrapper.e);
82
+ return this
83
+ },
84
+ css: function(style) {
85
+ this.e.className = style;
86
+ return this
87
+ },
88
+ cssAdd: function(style) {
89
+ this.e.classList.add(style);
90
+ return this
91
+ },
92
+ cssRemove: function(style) {
93
+ this.e.classList.remove(style);
94
+ return this
95
+ },
96
+ cssToggle: function(style) {
97
+ this.e.classList.toggle(style);
98
+ return this
99
+ },
100
+ disabled: function(disabled) {
101
+ this.e.disabled = disabled;
102
+ return this
103
+ },
104
+ href: function(value) {
105
+ return this.att('href', value)
106
+ },
107
+ html: function(html) {
108
+ this.e.innerHTML = html;
109
+ return this
110
+ },
111
+ id: function(value) {
112
+ return this.att('id', value)
113
+ },
114
+ /*
115
+ * Set inner as individual item or array. Not optimised.
116
+ */
117
+ inner: function(items) {
118
+ if (!Array.isArray(items)) {
119
+ items = [items];
120
+ }
121
+ const e = this.e;
122
+ e.innerHTML = '';
123
+ for (var i=0, il=items.length; i<il; i++) {
124
+ e.appendChild(this.__ge(items[i]));
125
+ }
126
+ return this
127
+ },
128
+ /*
129
+ * Set items from pool.
130
+ */
131
+ items: function(items, parent) {
132
+ this._pool.patch(this.e, items, parent);
133
+ return this
134
+ },
135
+ on: function(event, callback) {
136
+ this.e.addEventListener(event, e => callback(this, e));
137
+ return this
138
+ },
139
+ replace: function(el) {
140
+ this.e.parentNode.replaceChild(el, this.e);
141
+ return this
142
+ },
143
+ src: function(value) {
144
+ return this.att('src', value)
145
+ },
146
+ style: function(name, value) {
147
+ this.e.style[name] = value;
148
+ return this
149
+ },
150
+ swap: function(key, parent) {
151
+ this.child(this._pool.getOne(key, parent));
152
+ return this
153
+ },
154
+ text: function(value) {
155
+ this.e.textContent = value;
156
+ return this
157
+ },
158
+ visible: function(visible) {
159
+ this.e.classList.toggle('hidden', !visible);
160
+ return this
161
+ },
162
+ value: function(value) {
163
+ this.e.value = value;
164
+ return this
165
+ }
166
+ };
167
+
168
+ /**
169
+ * Creates and mounts a component onto an element.
170
+ *
171
+ * @param {unsure} elementOrId Either a string representing an id, or an element.
172
+ * @param {class} cls The class of Component to create
173
+ * @param {object} props The props to pass to the component (optional)
174
+ * @param {object} parent The parent component (optional)
175
+ */
176
+ function mount(elementOrId, cls, props, parent) {
177
+ const component = createComponent(cls, parent, props);
178
+ const nodeToReplace = getElement(elementOrId);
179
+ nodeToReplace.parentNode.replaceChild(component.e, nodeToReplace);
180
+ return component
181
+ }
182
+
183
+ /**
184
+ * returns a Wrapper around an element.
185
+ *
186
+ * @param {unsure} elementOrId Either a string representing an id, or an element.
187
+ */
188
+ function wrap(elementOrId) {
189
+ return new Wrapper(getElement(elementOrId))
190
+ }
191
+
192
+
193
+ function getElement(elementOrId) {
194
+ return isStr(elementOrId) ? document.getElementById(elementOrId) : elementOrId
195
+ }
196
+
197
+
198
+ /**
199
+ * Creates a component and initialises it.
200
+ *
201
+ * @param {class} cls The class of Component to create
202
+ * @param {object} parent The parent component (optional)
203
+ * @param {object} props The props to pass to the component (optional)
204
+ */
205
+ function createComponent(cls, parent, props) {
206
+ const component = buildComponent(cls, parent);
207
+ component.props = props;
208
+ component.init();
209
+ component.update();
210
+ return component
211
+ }
212
+
213
+ /**
214
+ * Builds a component.
215
+ */
216
+ function buildComponent(cls, parent) {
217
+ const component = new cls(parent);
218
+ component.__bv(component, cls.prototype);
219
+ return component
220
+ }
221
+
222
+
223
+ /**
224
+ * Creates a wrapper of type tag e.g. h('div')
225
+ */
226
+ function h(tag) {
227
+ return new Wrapper(doc.createElement(tag))
228
+ }
229
+
230
+ /**
231
+ * Pools same type components, retrieving by sequence.
232
+ * Must not be shared.
233
+ *
234
+ * @param {class} componentClass - The class of Component to create.
235
+ * @param {function} keyFn - A function which obtains the key to pool by
236
+ */
237
+ function KeyedPool(componentClass, keyFn) {
238
+ this._v = componentClass;
239
+ this._f = keyFn;
240
+ this._k = []; // keys
241
+ this._p = {}; // pool of component instances
242
+ }
243
+ const proto$1 = KeyedPool.prototype;
244
+
245
+ /**
246
+ * Retrieves a single component. Though not used in Wallace itself, it may
247
+ * be used elsewhere, such as in the router.
248
+ *
249
+ * @param {Object} item - The item which will be passed as props.
250
+ * @param {Component} parent - The parent component.
251
+ */
252
+ proto$1.getOne = function(item, parent) {
253
+ return this._get(this._p, this._v, this._f(item), item, parent)
254
+ };
255
+
256
+ /**
257
+ * Updates the element's childNodes to match the items.
258
+ * Performance is important.
259
+ *
260
+ * @param {DOMElement} e - The DOM element to patch.
261
+ * @param {Array} items - Array of items which will be passed as props.
262
+ * @param {Component} parent - The parent component.
263
+ */
264
+ proto$1.patch = function(e, items, parent) {
265
+ const pool = this._p;
266
+ const componentClass = this._v;
267
+ const keyFn = this._f;
268
+ const childNodes = e.childNodes;
269
+ const itemsLength = items.length;
270
+ const oldKeySequence = this._k;
271
+ const newKeys = [];
272
+ let item, key, component, childElementCount = oldKeySequence.length + 1;
273
+ for (let i=0; i<itemsLength; i++) {
274
+ item = items[i];
275
+ key = keyFn(item);
276
+ component = this._get(pool, componentClass, key, item, parent);
277
+ newKeys.push(key);
278
+ if (i > childElementCount) {
279
+ e.appendChild(component.e);
280
+ } else if (key !== oldKeySequence[i]) {
281
+ e.insertBefore(component.e, childNodes[i]);
282
+ pull(oldKeySequence, key, i);
283
+ }
284
+ }
285
+ this._k = newKeys;
286
+ trimChildren(e, childNodes, itemsLength);
287
+ };
288
+
289
+ // Internal
290
+ proto$1._get = function(pool, componentClass, key, item, parent) {
291
+ let component;
292
+ if (pool.hasOwnProperty(key)) {
293
+ component = pool[key];
294
+ component.setProps(item);
295
+ } else {
296
+ component = createComponent(componentClass, parent, item);
297
+ pool[key] = component;
298
+ }
299
+ return component
300
+ };
301
+
302
+ /**
303
+ * Pools same type components, retrieving by sequence.
304
+ * Must not be shared.
305
+ *
306
+ * @param {class} componentClass - The class of Component to create.
307
+ */
308
+ function SequentialPool(componentClass) {
309
+ this._v = componentClass;
310
+ this._p = []; // pool of component instances
311
+ this._c = 0; // Child element count
312
+ }
313
+
314
+ /**
315
+ * Updates the element's childNodes to match the items.
316
+ * Performance is important.
317
+ *
318
+ * @param {DOMElement} e - The DOM element to patch.
319
+ * @param {Array} items - Array of items which will be passed as props.
320
+ * @param {Component} parent - The parent component.
321
+ */
322
+ SequentialPool.prototype.patch = function(e, items, parent) {
323
+ const pool = this._p;
324
+ const componentClass = this._v;
325
+ const childNodes = e.childNodes;
326
+ const itemsLength = items.length;
327
+ let item, component, poolCount = pool.length, childElementCount = this._c;
328
+
329
+ for (let i=0; i<itemsLength; i++) {
330
+ item = items[i];
331
+ if (i < poolCount) {
332
+ component = pool[i];
333
+ component.setProps(item);
334
+ } else {
335
+ component = createComponent(componentClass, parent, item);
336
+ pool.push(component);
337
+ poolCount ++;
338
+ }
339
+ if (i >= childElementCount) {
340
+ e.appendChild(component.e);
341
+ }
342
+ }
343
+ this._c = itemsLength;
344
+ trimChildren(e, childNodes, itemsLength);
345
+ };
346
+
347
+ /**
348
+ * An object which creates and pools components according to the mappings provided.
349
+ * If there is no match in the mappings, the fallback function is called.
350
+ *
351
+ * Note that the fallback must return an instance (of Component or Wrapper) whereas
352
+ * mappings must specify component classes.
353
+ *
354
+ * You can rely solely on the fallback if you like.
355
+ *
356
+ * @param {Object} mappings - a mapping of format key->componentClass
357
+ * @param {function} fallback - a function to call when no key is provided.
358
+ *
359
+ */
360
+ function InstancePool(mappings, fallback) {
361
+ this._m = mappings;
362
+ this._f = fallback;
363
+ this._i = {}; // Instances
364
+ }
365
+
366
+ InstancePool.prototype.getOne = function(key, parentComponent) {
367
+ if (!this._i.hasOwnProperty(key)) {
368
+ this._i[key] = this._m.hasOwnProperty(key) ?
369
+ parentComponent.nest(this._m[key]) : this._f(key, parentComponent);
370
+ }
371
+ return this._i[key]
372
+ };
373
+
374
+ /**
375
+ * Trims the unwanted child elements from the end.
376
+ *
377
+ * @param {Node} e
378
+ * @param {Array} childNodes
379
+ * @param {Int} itemsLength
380
+ */
381
+ function trimChildren(e, childNodes, itemsLength) {
382
+ let lastIndex = childNodes.length - 1;
383
+ let keepIndex = itemsLength - 1;
384
+ for (let i=lastIndex; i>keepIndex; i--) {
385
+ e.removeChild(childNodes[i]);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Pulls an item forward in an array, to replicate insertBefore.
391
+ * @param {Array} arr
392
+ * @param {any} item
393
+ * @param {Int} to
394
+ */
395
+ function pull(arr, item, to) {
396
+ const position = arr.indexOf(item);
397
+ if (position != to) {
398
+ arr.splice(to, 0, arr.splice(position, 1)[0]);
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Wallace's crude way of tracking mounting and unmounting.
404
+ */
405
+
406
+ const trackedComponents = [];
407
+
408
+ var mountie = {
409
+ track: function (component) {
410
+ trackedComponents.push({component: component, isAttached: component.__ia()});
411
+ },
412
+ flush: function () {
413
+ for (let i=0, il=trackedComponents.length; i<il; i++) {
414
+ let trackedComponent = trackedComponents[i];
415
+ let component = trackedComponent.component;
416
+ let attachedNow = component.__ia();
417
+ if (attachedNow !== trackedComponent.isAttached) {
418
+ let fn = attachedNow ? component.mount : component.unmount;
419
+ fn.apply(component);
420
+ trackedComponent.isAttached = attachedNow;
421
+ }
422
+ }
423
+ }
424
+ };
425
+
426
+ /**
427
+ * Used internally.
428
+ * An object which pools the results of lookup queries so we don't have to
429
+ * repeat them in the same component.
430
+ * The Lookup instance will be shared between instances of a component.
431
+ * Must call reset() on every update.
432
+ */
433
+ function Lookup(callbacks) {
434
+ this.callbacks = callbacks;
435
+ this.run = {};
436
+ }
437
+
438
+ Lookup.prototype = {
439
+ get: function(component, key) {
440
+ const run = this.run;
441
+ if (run[key] === undefined) {
442
+ // Verbose but efficient way as it avoids lookups?
443
+ // Or is this harmful to performance because we're just reading values more than calling functions?
444
+ let o = component.__ov[key];
445
+ o = und(o) ? '' : o;
446
+ const n = this.callbacks[key](component, component.props);
447
+ const c = n !== o;
448
+ component.__ov[key] = n;
449
+ const rtn = {n, o, c};
450
+ run[key] = rtn;
451
+ return rtn
452
+ }
453
+ return run[key]
454
+ },
455
+ reset: function() {
456
+ this.run = {};
457
+ }
458
+ };
459
+
460
+ const noop = function() {};
461
+
462
+ /**
463
+ * Represents a component.
464
+ */
465
+ function Component(parent) {
466
+ const s = this;
467
+ s.parent = parent; // The parent component
468
+ s.props = undefined; // The props passed to the component. May be changed.
469
+
470
+ // These will be set during build
471
+ s.e = null; // the element
472
+ s.el = null; // the named wrappers
473
+
474
+ // Internal state objects
475
+ s.__nv = []; // Nested components
476
+ s.__ov = {}; // The old values for watches to compare against
477
+ }
478
+
479
+
480
+ var proto = Component.prototype;
481
+
482
+ proto.onUpdate = noop;
483
+ proto.afterUpdate = noop;
484
+ proto.onInit = noop;
485
+ proto.afterInit = noop;
486
+
487
+ /**
488
+ * Gets called once immediately after building.
489
+ * Sets initial props extracted from __html__.
490
+ * Note there is an issue here, in that we rely on there being initial props to call init
491
+ * on nested components.
492
+ */
493
+ proto.init = function() {
494
+ this.onInit();
495
+ for (let key in this.__ip) {
496
+ let nestedComponent = this.el[key];
497
+ let callback = this.__ip[key];
498
+ if (callback) {
499
+ nestedComponent.props = callback(this, this.props);
500
+ }
501
+ nestedComponent.init();
502
+ }
503
+ this.afterInit();
504
+ };
505
+ /**
506
+ * Calls a function somewhere up the parent tree.
507
+ */
508
+ proto.bubble = function(name) {
509
+ let target = this.parent;
510
+ while (!und(target)) {
511
+ if (target[name]) {
512
+ // We don't really care about performance here, so accessing arguments is fine.
513
+ return target[name].apply(target, Array.prototype.slice.call(arguments, 1))
514
+ }
515
+ target = target.parent;
516
+ }
517
+ throw 'Bubble popped.'
518
+ };
519
+ /**
520
+ * Move the component to new parent. Necessary if sharing a pool.
521
+ */
522
+ proto.move = function(newParent) {
523
+ if (this.parent && this.parent.__nv) {
524
+ const nv = this.parent.__nv;
525
+ nv.splice(nv.indexOf(this), 1);
526
+ }
527
+ this.parent = newParent;
528
+ };
529
+ /**
530
+ * Builds a nested component of the specified class. Its up to you how you use it.
531
+ */
532
+ proto.nest = function(cls, props) {
533
+ const child = createComponent(cls, this, props || this.props);
534
+ this.__nv.push(child);
535
+ return child
536
+ };
537
+ /**
538
+ * Lookup a watched value during update. Returns an object with {o, n, c}
539
+ * (oldValue, newValue, changed).
540
+ * You must call this.resetLookups before calling this during an update.
541
+ * The point is to pool the result so it doesn't have to be repeated.
542
+ */
543
+ proto.lookup = function(query) {
544
+ return this.__qc.get(this, query)
545
+ };
546
+ /**
547
+ * Resets the lookups, must be called before calling this.lookup() during an update.
548
+ */
549
+ proto.resetLookups = function() {
550
+ this.__qc.reset();
551
+ };
552
+ /**
553
+ * Sets the props and updates the component.
554
+ */
555
+ proto.setProps = function(props) {
556
+ this.props = props;
557
+ this.update();
558
+ return this
559
+ };
560
+ /**
561
+ * Call this if you want to get mount() and unmount() callbacks.
562
+ */
563
+ proto.trackMounting = function() {
564
+ this.__mt.track(this);
565
+ };
566
+ /**
567
+ * Updates the component.
568
+ */
569
+ proto.update = function() {
570
+ this.onUpdate();
571
+ this.resetLookups();
572
+ this.updateSelf();
573
+ this.updateNested();
574
+ this.afterUpdate();
575
+ };
576
+ /**
577
+ * Loops over watches skipping shielded watches if elements are hidden.
578
+ */
579
+ proto.updateSelf = function() {
580
+ let i = 0, watch, wrapper, shieldCount, shieldQuery, shieldQueryResult, shouldBeVisible;
581
+ const watches = this.__wc;
582
+ const il = watches.length;
583
+ while (i < il) {
584
+ watch = watches[i];
585
+ wrapper = this.el[watch.wk];
586
+ shieldQuery = watch.sq;
587
+ i ++;
588
+ shouldBeVisible = true;
589
+ if (shieldQuery) {
590
+ // Get the newValue for shieldQuery using lookup
591
+ shieldQueryResult = this.lookup(shieldQuery).n;
592
+
593
+ // Determine if shouldBeVisible based on reverseShield
594
+ // i.e. whether "shieldQuery===true" means show or hide.
595
+ shouldBeVisible = watch.rv ? shieldQueryResult : !shieldQueryResult;
596
+
597
+ // The number of watches to skip if this element is not visible
598
+ shieldCount = shouldBeVisible ? 0 : watch.sc;
599
+
600
+ // Set the element visibility
601
+ wrapper.visible(shouldBeVisible);
602
+ i += shieldCount;
603
+ }
604
+ if (shouldBeVisible) {
605
+ applyWatchCallbacks(this, wrapper, watch.cb);
606
+ }
607
+ }
608
+ };
609
+ /**
610
+ * Update nested components (but not repeat elements).
611
+ */
612
+ proto.updateNested = function() {
613
+ // These are user created by calling nest()
614
+ const items = this.__nv;
615
+ for (let i=0, il=items.length; i<il; i++) {
616
+ let child = items[i];
617
+ if (child.__ia()) {
618
+ child.update();
619
+ }
620
+ }
621
+ // These are created with directives, and whose props arguments may need reprocessed.
622
+ for (let key in this.__ip) {
623
+ let callback = this.__ip[key];
624
+ let nestedComponent = this.el[key];
625
+ if (callback) {
626
+ nestedComponent.setProps(callback(this, this.props));
627
+ } else {
628
+ nestedComponent.update();
629
+ }
630
+ }
631
+ };
632
+ /**
633
+ * Calls the callback if the value has changed (
634
+ */
635
+ // changed(name, callback) {
636
+ // const n = this.__ov[name]
637
+ // const o = this.props[name]
638
+ // if (n !== o) {
639
+ // callback(n, o)
640
+ // }
641
+ // }
642
+
643
+
644
+ /**
645
+ * Creates a watch.
646
+ */
647
+ proto.__wa = function(wrapperKey, shieldQuery, reverseShield, shieldCount, callbacks) {
648
+ return {
649
+ wk: wrapperKey, // The key of the corresponding wrapper.
650
+ sq: shieldQuery, // The shield query key
651
+ rv: reverseShield, // whether shieldQuery should be flipped
652
+ sc: shieldCount, // The number of items to shield
653
+ cb: callbacks // The callbacks - object
654
+ }
655
+ };
656
+
657
+
658
+ const applyWatchCallbacks = (component, wrapper, callbacks) => {
659
+
660
+ for (let key in callbacks) {
661
+ let callback = callbacks[key];
662
+ if (key === '*') {
663
+ callback.call(component, wrapper, component.props, component);
664
+ } else {
665
+ // means: {new, old, changed}
666
+ const {n, o, c} = component.lookup(key);
667
+ if (c) {
668
+ callback.call(component, n, o, wrapper, component.props, component);
669
+ }
670
+ }
671
+ }
672
+ };
673
+
674
+
675
+ /**
676
+ * The global mount tracker.
677
+ */
678
+ proto.__mt = mountie;
679
+
680
+ /**
681
+ * Nest Internal. For building a nested component declared in the html.
682
+ */
683
+ proto.__ni = function(path, cls) {
684
+ const child = buildComponent(cls, this);
685
+ this.__gw(path).replace(child.e);
686
+ return child
687
+ };
688
+
689
+ /**
690
+ *
691
+ * @param {function} baseClass - the base class to extend from
692
+ * @param {object} [prototypeExtras] - an object with extra things to be added to the prototype
693
+ * @param {function} [prototypeExtras] - the function to be used as constructor
694
+ */
695
+ Component.prototype.__ex = function(baseClass, prototypeExtras, constructorFunction) {
696
+ var subClass = constructorFunction || function(parent) {
697
+ baseClass.call(this, parent);
698
+ };
699
+ subClass.prototype = Object.create(baseClass && baseClass.prototype, {
700
+ constructor: { value: subClass, writable: true, configurable: true }
701
+ });
702
+ if (prototypeExtras) {
703
+ Object.assign(subClass.prototype, prototypeExtras);
704
+ }
705
+ return subClass
706
+ };
707
+
708
+
709
+ /**
710
+ * Create a component pool.
711
+ */
712
+ proto.pool = function(cls, keyFn) {
713
+ return keyFn ? new KeyedPool(cls, keyFn) : new SequentialPool(cls)
714
+ };
715
+
716
+ /**
717
+ * Create an instance pool, for switches.
718
+ */
719
+ proto.__ic = function(mappings, fallback) {
720
+ return new InstancePool(mappings, fallback)
721
+ };
722
+
723
+ /**
724
+ * Build the DOM. We pass prototype as local var for compactness.
725
+ */
726
+ proto.__bd = function(prototype) {
727
+ if (prototype.__cn === undefined) {
728
+ prototype.__cn = makeEl(prototype.__ht);
729
+ }
730
+ this.e = prototype.__cn.cloneNode(true);
731
+ };
732
+
733
+ // proto.__bd = function(prototype, clone) {
734
+ // if (clone && !prototype.__cn) {
735
+ // prototype.__cn = makeEl(prototype.__ht)
736
+ // }
737
+ // this.e = clone ? prototype.__cn.cloneNode(true) : makeEl(prototype.__ht)
738
+ // }
739
+
740
+ // proto.__bd = function(prototype) {
741
+ // this.e = makeEl(prototype.__ht)
742
+ // }
743
+
744
+ /**
745
+ * Returns a regular wrapper around element at path, where path is an array of indices.
746
+ * This is used by the babel plugin.
747
+ */
748
+ proto.__gw = function(path) {
749
+ return new Wrapper(this.__fe(path))
750
+ };
751
+
752
+ /**
753
+ * Finds an element at specified path, where path is an array of indices.
754
+ * This is used by the babel plugin.
755
+ */
756
+ proto.__fe = function(path) {
757
+ return path.reduce((acc, index) => acc.childNodes[index], this.e)
758
+ };
759
+
760
+ /**
761
+ * Is Attached.
762
+ * Determines whether this component is attached to the DOM.
763
+ */
764
+ proto.__ia = function() {
765
+ let e = this.e;
766
+ while (e) {
767
+ if (e === document) {
768
+ return true
769
+ }
770
+ e = e.parentNode;
771
+ }
772
+ return false
773
+ };
774
+
775
+ /**
776
+ * Creates a lookup.
777
+ */
778
+ proto.__lu = function(callbacks) {
779
+ return new Lookup(callbacks)
780
+ };
781
+
782
+ /**
783
+ * Creates an anonymous stub component class
784
+ */
785
+ proto.__sv = function() {
786
+ const cls = function(parent) {
787
+ Component.call(this, parent);
788
+ };
789
+ cls.prototype = new Component();
790
+ return cls
791
+ };
792
+
793
+ /**
794
+ * Toggles visibility, like wrapper.
795
+ */
796
+ proto.visible = function(visible) {
797
+ this.e.classList.toggle('hidden', !visible);
798
+ };
799
+
800
+ module.exports = {
801
+ createComponent,
802
+ h,
803
+ mount,
804
+ KeyedPool,
805
+ InstancePool,
806
+ isStr,
807
+ SequentialPool,
808
+ Component,
809
+ Wrapper,
810
+ wrap
811
+ };