wallace 0.0.7 → 0.1.0
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/lib/component.js +54 -15
- package/lib/index.js +13 -16
- package/lib/initCalls.js +44 -52
- package/lib/{pool.js → repeaters.js} +38 -43
- package/lib/types.d.ts +1635 -26
- package/lib/utils.js +30 -32
- package/package.json +4 -4
- package/lib/lookup.js +0 -62
package/lib/component.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
const ALWAYS_UPDATE = "__";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* The base component.
|
|
3
5
|
*/
|
|
4
|
-
export function Component(
|
|
5
|
-
this.
|
|
6
|
+
export function Component() {
|
|
7
|
+
this.ctrl = undefined; // The controller.
|
|
6
8
|
this.props = undefined; // The props passed to the component. May be changed.
|
|
7
9
|
this.el = null; // the element - will be set during build.
|
|
8
10
|
this.ref = {}; // user set references to elements or components.
|
|
9
11
|
// Internal state objects
|
|
10
12
|
this._e = {}; // The dynamic elements in the DOM.
|
|
11
|
-
this._p = {}; // The previous values for watches to compare against.
|
|
12
13
|
this._s = []; // A stash for misc objects.
|
|
14
|
+
this._p = {}; // The previous values for watches to compare against.
|
|
15
|
+
this._r = {}; // The current values read during an update.
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
Component.stubs = {};
|
|
19
|
+
|
|
15
20
|
var proto = Component.prototype;
|
|
16
21
|
|
|
17
22
|
Object.defineProperty(proto, "hidden", {
|
|
@@ -20,11 +25,50 @@ Object.defineProperty(proto, "hidden", {
|
|
|
20
25
|
},
|
|
21
26
|
});
|
|
22
27
|
|
|
28
|
+
proto._gs = function (name) {
|
|
29
|
+
return this.constructor.stubs[name];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Reads a query during update, returns an array with (oldValue, newValue, changed)
|
|
34
|
+
* and saves the old value. Must reset this._r before each run.
|
|
35
|
+
*/
|
|
36
|
+
proto._rq = function (props, key) {
|
|
37
|
+
const run = this._r;
|
|
38
|
+
if (run[key] === undefined) {
|
|
39
|
+
let oldValue = this._p[key];
|
|
40
|
+
const newValue = this._q[key](props, this);
|
|
41
|
+
this._p[key] = newValue;
|
|
42
|
+
const rtn = [newValue, oldValue, newValue !== oldValue];
|
|
43
|
+
run[key] = rtn;
|
|
44
|
+
return rtn;
|
|
45
|
+
}
|
|
46
|
+
return run[key];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Applies the callbacks.
|
|
51
|
+
*/
|
|
52
|
+
proto._ac = function (props, element, callbacks) {
|
|
53
|
+
for (let key in callbacks) {
|
|
54
|
+
let callback = callbacks[key];
|
|
55
|
+
if (key === ALWAYS_UPDATE) {
|
|
56
|
+
callback(element, props, this);
|
|
57
|
+
} else {
|
|
58
|
+
const result = this._rq(props, key);
|
|
59
|
+
if (result[2]) {
|
|
60
|
+
callback(result[0], result[1], element, props, this);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
23
66
|
/**
|
|
24
|
-
*
|
|
67
|
+
* The render function that gets called by parent components.
|
|
25
68
|
*/
|
|
26
|
-
proto.render = function (props) {
|
|
69
|
+
proto.render = function (props, ctrl) {
|
|
27
70
|
this.props = props;
|
|
71
|
+
this.ctrl = ctrl;
|
|
28
72
|
this.update();
|
|
29
73
|
};
|
|
30
74
|
|
|
@@ -39,10 +83,8 @@ proto.update = function () {
|
|
|
39
83
|
parent,
|
|
40
84
|
displayToggle,
|
|
41
85
|
detacher,
|
|
42
|
-
lookupReturn,
|
|
43
86
|
lookupTrue,
|
|
44
87
|
shouldBeVisible,
|
|
45
|
-
visibilityChanged,
|
|
46
88
|
detachedElements,
|
|
47
89
|
detachedElement,
|
|
48
90
|
index,
|
|
@@ -50,11 +92,10 @@ proto.update = function () {
|
|
|
50
92
|
thisElement;
|
|
51
93
|
|
|
52
94
|
const watches = this._w;
|
|
53
|
-
const lookup = this._l;
|
|
54
95
|
const props = this.props;
|
|
55
|
-
lookup.reset();
|
|
56
96
|
const il = watches.length;
|
|
57
|
-
|
|
97
|
+
this._r = {};
|
|
98
|
+
/*
|
|
58
99
|
Watches is an array of objects with keys:
|
|
59
100
|
e: the element reference (string)
|
|
60
101
|
c: the callbacks (object)
|
|
@@ -78,10 +119,8 @@ proto.update = function () {
|
|
|
78
119
|
i++;
|
|
79
120
|
shouldBeVisible = true;
|
|
80
121
|
if (displayToggle) {
|
|
81
|
-
|
|
82
|
-
lookupTrue = !!lookupReturn.n;
|
|
122
|
+
lookupTrue = !!this._rq(props, displayToggle.q)[0];
|
|
83
123
|
shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
|
|
84
|
-
visibilityChanged = lookupTrue != !!lookupReturn.o;
|
|
85
124
|
detacher = displayToggle.d;
|
|
86
125
|
if (detacher) {
|
|
87
126
|
index = detacher.i;
|
|
@@ -96,7 +135,7 @@ proto.update = function () {
|
|
|
96
135
|
}).length;
|
|
97
136
|
parent.insertBefore(
|
|
98
137
|
detachedElement,
|
|
99
|
-
parent.childNodes[adjustedIndex]
|
|
138
|
+
parent.childNodes[adjustedIndex]
|
|
100
139
|
);
|
|
101
140
|
detachedElements[index] = null;
|
|
102
141
|
} else if (!shouldBeVisible && !detachedElement) {
|
|
@@ -112,7 +151,7 @@ proto.update = function () {
|
|
|
112
151
|
}
|
|
113
152
|
}
|
|
114
153
|
if (shouldBeVisible) {
|
|
115
|
-
|
|
154
|
+
this._ac(props, element, watch.c);
|
|
116
155
|
}
|
|
117
156
|
}
|
|
118
157
|
};
|
package/lib/index.js
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mount, watch } from "./utils";
|
|
2
2
|
import { Component } from "./component";
|
|
3
|
-
import {
|
|
3
|
+
import { KeyedRepeater, SequentialRepeater } from "./repeaters";
|
|
4
4
|
import {
|
|
5
5
|
extendComponent,
|
|
6
|
+
defineComponent,
|
|
6
7
|
findElement,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
getKeyedRepeater,
|
|
9
|
+
getSequentialRepeater,
|
|
9
10
|
onEvent,
|
|
10
11
|
nestComponent,
|
|
11
|
-
defineComponent,
|
|
12
|
-
extendPrototype,
|
|
13
|
-
stashMisc,
|
|
14
12
|
saveRef,
|
|
13
|
+
stashMisc,
|
|
15
14
|
} from "./initCalls";
|
|
16
15
|
|
|
17
16
|
export {
|
|
18
|
-
extendComponent,
|
|
19
17
|
Component,
|
|
20
|
-
createComponent,
|
|
21
|
-
createProxy,
|
|
22
18
|
defineComponent,
|
|
23
|
-
|
|
19
|
+
extendComponent,
|
|
24
20
|
findElement,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
getKeyedRepeater,
|
|
22
|
+
getSequentialRepeater,
|
|
23
|
+
KeyedRepeater,
|
|
28
24
|
mount,
|
|
29
25
|
nestComponent,
|
|
30
26
|
onEvent,
|
|
31
|
-
stashMisc,
|
|
32
27
|
saveRef,
|
|
33
|
-
|
|
28
|
+
SequentialRepeater,
|
|
29
|
+
stashMisc,
|
|
30
|
+
watch,
|
|
34
31
|
};
|
package/lib/initCalls.js
CHANGED
|
@@ -1,106 +1,98 @@
|
|
|
1
1
|
import { Component } from "./component";
|
|
2
|
-
import { Lookup } from "./lookup";
|
|
3
2
|
import { buildComponent, replaceNode } from "./utils";
|
|
4
|
-
import {
|
|
3
|
+
import { KeyedRepeater, SequentialRepeater } from "./repeaters";
|
|
5
4
|
const throwAway = document.createElement("template");
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* Create an element from html string
|
|
7
|
+
* Create an element from html string.
|
|
9
8
|
*/
|
|
10
9
|
function makeEl(html) {
|
|
11
10
|
throwAway.innerHTML = html;
|
|
12
11
|
return throwAway.content.firstChild;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
export
|
|
16
|
-
return component.props;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const findElement = (rootElement, path) => {
|
|
14
|
+
export function findElement(rootElement, path) {
|
|
20
15
|
return path.reduce((acc, index) => acc.childNodes[index], rootElement);
|
|
21
|
-
}
|
|
16
|
+
}
|
|
22
17
|
|
|
23
|
-
export
|
|
18
|
+
export function nestComponent(rootElement, path, cls) {
|
|
24
19
|
const el = findElement(rootElement, path),
|
|
25
|
-
child = buildComponent(cls
|
|
20
|
+
child = buildComponent(cls);
|
|
26
21
|
replaceNode(el, child.el);
|
|
27
22
|
return child;
|
|
28
|
-
}
|
|
23
|
+
}
|
|
29
24
|
|
|
30
25
|
/**
|
|
31
26
|
* Saves a reference to element or nested component. Returns the element.
|
|
32
27
|
*/
|
|
33
|
-
export
|
|
28
|
+
export function saveRef(element, component, name) {
|
|
34
29
|
component.ref[name] = element;
|
|
35
30
|
return element;
|
|
36
|
-
}
|
|
31
|
+
}
|
|
37
32
|
|
|
38
33
|
/**
|
|
39
34
|
* Stash something on the component. Returns the element.
|
|
40
35
|
* The generated code is expected to keep track of the position.
|
|
41
36
|
*/
|
|
42
|
-
export
|
|
37
|
+
export function stashMisc(element, component, object) {
|
|
43
38
|
component._s.push(object);
|
|
44
39
|
return element;
|
|
45
|
-
}
|
|
40
|
+
}
|
|
46
41
|
|
|
47
|
-
export
|
|
42
|
+
export function onEvent(element, eventName, callback) {
|
|
48
43
|
element.addEventListener(eventName, callback);
|
|
49
44
|
return element;
|
|
50
|
-
}
|
|
45
|
+
}
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export const getKeyedPool = (cls, keyFn) => {
|
|
56
|
-
return new KeyedPool(cls, keyFn);
|
|
57
|
-
};
|
|
47
|
+
export function getKeyedRepeater(cls, keyFn) {
|
|
48
|
+
return new KeyedRepeater(cls, keyFn);
|
|
49
|
+
}
|
|
58
50
|
|
|
59
|
-
export
|
|
60
|
-
return new
|
|
61
|
-
}
|
|
51
|
+
export function getSequentialRepeater(cls) {
|
|
52
|
+
return new SequentialRepeater(cls);
|
|
53
|
+
}
|
|
62
54
|
|
|
63
|
-
export function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
prototypeExtras,
|
|
70
|
-
) {
|
|
71
|
-
const Constructor = extendPrototype(
|
|
72
|
-
inheritFrom || Component,
|
|
73
|
-
prototypeExtras,
|
|
74
|
-
);
|
|
75
|
-
extendComponent(Constructor.prototype, html, watches, lookups, buildFunction);
|
|
76
|
-
return Constructor;
|
|
55
|
+
export function extendComponent(base, componentDef) {
|
|
56
|
+
// This function call will have been replaced if 2nd arg is a valid component func.
|
|
57
|
+
// and therefor we would not receive it.
|
|
58
|
+
if (componentDef)
|
|
59
|
+
throw new Error("2nd arg to extendComponent must be a JSX arrow function");
|
|
60
|
+
return _createConstructor(base);
|
|
77
61
|
}
|
|
78
62
|
|
|
79
|
-
export function
|
|
80
|
-
prototype,
|
|
63
|
+
export function defineComponent(
|
|
81
64
|
html,
|
|
82
65
|
watches,
|
|
83
|
-
|
|
66
|
+
queries,
|
|
84
67
|
buildFunction,
|
|
68
|
+
inheritFrom
|
|
85
69
|
) {
|
|
70
|
+
const ComponentDefinition = _createConstructor(inheritFrom || Component);
|
|
71
|
+
const prototype = ComponentDefinition.prototype;
|
|
86
72
|
//Ensure these do not clash with fields on the component itself.
|
|
87
73
|
prototype._w = watches;
|
|
88
|
-
prototype.
|
|
74
|
+
prototype._q = queries;
|
|
89
75
|
prototype._b = buildFunction;
|
|
90
76
|
prototype._n = makeEl(html);
|
|
77
|
+
return ComponentDefinition;
|
|
91
78
|
}
|
|
92
79
|
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
base.call(this
|
|
80
|
+
function _createConstructor(base) {
|
|
81
|
+
const ComponentDefinition = function () {
|
|
82
|
+
base.call(this);
|
|
83
|
+
};
|
|
84
|
+
ComponentDefinition.stubs = {};
|
|
85
|
+
Object.assign(ComponentDefinition.stubs, base.stubs);
|
|
86
|
+
// This is a helper function for the user.
|
|
87
|
+
ComponentDefinition.methods = function (obj) {
|
|
88
|
+
Object.assign(ComponentDefinition.prototype, obj);
|
|
96
89
|
};
|
|
97
|
-
|
|
90
|
+
ComponentDefinition.prototype = Object.create(base && base.prototype, {
|
|
98
91
|
constructor: {
|
|
99
|
-
value:
|
|
92
|
+
value: ComponentDefinition,
|
|
100
93
|
writable: true,
|
|
101
94
|
configurable: true,
|
|
102
95
|
},
|
|
103
96
|
});
|
|
104
|
-
|
|
105
|
-
return Constructor;
|
|
97
|
+
return ComponentDefinition;
|
|
106
98
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildComponent } from "./utils";
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* Gets a component from the pool.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
function getComponent(pool, componentDefinition, ctrl, key, props) {
|
|
7
7
|
let component;
|
|
8
8
|
if (pool.hasOwnProperty(key)) {
|
|
9
9
|
component = pool[key];
|
|
10
|
-
component.render(item);
|
|
11
10
|
} else {
|
|
12
|
-
component =
|
|
11
|
+
component = buildComponent(componentDefinition);
|
|
13
12
|
pool[key] = component;
|
|
14
13
|
}
|
|
14
|
+
component.render(props, ctrl);
|
|
15
15
|
return component;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Trims the unwanted child elements from the end.
|
|
@@ -44,29 +44,27 @@ function pull(arr, item, to) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* Must not be shared.
|
|
47
|
+
* Repeats nested components, reusing items based on key.
|
|
49
48
|
*
|
|
50
|
-
* @param {
|
|
51
|
-
* @param {function} keyFn - A function which obtains the key
|
|
49
|
+
* @param {function} componentDefinition - The ComponentDefinition to create.
|
|
50
|
+
* @param {function} keyFn - A function which obtains the key.
|
|
52
51
|
*/
|
|
53
|
-
export function
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
52
|
+
export function KeyedRepeater(componentDefinition, keyFn) {
|
|
53
|
+
this.def = componentDefinition;
|
|
54
|
+
this.keyFn = keyFn;
|
|
55
|
+
this.keys = []; // keys
|
|
56
|
+
this.pool = {}; // pool of component instances
|
|
58
57
|
}
|
|
59
|
-
const proto =
|
|
58
|
+
const proto = KeyedRepeater.prototype;
|
|
60
59
|
|
|
61
60
|
/**
|
|
62
61
|
* Retrieves a single component. Though not used in wallace itself, it may
|
|
63
62
|
* be used elsewhere, such as in the router.
|
|
64
63
|
*
|
|
65
64
|
* @param {Object} item - The item which will be passed as props.
|
|
66
|
-
* @param {Component} parent - The parent component.
|
|
67
65
|
*/
|
|
68
|
-
proto.getOne = function (item,
|
|
69
|
-
return getComponent(this.
|
|
66
|
+
proto.getOne = function (item, ctrl) {
|
|
67
|
+
return getComponent(this.pool, this.def, ctrl, this.keyFn(item), item);
|
|
70
68
|
};
|
|
71
69
|
|
|
72
70
|
/**
|
|
@@ -75,17 +73,16 @@ proto.getOne = function (item, parent) {
|
|
|
75
73
|
*
|
|
76
74
|
* @param {DOMElement} e - The DOM element to patch.
|
|
77
75
|
* @param {Array} items - Array of items which will be passed as props.
|
|
78
|
-
* @param {Component} parent - The parent component.
|
|
79
76
|
*/
|
|
80
|
-
proto.patch = function (e, items,
|
|
77
|
+
proto.patch = function (e, items, ctrl) {
|
|
81
78
|
// Attempt to speed up by reducing lookups. Does this even do anything?
|
|
82
79
|
// Does webpack undo this/do it for for me? Does the engine?
|
|
83
|
-
const pool = this.
|
|
84
|
-
const
|
|
85
|
-
const keyFn = this.
|
|
80
|
+
const pool = this.pool;
|
|
81
|
+
const componentDefinition = this.def;
|
|
82
|
+
const keyFn = this.keyFn;
|
|
86
83
|
const childNodes = e.childNodes;
|
|
87
84
|
const itemsLength = items.length;
|
|
88
|
-
const oldKeySequence = this.
|
|
85
|
+
const oldKeySequence = this.keys;
|
|
89
86
|
const newKeys = [];
|
|
90
87
|
let item,
|
|
91
88
|
key,
|
|
@@ -94,7 +91,7 @@ proto.patch = function (e, items, parent) {
|
|
|
94
91
|
for (let i = 0; i < itemsLength; i++) {
|
|
95
92
|
item = items[i];
|
|
96
93
|
key = keyFn(item);
|
|
97
|
-
component = getComponent(pool,
|
|
94
|
+
component = getComponent(pool, componentDefinition, ctrl, key, item);
|
|
98
95
|
newKeys.push(key);
|
|
99
96
|
if (i > childElementCount) {
|
|
100
97
|
e.appendChild(component.el);
|
|
@@ -103,19 +100,19 @@ proto.patch = function (e, items, parent) {
|
|
|
103
100
|
pull(oldKeySequence, key, i);
|
|
104
101
|
}
|
|
105
102
|
}
|
|
106
|
-
this.
|
|
103
|
+
this.keys = newKeys;
|
|
107
104
|
trimChildren(e, childNodes, itemsLength);
|
|
108
105
|
};
|
|
109
106
|
|
|
110
107
|
/**
|
|
111
|
-
*
|
|
108
|
+
* Repeats nested components, yielding from its pool sequentially.
|
|
112
109
|
*
|
|
113
|
-
* @param {
|
|
110
|
+
* @param {componentDefinition} componentDefinition - The class ComponentDefinition to create.
|
|
114
111
|
*/
|
|
115
|
-
export function
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
112
|
+
export function SequentialRepeater(componentDefinition) {
|
|
113
|
+
this.def = componentDefinition;
|
|
114
|
+
this.pool = []; // pool of component instances
|
|
115
|
+
this.count = 0; // Child element count
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
/**
|
|
@@ -124,32 +121,30 @@ export function SequentialPool(componentClass) {
|
|
|
124
121
|
*
|
|
125
122
|
* @param {DOMElement} e - The DOM element to patch.
|
|
126
123
|
* @param {Array} items - Array of items which will be passed as props.
|
|
127
|
-
* @param {
|
|
124
|
+
* @param {any} ctrl - The parent item's controller.
|
|
128
125
|
*/
|
|
129
|
-
|
|
130
|
-
const pool = this.
|
|
131
|
-
const
|
|
126
|
+
SequentialRepeater.prototype.patch = function (e, items, ctrl) {
|
|
127
|
+
const pool = this.pool;
|
|
128
|
+
const componentDefinition = this.def;
|
|
132
129
|
const childNodes = e.childNodes;
|
|
133
130
|
const itemsLength = items.length;
|
|
134
|
-
let
|
|
135
|
-
component,
|
|
131
|
+
let component,
|
|
136
132
|
poolCount = pool.length,
|
|
137
|
-
childElementCount = this.
|
|
133
|
+
childElementCount = this.count;
|
|
138
134
|
|
|
139
135
|
for (let i = 0; i < itemsLength; i++) {
|
|
140
|
-
item = items[i];
|
|
141
136
|
if (i < poolCount) {
|
|
142
137
|
component = pool[i];
|
|
143
|
-
component.render(item);
|
|
144
138
|
} else {
|
|
145
|
-
component =
|
|
139
|
+
component = buildComponent(componentDefinition);
|
|
146
140
|
pool.push(component);
|
|
147
141
|
poolCount++;
|
|
148
142
|
}
|
|
143
|
+
component.render(items[i], ctrl);
|
|
149
144
|
if (i >= childElementCount) {
|
|
150
145
|
e.appendChild(component.el);
|
|
151
146
|
}
|
|
152
147
|
}
|
|
153
|
-
this.
|
|
148
|
+
this.count = itemsLength;
|
|
154
149
|
trimChildren(e, childNodes, itemsLength);
|
|
155
150
|
};
|