wallace 0.7.2 → 0.8.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
  }
@@ -20,15 +20,16 @@ export function SequentialRepeater(componentDefinition) {
20
20
  * @param {any} ctrl - The parent item's controller.
21
21
  */
22
22
  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,
23
+ const pool = this.pool,
24
+ componentDefinition = this.def,
25
+ childNodes = e.childNodes,
26
+ itemsLength = items.length,
29
27
  childElementCount = this.count;
28
+ let i = 0,
29
+ component,
30
+ poolCount = pool.length;
30
31
 
31
- for (let i = 0; i < itemsLength; i++) {
32
+ while (i < itemsLength) {
32
33
  if (i < poolCount) {
33
34
  component = pool[i];
34
35
  } else {
@@ -40,6 +41,7 @@ SequentialRepeater.prototype.patch = function (e, items, ctrl) {
40
41
  if (i >= childElementCount) {
41
42
  e.appendChild(component.el);
42
43
  }
44
+ i++;
43
45
  }
44
46
  this.count = itemsLength;
45
47
  trimChildren(e, childNodes, itemsLength);
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
@@ -145,9 +145,13 @@ Component instances have the following fields:
145
145
 
146
146
  - `props` the data for this component instance.
147
147
  - `ctrl` the controller object.
148
- - `refs` an object with references to node.
149
148
  - `el` the component instance's root element.
150
149
 
150
+ Optionally:
151
+
152
+ - `ref` an object containing named elements or nested components.
153
+ - `part` an object containing named parts.
154
+
151
155
  Both `props` and `ctrl` are set during the `render` method before calling `update`.
152
156
  There are no restrictions on types but typically:
153
157
 
@@ -526,10 +530,6 @@ declare module "wallace" {
526
530
  ThisType<ComponentInstance<Props, Controller, Methods>>;
527
531
  // Methods will not be available on nested component, so omit.
528
532
  readonly stubs?: Record<string, ComponentFunction<Props, Controller>>;
529
- create?(
530
- props?: Props,
531
- ctrl?: Controller
532
- ): ComponentInstance<Props, Controller, Methods>;
533
533
  }
534
534
 
535
535
  type ComponenMethods<Props, Controller> = {
@@ -559,8 +559,7 @@ declare module "wallace" {
559
559
  Methods extends object = {}
560
560
  > = ComponentFunction<Props, Controller, Methods>;
561
561
 
562
- export interface Ref {
563
- node: HTMLElement | ComponentInstance;
562
+ export interface Part {
564
563
  update(): void;
565
564
  }
566
565
 
@@ -575,7 +574,8 @@ declare module "wallace" {
575
574
  el: HTMLElement;
576
575
  props: Props;
577
576
  ctrl: Controller;
578
- refs: { [key: string]: Ref };
577
+ ref: { [key: string]: HTMLElement | ComponentInstance };
578
+ part: { [key: string]: Part };
579
579
  base: Component<Props, Controller>;
580
580
  } & Component<Props, Controller> &
581
581
  Methods;
@@ -620,6 +620,18 @@ declare module "wallace" {
620
620
  update(): void;
621
621
  }
622
622
 
623
+ /**
624
+ * Creates a component instance and renders it.
625
+ * @param def
626
+ * @param props
627
+ * @param ctrl
628
+ */
629
+ export function createComponent<Props, Controller, Methods extends object = {}>(
630
+ def: ComponentFunction<Props, Controller, Methods>,
631
+ props?: Props,
632
+ ctrl?: Controller
633
+ ): ComponentInstance<Props, Controller, Methods>;
634
+
623
635
  /**
624
636
  * Use to define a new component which extends another component, meaning it will
625
637
  * inherit its prototye and stubs.
@@ -634,9 +646,9 @@ declare module "wallace" {
634
646
  Controller = any,
635
647
  Methods extends object = {}
636
648
  >(
637
- base: Uses<Props, Controller, Methods>,
649
+ base: ComponentFunction<Props, Controller, Methods>,
638
650
  componentFunc?: ComponentFunction<Props, Controller, Methods>
639
- ): Uses<Props, Controller, Methods>;
651
+ ): ComponentFunction<Props, Controller, Methods>;
640
652
 
641
653
  /**
642
654
  * *Replaces* element with an instance of componentDefinition and renders it.
@@ -645,7 +657,7 @@ declare module "wallace" {
645
657
  */
646
658
  export function mount<Props = any, Controller = any, Methods extends object = {}>(
647
659
  element: string | HTMLElement,
648
- componentDefinition: Uses<Props, Controller, Methods>,
660
+ componentDefinition: ComponentFunction<Props, Controller, Methods>,
649
661
  props?: Props,
650
662
  ctrl?: Controller
651
663
  ): ComponentInstance<Props, Controller, Methods>;
@@ -868,6 +880,23 @@ interface DirectiveAttributes extends AllDomEvents {
868
880
  */
869
881
  items?: MustBeExpression;
870
882
 
883
+ /**
884
+ * ## Wallace directive: part
885
+ *
886
+ * Saves a reference to part of a component allowing you to update it independently.
887
+ *
888
+ * ```
889
+ * <div part:title>
890
+ * {name}
891
+ * </div>
892
+ * ```
893
+ *
894
+ * ```
895
+ * component.part.title.update();
896
+ * ```
897
+ */
898
+ part?: null;
899
+
871
900
  /**
872
901
  * ## Wallace directive: props
873
902
  *
@@ -879,10 +908,7 @@ interface DirectiveAttributes extends AllDomEvents {
879
908
  /**
880
909
  * ## Wallace directive: ref
881
910
  *
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()`.
911
+ * Saves a reference to an element or nested component.
886
912
  *
887
913
  * ```
888
914
  * <div ref:title>
@@ -891,11 +917,8 @@ interface DirectiveAttributes extends AllDomEvents {
891
917
  * ```
892
918
  *
893
919
  * ```
894
- * component.refs.title.update();
895
- * component.refs.title.node.textContent = 'hello';
920
+ * component.ref.title.textContent = 'hello';
896
921
  * ```
897
- *
898
- * Requires a qualifier, but you lose the tooltip in that format.
899
922
  */
900
923
  ref?: null;
901
924
 
@@ -969,8 +992,9 @@ declare namespace JSX {
969
992
  * - `if` excludes an element from the DOM.
970
993
  * - `items` set items for repeated component, must be an array of props.
971
994
  * - `on[EventName]` creates an event handler (note the code is copied)
995
+ * - `part:xyz` saves a reference to part of a component so it can be updated
972
996
  * - `props` specifes props for a nested components.
973
- * - `ref:xyz` saves a reference to node, allowing partial updates or access to element/component.
997
+ * - `ref:xyz` saves a reference to an element or nested omponent.
974
998
  * - `show` sets and element or component's hidden property.
975
999
  * - `style:xyz` sets a specific style property.
976
1000
  * - `toggle:xyz` toggles `xyz` as defined by `class:xyz` on same element, or class
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wallace",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "author": "Andrew Buchan",
5
5
  "description": "The framework that brings you FREEDOM!!",
6
6
  "license": "ISC",
@@ -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.8.0",
18
18
  "browserify": "^17.0.1"
19
19
  },
20
- "gitHead": "8ddf878a5e0119acc5edea32f08b7fc8a40974f1"
20
+ "gitHead": "7e497347a84b4326da188f11b7a71c85cc70bf41"
21
21
  }
File without changes