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 CHANGED
@@ -1,42 +1,40 @@
1
1
  const throwAway = document.createElement("template");
2
2
  const NO_LOOKUP = "__";
3
3
 
4
- const ComponentBase = {
5
- stubs: {},
6
- prototype: {
7
- /**
8
- * The render function that gets called by parent components.
9
- */
10
- render: function (props, ctrl) {
11
- this.props = props;
12
- this.ctrl = ctrl;
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
- * Updates the DOM and renders nested components.
18
- */
19
- update: function () {
20
- this._u(0, this._l);
21
- },
14
+ /**
15
+ * Updates the DOM and renders nested components.
16
+ */
17
+ update: function () {
18
+ this._u(0, this._l);
19
+ },
22
20
 
23
- _u: function (i, il) {
24
- let watch,
25
- element,
26
- parent,
27
- displayToggle,
28
- detacher,
29
- lookupTrue,
30
- shouldBeVisible,
31
- detachedElements,
32
- detachedElement,
33
- index,
34
- adjustedIndex;
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
- const watches = this._w,
37
- props = this.props,
38
- previous = this._p;
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
- while (i < il) {
60
- watch = watches[i];
61
- element = this._e[watch.e];
62
- displayToggle = watch.v;
63
- shouldBeVisible = true;
64
- if (displayToggle) {
65
- lookupTrue = !!this._q[displayToggle.q](props, this);
66
- shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
67
- detacher = displayToggle.d;
68
- if (detacher) {
69
- index = detacher.i;
70
- parent = this._e[detacher.e];
71
- detachedElements = this._s[detacher.s];
72
- detachedElement = detachedElements[index];
73
- if (shouldBeVisible && detachedElement) {
74
- adjustedIndex =
75
- index -
76
- Object.keys(detachedElements).filter(function (k) {
77
- return k < index && detachedElements[k];
78
- }).length;
79
- parent.insertBefore(detachedElement, parent.childNodes[adjustedIndex]);
80
- detachedElements[index] = null;
81
- } else if (!shouldBeVisible && !detachedElement) {
82
- parent.removeChild(element);
83
- detachedElements[index] = element;
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
- const prev = previous[i],
94
- callbacks = watch.c;
95
- for (let key in callbacks) {
96
- if (key === NO_LOOKUP) {
97
- callbacks[key](element, props, this);
98
- } else {
99
- const oldValue = prev[key],
100
- newValue = this._q[key](props, this);
101
- if (oldValue !== newValue) {
102
- callbacks[key](element, props, this, newValue);
103
- prev[key] = newValue;
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(ComponentBase.prototype, "hidden", {
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 {*} baseComponent - a component definition to inherit from.
124
- * @returns the newly created component definition function.
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 createConstructor(baseComponent) {
127
- const Component = function () {
128
- const root = (this.el = this._n.cloneNode(true)),
129
- dynamicElements = (this._e = []),
130
- stash = (this._s = []),
131
- previous = (this._p = []),
132
- refs = (this.refs = {});
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
- Component.create = function (props, ctrl) {
155
- const component = new Component();
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, buildFunction, inheritFrom) {
164
- const ComponentDefinition = createConstructor(inheritFrom || ComponentBase);
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._b = buildFunction;
171
- proto._n = throwAway.content.firstChild;
172
- proto.base = ComponentBase.prototype;
155
+ proto._t = throwAway.content.firstChild;
156
+ proto.base = ComponentPrototype;
173
157
  return ComponentDefinition;
174
158
  }
@@ -0,0 +1,5 @@
1
+ export function createComponent(ComponentFunction, props, ctrl) {
2
+ const component = new ComponentFunction();
3
+ component.render(props, ctrl);
4
+ return component;
5
+ }
package/lib/extend.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createConstructor } from "./component";
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 createConstructor(base);
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 { nestComponent } from "./nest";
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, component, refs, name, start, end) {
17
- refs[name] = new Ref(component, node, start, end);
18
- return node;
5
+ export function saveRef(node, refs, name) {
6
+ return (refs[name] = node);
19
7
  }
@@ -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
  *
@@ -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
- const componentDefinition = this.def;
25
- const childNodes = e.childNodes;
26
- const itemsLength = items.length;
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
- for (let i = 0; i < itemsLength; i++) {
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
- 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
+ }
46
50
  };
package/lib/router.js CHANGED
@@ -60,7 +60,7 @@ Router.methods = {
60
60
  }
61
61
  },
62
62
  mount(component) {
63
- this.el.innerHTML = "";
63
+ this.el.textContent = "";
64
64
  this.el.appendChild(component.el);
65
65
  }
66
66
  };
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
 
@@ -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 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:
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 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.
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
- ## 4. Directives
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
- ## 5. Controllers
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
- ## 6. Inheritance
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
- ## 7. Stubs
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
- ## 8. TypeScript
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 or nesting:
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
- ## 9. Helpers
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 Ref {
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
- refs: { [key: string]: Ref };
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: Uses<Props, Controller, Methods>,
689
+ base: ComponentFunction<Props, Controller, Methods>,
638
690
  componentFunc?: ComponentFunction<Props, Controller, Methods>
639
- ): Uses<Props, Controller, Methods>;
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: Uses<Props, Controller, Methods>,
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 a node allowing you 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.refs.title.update();
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 must not have siblings.
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 node, allowing partial updates or access to element/component.
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.7.2",
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.7.0",
17
+ "babel-plugin-wallace": "^0.10.0",
18
18
  "browserify": "^17.0.1"
19
19
  },
20
- "gitHead": "8ddf878a5e0119acc5edea32f08b7fc8a40974f1"
20
+ "gitHead": "5516e673ca0e4c0a01644701b914ca923e000580"
21
21
  }
File without changes