wallace 0.8.0 → 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/repeaters/keyed.js +53 -64
- package/lib/repeaters/sequential.js +5 -3
- package/lib/types.d.ts +69 -17
- package/lib/utils.js +0 -15
- package/package.json +4 -4
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
|
*
|
|
@@ -44,5 +42,9 @@ SequentialRepeater.prototype.patch = function (e, items, ctrl) {
|
|
|
44
42
|
i++;
|
|
45
43
|
}
|
|
46
44
|
this.count = itemsLength;
|
|
47
|
-
|
|
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
|
+
}
|
|
48
50
|
};
|
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
|
|
|
@@ -179,7 +180,7 @@ Other than that, its standard JSX, except for three special cases:
|
|
|
179
180
|
|
|
180
181
|
## 3. Nesting
|
|
181
182
|
|
|
182
|
-
To nest
|
|
183
|
+
To nest a component use its name followed by `.nest` and pass `props` if needed:
|
|
183
184
|
|
|
184
185
|
```tsx
|
|
185
186
|
const Task = (task) => (<div></div>);
|
|
@@ -200,11 +201,46 @@ const TaskList = (tasks) => (
|
|
|
200
201
|
|
|
201
202
|
Notes:
|
|
202
203
|
|
|
203
|
-
- 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.
|
|
204
241
|
- Repeat must be the only child element under its parent.
|
|
205
|
-
- The `props` expects an array on repeat (See **TypeScript** below)
|
|
206
242
|
|
|
207
|
-
##
|
|
243
|
+
## 5. Directives
|
|
208
244
|
|
|
209
245
|
Directives are attributes with special behaviours.
|
|
210
246
|
|
|
@@ -217,7 +253,7 @@ temporarily change it to something `class x:danger`.
|
|
|
217
253
|
|
|
218
254
|
You can define your own directives in your babel config.
|
|
219
255
|
|
|
220
|
-
##
|
|
256
|
+
## 6. Controllers
|
|
221
257
|
|
|
222
258
|
A controller is just an object you create which gets passed down to every nested
|
|
223
259
|
component, making it a convenient place to handle:
|
|
@@ -268,7 +304,7 @@ TaskList.methods = {
|
|
|
268
304
|
};
|
|
269
305
|
```
|
|
270
306
|
|
|
271
|
-
##
|
|
307
|
+
## 7. Inheritance
|
|
272
308
|
|
|
273
309
|
You can creat new component defintion by extending another one, either preserving the
|
|
274
310
|
base's structure, or overriding it:
|
|
@@ -284,7 +320,7 @@ const Child2 = extendComponent(Parent, ({name}) => <h3>{name}</h3>);
|
|
|
284
320
|
|
|
285
321
|
Either way the new component definition inherits the parent *prototype* and *stubs*.
|
|
286
322
|
|
|
287
|
-
##
|
|
323
|
+
## 8. Stubs
|
|
288
324
|
|
|
289
325
|
Stubs are named placeholders for nested components which are requested in the JSX:
|
|
290
326
|
|
|
@@ -317,7 +353,7 @@ Notes:
|
|
|
317
353
|
- Stubs are separate components, so cannot access methods on the containing component
|
|
318
354
|
through `self` (use the controller for that kind of thing).
|
|
319
355
|
|
|
320
|
-
##
|
|
356
|
+
## 9. TypeScript
|
|
321
357
|
|
|
322
358
|
The main type is `Uses` which must be placed right after the comonent name:
|
|
323
359
|
|
|
@@ -341,7 +377,7 @@ const Task: Uses<null> = () => <div>Hello</div>;
|
|
|
341
377
|
|
|
342
378
|
### Props
|
|
343
379
|
|
|
344
|
-
TypeScript will ensure you pass correct props during mounting
|
|
380
|
+
TypeScript will ensure you pass correct props during mounting, nesting and repeating:
|
|
345
381
|
|
|
346
382
|
```
|
|
347
383
|
const TaskList: Uses<iTask[]> = (tasks) => (
|
|
@@ -353,6 +389,8 @@ const TaskList: Uses<iTask[]> = (tasks) => (
|
|
|
353
389
|
</div>
|
|
354
390
|
</div>
|
|
355
391
|
);
|
|
392
|
+
|
|
393
|
+
mount("main", TaskList, [{test: 'foo'}]);
|
|
356
394
|
```
|
|
357
395
|
|
|
358
396
|
### Controller
|
|
@@ -439,7 +477,7 @@ Wallace defines some other types you may use:
|
|
|
439
477
|
constructor, not a class)
|
|
440
478
|
- `ComponentInstance<Props, Controller, Methods>` - a component instance.
|
|
441
479
|
|
|
442
|
-
##
|
|
480
|
+
## 10. Helpers
|
|
443
481
|
|
|
444
482
|
Each of these has their own JSDoc, we just lsit them here.
|
|
445
483
|
|
|
@@ -517,10 +555,12 @@ declare module "wallace" {
|
|
|
517
555
|
}): JSX.Element;
|
|
518
556
|
repeat?({
|
|
519
557
|
items,
|
|
558
|
+
key,
|
|
520
559
|
show,
|
|
521
560
|
hide
|
|
522
561
|
}: {
|
|
523
562
|
items: Array<Props>;
|
|
563
|
+
key?: string | ((item: Props) => any);
|
|
524
564
|
show?: boolean;
|
|
525
565
|
hide?: boolean;
|
|
526
566
|
}): JSX.Element;
|
|
@@ -880,6 +920,15 @@ interface DirectiveAttributes extends AllDomEvents {
|
|
|
880
920
|
*/
|
|
881
921
|
items?: MustBeExpression;
|
|
882
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
|
+
|
|
883
932
|
/**
|
|
884
933
|
* ## Wallace directive: part
|
|
885
934
|
*
|
|
@@ -977,8 +1026,10 @@ declare namespace JSX {
|
|
|
977
1026
|
* ```
|
|
978
1027
|
* <MyComponent.nest props={singleProps} />
|
|
979
1028
|
* <MyComponent.repeat items={arrayOfProps} />
|
|
1029
|
+
* <MyComponent.repeat items={arrayOfProps} key="id"/>
|
|
1030
|
+
* <MyComponent.repeat items={arrayOfProps} key={(i) => i.id}/>
|
|
980
1031
|
* ```
|
|
981
|
-
* Note that repeated components
|
|
1032
|
+
* Note that repeated components may not have siblings.
|
|
982
1033
|
*
|
|
983
1034
|
* Available Wallace directives:
|
|
984
1035
|
*
|
|
@@ -990,6 +1041,7 @@ declare namespace JSX {
|
|
|
990
1041
|
* - `hide` sets an element or component's hidden property.
|
|
991
1042
|
* - `html` Set the element's `innnerHTML` property.
|
|
992
1043
|
* - `if` excludes an element from the DOM.
|
|
1044
|
+
* - `key` specifies a key for repeated items.
|
|
993
1045
|
* - `items` set items for repeated component, must be an array of props.
|
|
994
1046
|
* - `on[EventName]` creates an event handler (note the code is copied)
|
|
995
1047
|
* - `part:xyz` saves a reference to part of a component so it can be updated
|
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
|
}
|