wallace 0.8.0 → 0.11.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Wallace
2
2
 
3
- This package contains the library for the [Wallace](https://github.com/wallace-js/wallace) framework, which you import into your source files:
3
+ This package contains the library for the [Wallace](https://wallace.js.org) framework, which you import into your source files:
4
4
 
5
5
  ```jsx
6
6
  import { mount } from 'wallace';
@@ -26,4 +26,4 @@ npx create-wallace-app
26
26
 
27
27
  As that sets up your babel and webpack configurations for you.
28
28
 
29
- For more detailed documentation see the [Wallace repository on github](https://github.com/wallace-js/wallace).
29
+ For more detailed documentation see the [Wallace repository on github](https://wallace.js.org/docs/).
package/lib/component.js CHANGED
@@ -115,10 +115,13 @@ Object.defineProperty(ComponentPrototype, "hidden", {
115
115
  });
116
116
 
117
117
  const ComponentBase = {
118
- stubs: {},
119
118
  prototype: ComponentPrototype
120
119
  };
121
120
 
121
+ if (wallaceConfig.flags.useStubs) {
122
+ ComponentBase.stubs = {};
123
+ }
124
+
122
125
  /**
123
126
  *
124
127
  * @param {function} ComponentFunction - The Component definition function to add bits to.
@@ -134,15 +137,22 @@ export function initConstructor(ComponentFunction, BaseComponentFunction) {
134
137
  }
135
138
  }
136
139
  ));
137
- Object.defineProperty(ComponentFunction, "methods", {
138
- set: function (value) {
139
- Object.assign(proto, value);
140
- },
141
- get: function () {
142
- return proto;
143
- }
144
- });
145
- ComponentFunction.stubs = Object.assign({}, BaseComponentFunction.stubs);
140
+
141
+ if (wallaceConfig.flags.useMethods) {
142
+ Object.defineProperty(ComponentFunction, "methods", {
143
+ set: function (value) {
144
+ Object.assign(proto, value);
145
+ },
146
+ get: function () {
147
+ return proto;
148
+ }
149
+ });
150
+ }
151
+
152
+ if (wallaceConfig.flags.useStubs) {
153
+ ComponentFunction.stubs = Object.assign({}, BaseComponentFunction.stubs);
154
+ }
155
+
146
156
  return ComponentFunction;
147
157
  }
148
158
 
@@ -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
@@ -8,17 +8,53 @@
8
8
 
9
9
  ### Contents
10
10
 
11
+ 0. Configuration
11
12
  1. Components
12
13
  2. JSX
13
14
  3. Nesting
14
- 4. Directives
15
- 5. Controllers
16
- 6. Inheritance
17
- 7. Stubs
18
- 8. TypeScript
19
- 9. Helpers
15
+ 4. Repeating
16
+ 5. Directives
17
+ 6. Controllers
18
+ 7. Inheritance
19
+ 8. Stubs
20
+ 9. TypeScript
21
+ 10. Helpers
20
22
 
21
- For more detailed documentation go to https://github.com/wallace-js/wallace
23
+ For more detailed documentation go to https://wallace.js.org/docs/
24
+
25
+
26
+ ## 0. Configuration
27
+
28
+ You need to set flags in your babel config to use certain features:
29
+
30
+ 1. useControllers - enables use of `ctrl` in components.
31
+ 2. useMethods - adds the `methods` helper to components.
32
+ 3. useStubs - enables the use of stubs.
33
+
34
+ The types (and therefore tool tips) are unaffected by these flags, and will treat them
35
+ all as being true.
36
+
37
+ ```tsx
38
+ module.exports = {
39
+ plugins: [
40
+ [
41
+ "babel-plugin-wallace",
42
+ {
43
+ flags: {
44
+ useControllers: true,
45
+ useMethods: true,
46
+ useStubs: true
47
+ },
48
+ directives: [...]
49
+ }
50
+ ],
51
+ "@babel/plugin-syntax-jsx"
52
+ ],
53
+ presets: ["@babel/preset-typescript", ...]
54
+ };
55
+ ```
56
+
57
+ The `directives` option lets you override or define new directives. See main docs.
22
58
 
23
59
  ## 1. Components
24
60
 
@@ -179,7 +215,7 @@ Other than that, its standard JSX, except for three special cases:
179
215
 
180
216
  ## 3. Nesting
181
217
 
182
- To nest or repeat components use its name followed by `.nest` or `.repeat`:
218
+ To nest a component use its name followed by `.nest` and pass `props` if needed:
183
219
 
184
220
  ```tsx
185
221
  const Task = (task) => (<div></div>);
@@ -200,11 +236,46 @@ const TaskList = (tasks) => (
200
236
 
201
237
  Notes:
202
238
 
203
- - You cannot use nest or repeat on the root element.
239
+ - You cannot use nest on the root element.
240
+
241
+ ## 4. Repeating
242
+
243
+ To repeat a component use its name followed by `.repeat` and pass `items`:
244
+
245
+ ```tsx
246
+ const Task = (task) => (<div></div>);
247
+
248
+ const TaskList = (tasks) => (
249
+ <div>
250
+ <Task.repeat items={tasks} />
251
+ </div>
252
+ );
253
+ ```
254
+
255
+ This form reuses components sequentially, which may cause issues with CSS animations
256
+ and focus, in which case you should use a keyed repeater by passing `key` which can
257
+ be a string or a function:
258
+
259
+ ```tsx
260
+ const TaskList = (tasks) => (
261
+ <div>
262
+ <Task.repeat items={tasks} key="id"/>
263
+ </div>
264
+ );
265
+
266
+ const TaskList = (tasks) => (
267
+ <div>
268
+ <Task.repeat items={tasks} key={(x) => x.id}/>
269
+ </div>
270
+ );
271
+ ```
272
+
273
+ Notes:
274
+
275
+ - You cannot repeat on the root element.
204
276
  - Repeat must be the only child element under its parent.
205
- - The `props` expects an array on repeat (See **TypeScript** below)
206
277
 
207
- ## 4. Directives
278
+ ## 5. Directives
208
279
 
209
280
  Directives are attributes with special behaviours.
210
281
 
@@ -217,7 +288,7 @@ temporarily change it to something `class x:danger`.
217
288
 
218
289
  You can define your own directives in your babel config.
219
290
 
220
- ## 5. Controllers
291
+ ## 6. Controllers
221
292
 
222
293
  A controller is just an object you create which gets passed down to every nested
223
294
  component, making it a convenient place to handle:
@@ -268,7 +339,7 @@ TaskList.methods = {
268
339
  };
269
340
  ```
270
341
 
271
- ## 6. Inheritance
342
+ ## 7. Inheritance
272
343
 
273
344
  You can creat new component defintion by extending another one, either preserving the
274
345
  base's structure, or overriding it:
@@ -284,7 +355,7 @@ const Child2 = extendComponent(Parent, ({name}) => <h3>{name}</h3>);
284
355
 
285
356
  Either way the new component definition inherits the parent *prototype* and *stubs*.
286
357
 
287
- ## 7. Stubs
358
+ ## 8. Stubs
288
359
 
289
360
  Stubs are named placeholders for nested components which are requested in the JSX:
290
361
 
@@ -317,7 +388,7 @@ Notes:
317
388
  - Stubs are separate components, so cannot access methods on the containing component
318
389
  through `self` (use the controller for that kind of thing).
319
390
 
320
- ## 8. TypeScript
391
+ ## 9. TypeScript
321
392
 
322
393
  The main type is `Uses` which must be placed right after the comonent name:
323
394
 
@@ -341,7 +412,7 @@ const Task: Uses<null> = () => <div>Hello</div>;
341
412
 
342
413
  ### Props
343
414
 
344
- TypeScript will ensure you pass correct props during mounting or nesting:
415
+ TypeScript will ensure you pass correct props during mounting, nesting and repeating:
345
416
 
346
417
  ```
347
418
  const TaskList: Uses<iTask[]> = (tasks) => (
@@ -353,6 +424,8 @@ const TaskList: Uses<iTask[]> = (tasks) => (
353
424
  </div>
354
425
  </div>
355
426
  );
427
+
428
+ mount("main", TaskList, [{test: 'foo'}]);
356
429
  ```
357
430
 
358
431
  ### Controller
@@ -439,7 +512,7 @@ Wallace defines some other types you may use:
439
512
  constructor, not a class)
440
513
  - `ComponentInstance<Props, Controller, Methods>` - a component instance.
441
514
 
442
- ## 9. Helpers
515
+ ## 10. Helpers
443
516
 
444
517
  Each of these has their own JSDoc, we just lsit them here.
445
518
 
@@ -517,10 +590,12 @@ declare module "wallace" {
517
590
  }): JSX.Element;
518
591
  repeat?({
519
592
  items,
593
+ key,
520
594
  show,
521
595
  hide
522
596
  }: {
523
597
  items: Array<Props>;
598
+ key?: string | ((item: Props) => any);
524
599
  show?: boolean;
525
600
  hide?: boolean;
526
601
  }): JSX.Element;
@@ -880,6 +955,15 @@ interface DirectiveAttributes extends AllDomEvents {
880
955
  */
881
956
  items?: MustBeExpression;
882
957
 
958
+ /** ## Wallace directive: key
959
+ *
960
+ * Specifies a key for repeated components, creating an association between the key
961
+ * and the nested component.
962
+ *
963
+ * You can specify a property as a string or a function.
964
+ */
965
+ key?: any;
966
+
883
967
  /**
884
968
  * ## Wallace directive: part
885
969
  *
@@ -963,9 +1047,11 @@ interface DirectiveAttributes extends AllDomEvents {
963
1047
  toggle?: string;
964
1048
 
965
1049
  /**
966
- * Foo
1050
+ * ## Wallace directive: unique
1051
+ *
1052
+ * Performance optimisation that can be applied to a component which is only used once.
967
1053
  */
968
- "class-a"?: string;
1054
+ unique?: boolean;
969
1055
  }
970
1056
 
971
1057
  declare namespace JSX {
@@ -977,8 +1063,10 @@ declare namespace JSX {
977
1063
  * ```
978
1064
  * <MyComponent.nest props={singleProps} />
979
1065
  * <MyComponent.repeat items={arrayOfProps} />
1066
+ * <MyComponent.repeat items={arrayOfProps} key="id"/>
1067
+ * <MyComponent.repeat items={arrayOfProps} key={(i) => i.id}/>
980
1068
  * ```
981
- * Note that repeated components must not have siblings.
1069
+ * Note that repeated components may not have siblings.
982
1070
  *
983
1071
  * Available Wallace directives:
984
1072
  *
@@ -990,6 +1078,7 @@ declare namespace JSX {
990
1078
  * - `hide` sets an element or component's hidden property.
991
1079
  * - `html` Set the element's `innnerHTML` property.
992
1080
  * - `if` excludes an element from the DOM.
1081
+ * - `key` specifies a key for repeated items.
993
1082
  * - `items` set items for repeated component, must be an array of props.
994
1083
  * - `on[EventName]` creates an event handler (note the code is copied)
995
1084
  * - `part:xyz` saves a reference to part of a component so it can be updated
@@ -999,6 +1088,7 @@ declare namespace JSX {
999
1088
  * - `style:xyz` sets a specific style property.
1000
1089
  * - `toggle:xyz` toggles `xyz` as defined by `class:xyz` on same element, or class
1001
1090
  * `xyz`.
1091
+ * - `unique` can be set on components which only used once for better performance.
1002
1092
  *
1003
1093
  * You will get more details by hovering on the directive itself, but unfortunetely
1004
1094
  * the tool tip won't display when you use a qualifier, like `class:danger`. To see
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,9 @@
1
1
  {
2
2
  "name": "wallace",
3
- "version": "0.8.0",
3
+ "version": "0.11.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
+ "homepage": "https://wallace.js.org",
6
7
  "license": "ISC",
7
8
  "main": "lib/index.js",
8
9
  "files": [
@@ -14,8 +15,8 @@
14
15
  "test": "jest --clearCache && jest"
15
16
  },
16
17
  "dependencies": {
17
- "babel-plugin-wallace": "^0.8.0",
18
+ "babel-plugin-wallace": "^0.11.0",
18
19
  "browserify": "^17.0.1"
19
20
  },
20
- "gitHead": "7e497347a84b4326da188f11b7a71c85cc70bf41"
21
+ "gitHead": "f145fe3b852025e2c851c27d75e7a104c5ec2bda"
21
22
  }