wallace 0.7.2 → 0.10.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 +99 -115
- package/lib/createComponent.js +5 -0
- package/lib/extend.js +4 -2
- package/lib/index.js +3 -1
- package/lib/part.js +17 -0
- package/lib/refs.js +2 -14
- package/lib/repeaters/keyed.js +53 -64
- package/lib/repeaters/sequential.js +14 -10
- package/lib/router.js +1 -1
- package/lib/types.d.ts +113 -37
- package/lib/utils.js +0 -15
- package/package.json +4 -4
- /package/lib/{nest.js → nestComponent.js} +0 -0
package/lib/component.js
CHANGED
|
@@ -1,42 +1,40 @@
|
|
|
1
1
|
const throwAway = document.createElement("template");
|
|
2
2
|
const NO_LOOKUP = "__";
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.update();
|
|
14
|
-
},
|
|
4
|
+
const ComponentPrototype = {
|
|
5
|
+
/**
|
|
6
|
+
* The render function that gets called by parent components.
|
|
7
|
+
*/
|
|
8
|
+
render: function (props, ctrl) {
|
|
9
|
+
this.props = props;
|
|
10
|
+
this.ctrl = ctrl;
|
|
11
|
+
this.update();
|
|
12
|
+
},
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Updates the DOM and renders nested components.
|
|
16
|
+
*/
|
|
17
|
+
update: function () {
|
|
18
|
+
this._u(0, this._l);
|
|
19
|
+
},
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
_u: function (i, il) {
|
|
22
|
+
let watch,
|
|
23
|
+
element,
|
|
24
|
+
parent,
|
|
25
|
+
displayToggle,
|
|
26
|
+
detacher,
|
|
27
|
+
lookupTrue,
|
|
28
|
+
shouldBeVisible,
|
|
29
|
+
detachedElements,
|
|
30
|
+
detachedElement,
|
|
31
|
+
index,
|
|
32
|
+
adjustedIndex;
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const watches = this._w,
|
|
35
|
+
props = this.props,
|
|
36
|
+
previous = this._p;
|
|
37
|
+
/*
|
|
40
38
|
Watches is an array of objects with keys:
|
|
41
39
|
e: the element index (number)
|
|
42
40
|
c: the callbacks (object)
|
|
@@ -56,94 +54,87 @@ const ComponentBase = {
|
|
|
56
54
|
s: the stash key of the detacher (plain object)
|
|
57
55
|
e: the parent element key
|
|
58
56
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
element.hidden = !shouldBeVisible;
|
|
87
|
-
}
|
|
88
|
-
if (!shouldBeVisible) {
|
|
89
|
-
i += displayToggle.s;
|
|
57
|
+
while (i < il) {
|
|
58
|
+
watch = watches[i];
|
|
59
|
+
element = this._e[watch.e];
|
|
60
|
+
displayToggle = watch.v;
|
|
61
|
+
shouldBeVisible = true;
|
|
62
|
+
if (displayToggle) {
|
|
63
|
+
lookupTrue = !!this._q[displayToggle.q](props, this);
|
|
64
|
+
shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
|
|
65
|
+
detacher = displayToggle.d;
|
|
66
|
+
if (detacher) {
|
|
67
|
+
index = detacher.i;
|
|
68
|
+
parent = this._e[detacher.e];
|
|
69
|
+
detachedElements = this._s[detacher.s];
|
|
70
|
+
detachedElement = detachedElements[index];
|
|
71
|
+
if (shouldBeVisible && detachedElement) {
|
|
72
|
+
adjustedIndex =
|
|
73
|
+
index -
|
|
74
|
+
Object.keys(detachedElements).filter(function (k) {
|
|
75
|
+
return k < index && detachedElements[k];
|
|
76
|
+
}).length;
|
|
77
|
+
parent.insertBefore(detachedElement, parent.childNodes[adjustedIndex]);
|
|
78
|
+
detachedElements[index] = null;
|
|
79
|
+
} else if (!shouldBeVisible && !detachedElement) {
|
|
80
|
+
parent.removeChild(element);
|
|
81
|
+
detachedElements[index] = element;
|
|
90
82
|
}
|
|
83
|
+
} else {
|
|
84
|
+
element.hidden = !shouldBeVisible;
|
|
91
85
|
}
|
|
92
|
-
if (shouldBeVisible) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
86
|
+
if (!shouldBeVisible) {
|
|
87
|
+
i += displayToggle.s;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (shouldBeVisible) {
|
|
91
|
+
const prev = previous[i],
|
|
92
|
+
callbacks = watch.c;
|
|
93
|
+
for (let key in callbacks) {
|
|
94
|
+
if (key === NO_LOOKUP) {
|
|
95
|
+
callbacks[key](element, props, this);
|
|
96
|
+
} else {
|
|
97
|
+
const oldValue = prev[key],
|
|
98
|
+
newValue = this._q[key](props, this);
|
|
99
|
+
if (oldValue !== newValue) {
|
|
100
|
+
callbacks[key](element, props, this, newValue);
|
|
101
|
+
prev[key] = newValue;
|
|
105
102
|
}
|
|
106
103
|
}
|
|
107
104
|
}
|
|
108
|
-
i++;
|
|
109
105
|
}
|
|
106
|
+
i++;
|
|
110
107
|
}
|
|
111
108
|
}
|
|
112
109
|
};
|
|
113
110
|
|
|
114
|
-
Object.defineProperty(
|
|
111
|
+
Object.defineProperty(ComponentPrototype, "hidden", {
|
|
115
112
|
set: function (value) {
|
|
116
113
|
this.el.hidden = value;
|
|
117
114
|
}
|
|
118
115
|
});
|
|
119
116
|
|
|
117
|
+
const ComponentBase = {
|
|
118
|
+
stubs: {},
|
|
119
|
+
prototype: ComponentPrototype
|
|
120
|
+
};
|
|
121
|
+
|
|
120
122
|
/**
|
|
121
|
-
* Creates the constructor function for a component definition.
|
|
122
123
|
*
|
|
123
|
-
* @param {
|
|
124
|
-
* @
|
|
124
|
+
* @param {function} ComponentFunction - The Component definition function to add bits to.
|
|
125
|
+
* @param {function} BaseComponentFunction - A Component definition function to inherit bits from.
|
|
126
|
+
* @returns the ComponentFunction with bits added.
|
|
125
127
|
*/
|
|
126
|
-
export function
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.ctrl = {};
|
|
134
|
-
this.props = {};
|
|
135
|
-
this._l = this._w.length;
|
|
136
|
-
this._b(this, root, dynamicElements, stash, previous, refs);
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const proto = (Component.prototype = Object.create(baseComponent.prototype, {
|
|
140
|
-
constructor: {
|
|
141
|
-
value: Component
|
|
128
|
+
export function initConstructor(ComponentFunction, BaseComponentFunction) {
|
|
129
|
+
const proto = (ComponentFunction.prototype = Object.create(
|
|
130
|
+
BaseComponentFunction.prototype,
|
|
131
|
+
{
|
|
132
|
+
constructor: {
|
|
133
|
+
value: ComponentFunction
|
|
134
|
+
}
|
|
142
135
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// This lets us assign to prototype without replacing it.
|
|
146
|
-
Object.defineProperty(Component, "methods", {
|
|
136
|
+
));
|
|
137
|
+
Object.defineProperty(ComponentFunction, "methods", {
|
|
147
138
|
set: function (value) {
|
|
148
139
|
Object.assign(proto, value);
|
|
149
140
|
},
|
|
@@ -151,24 +142,17 @@ export function createConstructor(baseComponent) {
|
|
|
151
142
|
return proto;
|
|
152
143
|
}
|
|
153
144
|
});
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
component.render(props, ctrl);
|
|
157
|
-
return component;
|
|
158
|
-
};
|
|
159
|
-
Component.stubs = Object.assign({}, baseComponent.stubs);
|
|
160
|
-
return Component;
|
|
145
|
+
ComponentFunction.stubs = Object.assign({}, BaseComponentFunction.stubs);
|
|
146
|
+
return ComponentFunction;
|
|
161
147
|
}
|
|
162
148
|
|
|
163
|
-
export function defineComponent(html, watches, queries,
|
|
164
|
-
const ComponentDefinition =
|
|
149
|
+
export function defineComponent(html, watches, queries, contructor, inheritFrom) {
|
|
150
|
+
const ComponentDefinition = initConstructor(contructor, inheritFrom || ComponentBase);
|
|
165
151
|
const proto = ComponentDefinition.prototype;
|
|
166
152
|
throwAway.innerHTML = html;
|
|
167
|
-
//Ensure these do not clash with fields on the component itself.
|
|
168
153
|
proto._w = watches;
|
|
169
154
|
proto._q = queries;
|
|
170
|
-
proto.
|
|
171
|
-
proto.
|
|
172
|
-
proto.base = ComponentBase.prototype;
|
|
155
|
+
proto._t = throwAway.content.firstChild;
|
|
156
|
+
proto.base = ComponentPrototype;
|
|
173
157
|
return ComponentDefinition;
|
|
174
158
|
}
|
package/lib/extend.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { initConstructor } from "./component";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Calls to this function which provide the 2nd argument:
|
|
@@ -16,5 +16,7 @@ export function extendComponent(base, componentDef) {
|
|
|
16
16
|
// and therefore we would not receive it.
|
|
17
17
|
if (componentDef)
|
|
18
18
|
throw new Error("2nd arg to extendComponent must be a JSX arrow function");
|
|
19
|
-
return
|
|
19
|
+
return initConstructor(function () {
|
|
20
|
+
base.call(this);
|
|
21
|
+
}, base);
|
|
20
22
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { defineComponent } from "./component";
|
|
2
2
|
export { extendComponent } from "./extend";
|
|
3
3
|
export { mount } from "./mount";
|
|
4
|
-
export {
|
|
4
|
+
export { createComponent } from "./createComponent";
|
|
5
|
+
export { nestComponent } from "./nestComponent";
|
|
5
6
|
export { saveRef } from "./refs";
|
|
7
|
+
export { savePart } from "./part";
|
|
6
8
|
export { KeyedRepeater } from "./repeaters/keyed";
|
|
7
9
|
export { SequentialRepeater } from "./repeaters/sequential";
|
|
8
10
|
export { Router, route } from "./router";
|
package/lib/part.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function Part(component, start, end) {
|
|
2
|
+
this._c = component;
|
|
3
|
+
this._s = start;
|
|
4
|
+
this._e = end;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
Part.prototype.update = function () {
|
|
8
|
+
this._c._u(this._s, this._e);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Saves a reference to a part of a component so it can be updated independently.
|
|
13
|
+
*/
|
|
14
|
+
export function savePart(node, component, parts, name, start, end) {
|
|
15
|
+
parts[name] = new Part(component, start, end);
|
|
16
|
+
return node;
|
|
17
|
+
}
|
package/lib/refs.js
CHANGED
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
function Ref(component, node, start, end) {
|
|
2
|
-
this.node = node;
|
|
3
|
-
this._c = component;
|
|
4
|
-
this._s = start;
|
|
5
|
-
this._e = end;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
Ref.prototype.update = function () {
|
|
9
|
-
this._c._u(this._s, this._e);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
1
|
/**
|
|
13
2
|
* Saves a reference to a node (element or nested component)
|
|
14
3
|
* Returns the node.
|
|
15
4
|
*/
|
|
16
|
-
export function saveRef(node,
|
|
17
|
-
refs[name] =
|
|
18
|
-
return node;
|
|
5
|
+
export function saveRef(node, refs, name) {
|
|
6
|
+
return (refs[name] = node);
|
|
19
7
|
}
|
package/lib/repeaters/keyed.js
CHANGED
|
@@ -1,33 +1,3 @@
|
|
|
1
|
-
import { trimChildren } from "../utils";
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* Gets a component from the pool.
|
|
5
|
-
*/
|
|
6
|
-
function getComponent(pool, componentDefinition, ctrl, key, props) {
|
|
7
|
-
let component;
|
|
8
|
-
if (pool.hasOwnProperty(key)) {
|
|
9
|
-
component = pool[key];
|
|
10
|
-
} else {
|
|
11
|
-
component = new componentDefinition();
|
|
12
|
-
pool[key] = component;
|
|
13
|
-
}
|
|
14
|
-
component.render(props, ctrl);
|
|
15
|
-
return component;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Pulls an item forward in an array, to replicate insertBefore.
|
|
20
|
-
* @param {Array} arr
|
|
21
|
-
* @param {any} item
|
|
22
|
-
* @param {Int} to
|
|
23
|
-
*/
|
|
24
|
-
function pull(arr, item, to) {
|
|
25
|
-
const position = arr.indexOf(item);
|
|
26
|
-
if (position != to) {
|
|
27
|
-
arr.splice(to, 0, arr.splice(position, 1)[0]);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
1
|
/**
|
|
32
2
|
* Repeats nested components, reusing items based on key.
|
|
33
3
|
*
|
|
@@ -37,20 +7,9 @@ function pull(arr, item, to) {
|
|
|
37
7
|
export function KeyedRepeater(componentDefinition, keyFn) {
|
|
38
8
|
this.def = componentDefinition;
|
|
39
9
|
this.keyFn = keyFn;
|
|
40
|
-
this.keys = []; // keys
|
|
41
|
-
this.pool = {}; // pool of component instances
|
|
10
|
+
this.keys = []; // array of keys as last set.
|
|
11
|
+
this.pool = {}; // pool of component instances.
|
|
42
12
|
}
|
|
43
|
-
const proto = KeyedRepeater.prototype;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Retrieves a single component. Though not used in wallace itself, it may
|
|
47
|
-
* be used elsewhere, such as in the router.
|
|
48
|
-
*
|
|
49
|
-
* @param {Object} item - The item which will be passed as props.
|
|
50
|
-
*/
|
|
51
|
-
proto.getOne = function (item, ctrl) {
|
|
52
|
-
return getComponent(this.pool, this.def, ctrl, this.keyFn(item), item);
|
|
53
|
-
};
|
|
54
13
|
|
|
55
14
|
/**
|
|
56
15
|
* Updates the element's childNodes to match the items.
|
|
@@ -58,33 +17,63 @@ proto.getOne = function (item, ctrl) {
|
|
|
58
17
|
*
|
|
59
18
|
* @param {DOMElement} e - The DOM element to patch.
|
|
60
19
|
* @param {Array} items - Array of items which will be passed as props.
|
|
20
|
+
* @param {any} ctrl - The parent item's controller.
|
|
61
21
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
22
|
+
KeyedRepeater.prototype.patch = function (e, items, ctrl) {
|
|
23
|
+
const pool = this.pool,
|
|
24
|
+
componentDefinition = this.def,
|
|
25
|
+
keyFn = this.keyFn,
|
|
26
|
+
childNodes = e.childNodes,
|
|
27
|
+
itemsLength = items.length,
|
|
28
|
+
previousKeys = this.keys,
|
|
29
|
+
previousKeysLength = previousKeys.length,
|
|
30
|
+
newKeys = [],
|
|
31
|
+
previousKeysSet = new Set(previousKeys);
|
|
72
32
|
let item,
|
|
33
|
+
el,
|
|
73
34
|
key,
|
|
74
35
|
component,
|
|
75
|
-
|
|
76
|
-
|
|
36
|
+
anchor = null,
|
|
37
|
+
fragAnchor = null,
|
|
38
|
+
untouched = true,
|
|
39
|
+
append = false,
|
|
40
|
+
offset = previousKeysLength - itemsLength,
|
|
41
|
+
i = itemsLength - 1;
|
|
42
|
+
|
|
43
|
+
// Working backwards saves us having to track moves.
|
|
44
|
+
const frag = document.createDocumentFragment();
|
|
45
|
+
while (i >= 0) {
|
|
77
46
|
item = items[i];
|
|
78
47
|
key = keyFn(item);
|
|
79
|
-
component =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
48
|
+
component = pool[key] || (pool[key] = new componentDefinition());
|
|
49
|
+
component.render(item, ctrl);
|
|
50
|
+
el = component.el;
|
|
51
|
+
if (untouched && !previousKeysSet.has(key)) {
|
|
52
|
+
frag.insertBefore(el, fragAnchor);
|
|
53
|
+
fragAnchor = el;
|
|
54
|
+
append = true;
|
|
55
|
+
offset++;
|
|
56
|
+
} else {
|
|
57
|
+
if (key !== previousKeys[i + offset]) {
|
|
58
|
+
e.insertBefore(el, anchor);
|
|
59
|
+
untouched = false;
|
|
60
|
+
}
|
|
61
|
+
anchor = el;
|
|
86
62
|
}
|
|
63
|
+
newKeys.push(key);
|
|
64
|
+
previousKeysSet.delete(key);
|
|
65
|
+
i--;
|
|
87
66
|
}
|
|
88
|
-
|
|
89
|
-
|
|
67
|
+
|
|
68
|
+
if (append) {
|
|
69
|
+
e.appendChild(frag);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let toStrip = previousKeysSet.size;
|
|
73
|
+
while (toStrip > 0) {
|
|
74
|
+
e.removeChild(childNodes[0]);
|
|
75
|
+
toStrip--;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.keys = newKeys.reverse();
|
|
90
79
|
};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { trimChildren } from "../utils";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Repeats nested components, yielding from its pool sequentially.
|
|
5
3
|
*
|
|
@@ -20,15 +18,16 @@ export function SequentialRepeater(componentDefinition) {
|
|
|
20
18
|
* @param {any} ctrl - The parent item's controller.
|
|
21
19
|
*/
|
|
22
20
|
SequentialRepeater.prototype.patch = function (e, items, ctrl) {
|
|
23
|
-
const pool = this.pool
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let component,
|
|
28
|
-
poolCount = pool.length,
|
|
21
|
+
const pool = this.pool,
|
|
22
|
+
componentDefinition = this.def,
|
|
23
|
+
childNodes = e.childNodes,
|
|
24
|
+
itemsLength = items.length,
|
|
29
25
|
childElementCount = this.count;
|
|
26
|
+
let i = 0,
|
|
27
|
+
component,
|
|
28
|
+
poolCount = pool.length;
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
while (i < itemsLength) {
|
|
32
31
|
if (i < poolCount) {
|
|
33
32
|
component = pool[i];
|
|
34
33
|
} else {
|
|
@@ -40,7 +39,12 @@ SequentialRepeater.prototype.patch = function (e, items, ctrl) {
|
|
|
40
39
|
if (i >= childElementCount) {
|
|
41
40
|
e.appendChild(component.el);
|
|
42
41
|
}
|
|
42
|
+
i++;
|
|
43
43
|
}
|
|
44
44
|
this.count = itemsLength;
|
|
45
|
-
|
|
45
|
+
let lastIndex = childNodes.length - 1;
|
|
46
|
+
let keepIndex = itemsLength - 1;
|
|
47
|
+
for (let i = lastIndex; i > keepIndex; i--) {
|
|
48
|
+
e.removeChild(childNodes[i]);
|
|
49
|
+
}
|
|
46
50
|
};
|
package/lib/router.js
CHANGED
package/lib/types.d.ts
CHANGED
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
1. Components
|
|
12
12
|
2. JSX
|
|
13
13
|
3. Nesting
|
|
14
|
-
4.
|
|
15
|
-
5.
|
|
16
|
-
6.
|
|
17
|
-
7.
|
|
18
|
-
8.
|
|
19
|
-
9.
|
|
14
|
+
4. Repeating
|
|
15
|
+
5. Directives
|
|
16
|
+
6. Controllers
|
|
17
|
+
7. Inheritance
|
|
18
|
+
8. Stubs
|
|
19
|
+
9. TypeScript
|
|
20
|
+
10. Helpers
|
|
20
21
|
|
|
21
22
|
For more detailed documentation go to https://github.com/wallace-js/wallace
|
|
22
23
|
|
|
@@ -145,9 +146,13 @@ Component instances have the following fields:
|
|
|
145
146
|
|
|
146
147
|
- `props` the data for this component instance.
|
|
147
148
|
- `ctrl` the controller object.
|
|
148
|
-
- `refs` an object with references to node.
|
|
149
149
|
- `el` the component instance's root element.
|
|
150
150
|
|
|
151
|
+
Optionally:
|
|
152
|
+
|
|
153
|
+
- `ref` an object containing named elements or nested components.
|
|
154
|
+
- `part` an object containing named parts.
|
|
155
|
+
|
|
151
156
|
Both `props` and `ctrl` are set during the `render` method before calling `update`.
|
|
152
157
|
There are no restrictions on types but typically:
|
|
153
158
|
|
|
@@ -175,7 +180,7 @@ Other than that, its standard JSX, except for three special cases:
|
|
|
175
180
|
|
|
176
181
|
## 3. Nesting
|
|
177
182
|
|
|
178
|
-
To nest
|
|
183
|
+
To nest a component use its name followed by `.nest` and pass `props` if needed:
|
|
179
184
|
|
|
180
185
|
```tsx
|
|
181
186
|
const Task = (task) => (<div></div>);
|
|
@@ -196,11 +201,46 @@ const TaskList = (tasks) => (
|
|
|
196
201
|
|
|
197
202
|
Notes:
|
|
198
203
|
|
|
199
|
-
- You cannot use nest
|
|
204
|
+
- You cannot use nest on the root element.
|
|
205
|
+
|
|
206
|
+
## 4. Repeating
|
|
207
|
+
|
|
208
|
+
To repeat a component use its name followed by `.repeat` and pass `items`:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
const Task = (task) => (<div></div>);
|
|
212
|
+
|
|
213
|
+
const TaskList = (tasks) => (
|
|
214
|
+
<div>
|
|
215
|
+
<Task.repeat items={tasks} />
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
This form reuses components sequentially, which may cause issues with CSS animations
|
|
221
|
+
and focus, in which case you should use a keyed repeater by passing `key` which can
|
|
222
|
+
be a string or a function:
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
const TaskList = (tasks) => (
|
|
226
|
+
<div>
|
|
227
|
+
<Task.repeat items={tasks} key="id"/>
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const TaskList = (tasks) => (
|
|
232
|
+
<div>
|
|
233
|
+
<Task.repeat items={tasks} key={(x) => x.id}/>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Notes:
|
|
239
|
+
|
|
240
|
+
- You cannot repeat on the root element.
|
|
200
241
|
- Repeat must be the only child element under its parent.
|
|
201
|
-
- The `props` expects an array on repeat (See **TypeScript** below)
|
|
202
242
|
|
|
203
|
-
##
|
|
243
|
+
## 5. Directives
|
|
204
244
|
|
|
205
245
|
Directives are attributes with special behaviours.
|
|
206
246
|
|
|
@@ -213,7 +253,7 @@ temporarily change it to something `class x:danger`.
|
|
|
213
253
|
|
|
214
254
|
You can define your own directives in your babel config.
|
|
215
255
|
|
|
216
|
-
##
|
|
256
|
+
## 6. Controllers
|
|
217
257
|
|
|
218
258
|
A controller is just an object you create which gets passed down to every nested
|
|
219
259
|
component, making it a convenient place to handle:
|
|
@@ -264,7 +304,7 @@ TaskList.methods = {
|
|
|
264
304
|
};
|
|
265
305
|
```
|
|
266
306
|
|
|
267
|
-
##
|
|
307
|
+
## 7. Inheritance
|
|
268
308
|
|
|
269
309
|
You can creat new component defintion by extending another one, either preserving the
|
|
270
310
|
base's structure, or overriding it:
|
|
@@ -280,7 +320,7 @@ const Child2 = extendComponent(Parent, ({name}) => <h3>{name}</h3>);
|
|
|
280
320
|
|
|
281
321
|
Either way the new component definition inherits the parent *prototype* and *stubs*.
|
|
282
322
|
|
|
283
|
-
##
|
|
323
|
+
## 8. Stubs
|
|
284
324
|
|
|
285
325
|
Stubs are named placeholders for nested components which are requested in the JSX:
|
|
286
326
|
|
|
@@ -313,7 +353,7 @@ Notes:
|
|
|
313
353
|
- Stubs are separate components, so cannot access methods on the containing component
|
|
314
354
|
through `self` (use the controller for that kind of thing).
|
|
315
355
|
|
|
316
|
-
##
|
|
356
|
+
## 9. TypeScript
|
|
317
357
|
|
|
318
358
|
The main type is `Uses` which must be placed right after the comonent name:
|
|
319
359
|
|
|
@@ -337,7 +377,7 @@ const Task: Uses<null> = () => <div>Hello</div>;
|
|
|
337
377
|
|
|
338
378
|
### Props
|
|
339
379
|
|
|
340
|
-
TypeScript will ensure you pass correct props during mounting
|
|
380
|
+
TypeScript will ensure you pass correct props during mounting, nesting and repeating:
|
|
341
381
|
|
|
342
382
|
```
|
|
343
383
|
const TaskList: Uses<iTask[]> = (tasks) => (
|
|
@@ -349,6 +389,8 @@ const TaskList: Uses<iTask[]> = (tasks) => (
|
|
|
349
389
|
</div>
|
|
350
390
|
</div>
|
|
351
391
|
);
|
|
392
|
+
|
|
393
|
+
mount("main", TaskList, [{test: 'foo'}]);
|
|
352
394
|
```
|
|
353
395
|
|
|
354
396
|
### Controller
|
|
@@ -435,7 +477,7 @@ Wallace defines some other types you may use:
|
|
|
435
477
|
constructor, not a class)
|
|
436
478
|
- `ComponentInstance<Props, Controller, Methods>` - a component instance.
|
|
437
479
|
|
|
438
|
-
##
|
|
480
|
+
## 10. Helpers
|
|
439
481
|
|
|
440
482
|
Each of these has their own JSDoc, we just lsit them here.
|
|
441
483
|
|
|
@@ -513,10 +555,12 @@ declare module "wallace" {
|
|
|
513
555
|
}): JSX.Element;
|
|
514
556
|
repeat?({
|
|
515
557
|
items,
|
|
558
|
+
key,
|
|
516
559
|
show,
|
|
517
560
|
hide
|
|
518
561
|
}: {
|
|
519
562
|
items: Array<Props>;
|
|
563
|
+
key?: string | ((item: Props) => any);
|
|
520
564
|
show?: boolean;
|
|
521
565
|
hide?: boolean;
|
|
522
566
|
}): JSX.Element;
|
|
@@ -526,10 +570,6 @@ declare module "wallace" {
|
|
|
526
570
|
ThisType<ComponentInstance<Props, Controller, Methods>>;
|
|
527
571
|
// Methods will not be available on nested component, so omit.
|
|
528
572
|
readonly stubs?: Record<string, ComponentFunction<Props, Controller>>;
|
|
529
|
-
create?(
|
|
530
|
-
props?: Props,
|
|
531
|
-
ctrl?: Controller
|
|
532
|
-
): ComponentInstance<Props, Controller, Methods>;
|
|
533
573
|
}
|
|
534
574
|
|
|
535
575
|
type ComponenMethods<Props, Controller> = {
|
|
@@ -559,8 +599,7 @@ declare module "wallace" {
|
|
|
559
599
|
Methods extends object = {}
|
|
560
600
|
> = ComponentFunction<Props, Controller, Methods>;
|
|
561
601
|
|
|
562
|
-
export interface
|
|
563
|
-
node: HTMLElement | ComponentInstance;
|
|
602
|
+
export interface Part {
|
|
564
603
|
update(): void;
|
|
565
604
|
}
|
|
566
605
|
|
|
@@ -575,7 +614,8 @@ declare module "wallace" {
|
|
|
575
614
|
el: HTMLElement;
|
|
576
615
|
props: Props;
|
|
577
616
|
ctrl: Controller;
|
|
578
|
-
|
|
617
|
+
ref: { [key: string]: HTMLElement | ComponentInstance };
|
|
618
|
+
part: { [key: string]: Part };
|
|
579
619
|
base: Component<Props, Controller>;
|
|
580
620
|
} & Component<Props, Controller> &
|
|
581
621
|
Methods;
|
|
@@ -620,6 +660,18 @@ declare module "wallace" {
|
|
|
620
660
|
update(): void;
|
|
621
661
|
}
|
|
622
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Creates a component instance and renders it.
|
|
665
|
+
* @param def
|
|
666
|
+
* @param props
|
|
667
|
+
* @param ctrl
|
|
668
|
+
*/
|
|
669
|
+
export function createComponent<Props, Controller, Methods extends object = {}>(
|
|
670
|
+
def: ComponentFunction<Props, Controller, Methods>,
|
|
671
|
+
props?: Props,
|
|
672
|
+
ctrl?: Controller
|
|
673
|
+
): ComponentInstance<Props, Controller, Methods>;
|
|
674
|
+
|
|
623
675
|
/**
|
|
624
676
|
* Use to define a new component which extends another component, meaning it will
|
|
625
677
|
* inherit its prototye and stubs.
|
|
@@ -634,9 +686,9 @@ declare module "wallace" {
|
|
|
634
686
|
Controller = any,
|
|
635
687
|
Methods extends object = {}
|
|
636
688
|
>(
|
|
637
|
-
base:
|
|
689
|
+
base: ComponentFunction<Props, Controller, Methods>,
|
|
638
690
|
componentFunc?: ComponentFunction<Props, Controller, Methods>
|
|
639
|
-
):
|
|
691
|
+
): ComponentFunction<Props, Controller, Methods>;
|
|
640
692
|
|
|
641
693
|
/**
|
|
642
694
|
* *Replaces* element with an instance of componentDefinition and renders it.
|
|
@@ -645,7 +697,7 @@ declare module "wallace" {
|
|
|
645
697
|
*/
|
|
646
698
|
export function mount<Props = any, Controller = any, Methods extends object = {}>(
|
|
647
699
|
element: string | HTMLElement,
|
|
648
|
-
componentDefinition:
|
|
700
|
+
componentDefinition: ComponentFunction<Props, Controller, Methods>,
|
|
649
701
|
props?: Props,
|
|
650
702
|
ctrl?: Controller
|
|
651
703
|
): ComponentInstance<Props, Controller, Methods>;
|
|
@@ -868,6 +920,32 @@ interface DirectiveAttributes extends AllDomEvents {
|
|
|
868
920
|
*/
|
|
869
921
|
items?: MustBeExpression;
|
|
870
922
|
|
|
923
|
+
/** ## Wallace directive: key
|
|
924
|
+
*
|
|
925
|
+
* Specifies a key for repeated components, creating an association between the key
|
|
926
|
+
* and the nested component.
|
|
927
|
+
*
|
|
928
|
+
* You can specify a property as a string or a function.
|
|
929
|
+
*/
|
|
930
|
+
key?: any;
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* ## Wallace directive: part
|
|
934
|
+
*
|
|
935
|
+
* Saves a reference to part of a component allowing you to update it independently.
|
|
936
|
+
*
|
|
937
|
+
* ```
|
|
938
|
+
* <div part:title>
|
|
939
|
+
* {name}
|
|
940
|
+
* </div>
|
|
941
|
+
* ```
|
|
942
|
+
*
|
|
943
|
+
* ```
|
|
944
|
+
* component.part.title.update();
|
|
945
|
+
* ```
|
|
946
|
+
*/
|
|
947
|
+
part?: null;
|
|
948
|
+
|
|
871
949
|
/**
|
|
872
950
|
* ## Wallace directive: props
|
|
873
951
|
*
|
|
@@ -879,10 +957,7 @@ interface DirectiveAttributes extends AllDomEvents {
|
|
|
879
957
|
/**
|
|
880
958
|
* ## Wallace directive: ref
|
|
881
959
|
*
|
|
882
|
-
* Saves a reference to
|
|
883
|
-
*
|
|
884
|
-
* 1. Access the element or component as `ref.node`
|
|
885
|
-
* 2. Update the all nested elements using `ref.update()`.
|
|
960
|
+
* Saves a reference to an element or nested component.
|
|
886
961
|
*
|
|
887
962
|
* ```
|
|
888
963
|
* <div ref:title>
|
|
@@ -891,11 +966,8 @@ interface DirectiveAttributes extends AllDomEvents {
|
|
|
891
966
|
* ```
|
|
892
967
|
*
|
|
893
968
|
* ```
|
|
894
|
-
* component.
|
|
895
|
-
* component.refs.title.node.textContent = 'hello';
|
|
969
|
+
* component.ref.title.textContent = 'hello';
|
|
896
970
|
* ```
|
|
897
|
-
*
|
|
898
|
-
* Requires a qualifier, but you lose the tooltip in that format.
|
|
899
971
|
*/
|
|
900
972
|
ref?: null;
|
|
901
973
|
|
|
@@ -954,8 +1026,10 @@ declare namespace JSX {
|
|
|
954
1026
|
* ```
|
|
955
1027
|
* <MyComponent.nest props={singleProps} />
|
|
956
1028
|
* <MyComponent.repeat items={arrayOfProps} />
|
|
1029
|
+
* <MyComponent.repeat items={arrayOfProps} key="id"/>
|
|
1030
|
+
* <MyComponent.repeat items={arrayOfProps} key={(i) => i.id}/>
|
|
957
1031
|
* ```
|
|
958
|
-
* Note that repeated components
|
|
1032
|
+
* Note that repeated components may not have siblings.
|
|
959
1033
|
*
|
|
960
1034
|
* Available Wallace directives:
|
|
961
1035
|
*
|
|
@@ -967,10 +1041,12 @@ declare namespace JSX {
|
|
|
967
1041
|
* - `hide` sets an element or component's hidden property.
|
|
968
1042
|
* - `html` Set the element's `innnerHTML` property.
|
|
969
1043
|
* - `if` excludes an element from the DOM.
|
|
1044
|
+
* - `key` specifies a key for repeated items.
|
|
970
1045
|
* - `items` set items for repeated component, must be an array of props.
|
|
971
1046
|
* - `on[EventName]` creates an event handler (note the code is copied)
|
|
1047
|
+
* - `part:xyz` saves a reference to part of a component so it can be updated
|
|
972
1048
|
* - `props` specifes props for a nested components.
|
|
973
|
-
* - `ref:xyz` saves a reference to
|
|
1049
|
+
* - `ref:xyz` saves a reference to an element or nested omponent.
|
|
974
1050
|
* - `show` sets and element or component's hidden property.
|
|
975
1051
|
* - `style:xyz` sets a specific style property.
|
|
976
1052
|
* - `toggle:xyz` toggles `xyz` as defined by `class:xyz` on same element, or class
|
package/lib/utils.js
CHANGED
|
@@ -6,21 +6,6 @@ export function replaceNode(nodeToReplace, newNode) {
|
|
|
6
6
|
nodeToReplace.parentNode.replaceChild(newNode, nodeToReplace);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Trims the unwanted child elements from the end.
|
|
11
|
-
*
|
|
12
|
-
* @param {Node} e
|
|
13
|
-
* @param {Array} childNodes
|
|
14
|
-
* @param {Int} itemsLength
|
|
15
|
-
*/
|
|
16
|
-
export function trimChildren(e, childNodes, itemsLength) {
|
|
17
|
-
let lastIndex = childNodes.length - 1;
|
|
18
|
-
let keepIndex = itemsLength - 1;
|
|
19
|
-
for (let i = lastIndex; i > keepIndex; i--) {
|
|
20
|
-
e.removeChild(childNodes[i]);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
9
|
/**
|
|
25
10
|
* Stash something on the component. Returns the element.
|
|
26
11
|
* The generated code is expected to keep track of the position.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wallace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"author": "Andrew Buchan",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "An insanely small, fast, intuitive and extendable front-end framework",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"files": [
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"test": "jest --clearCache && jest"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"babel-plugin-wallace": "^0.
|
|
17
|
+
"babel-plugin-wallace": "^0.10.0",
|
|
18
18
|
"browserify": "^17.0.1"
|
|
19
19
|
},
|
|
20
|
-
"gitHead": "
|
|
20
|
+
"gitHead": "5516e673ca0e4c0a01644701b914ca923e000580"
|
|
21
21
|
}
|
|
File without changes
|