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.
@@ -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
- proto.patch = function (e, items, ctrl) {
63
- // Attempt to speed up by reducing lookups. Does this even do anything?
64
- // Does webpack undo this/do it for for me? Does the engine?
65
- const pool = this.pool;
66
- const componentDefinition = this.def;
67
- const keyFn = this.keyFn;
68
- const childNodes = e.childNodes;
69
- const itemsLength = items.length;
70
- const oldKeySequence = this.keys;
71
- const newKeys = [];
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
- childElementCount = oldKeySequence.length + 1;
76
- for (let i = 0; i < itemsLength; i++) {
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 = getComponent(pool, componentDefinition, ctrl, key, item);
80
- newKeys.push(key);
81
- if (i > childElementCount) {
82
- e.appendChild(component.el);
83
- } else if (key !== oldKeySequence[i]) {
84
- e.insertBefore(component.el, childNodes[i]);
85
- pull(oldKeySequence, key, i);
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
- this.keys = newKeys;
89
- trimChildren(e, childNodes, itemsLength);
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
- trimChildren(e, childNodes, itemsLength);
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. Directives
15
- 5. Controllers
16
- 6. Inheritance
17
- 7. Stubs
18
- 8. TypeScript
19
- 9. Helpers
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 or repeat components use its name followed by `.nest` or `.repeat`:
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 or repeat on the root element.
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
- ## 4. Directives
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
- ## 5. Controllers
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
- ## 6. Inheritance
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
- ## 7. Stubs
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
- ## 8. TypeScript
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 or nesting:
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
- ## 9. Helpers
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 must not have siblings.
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.8.0",
3
+ "version": "0.10.0",
4
4
  "author": "Andrew Buchan",
5
- "description": "The framework that brings you FREEDOM!!",
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.8.0",
17
+ "babel-plugin-wallace": "^0.10.0",
18
18
  "browserify": "^17.0.1"
19
19
  },
20
- "gitHead": "7e497347a84b4326da188f11b7a71c85cc70bf41"
20
+ "gitHead": "5516e673ca0e4c0a01644701b914ca923e000580"
21
21
  }