vasille 2.0.3 → 2.2.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.
Files changed (79) hide show
  1. package/README.md +7 -3
  2. package/cdn/es2015.js +939 -1009
  3. package/cdn/es5.js +1048 -1029
  4. package/flow-typed/vasille.js +2641 -832
  5. package/lib/binding/attribute.js +11 -12
  6. package/lib/binding/binding.js +9 -19
  7. package/lib/binding/class.js +34 -42
  8. package/lib/binding/style.js +5 -11
  9. package/lib/core/core.js +78 -32
  10. package/lib/core/destroyable.js +2 -2
  11. package/lib/core/ivalue.js +15 -13
  12. package/lib/functional/components.js +17 -0
  13. package/lib/functional/merge.js +41 -0
  14. package/lib/functional/models.js +26 -0
  15. package/lib/functional/options.js +1 -0
  16. package/lib/functional/reactivity.js +33 -0
  17. package/lib/functional/stack.js +127 -0
  18. package/lib/index.js +2 -7
  19. package/lib/models/array-model.js +9 -0
  20. package/lib/models/object-model.js +28 -14
  21. package/lib/node/app.js +23 -14
  22. package/lib/node/interceptor.js +3 -3
  23. package/lib/node/node.js +338 -684
  24. package/lib/node/watch.js +9 -17
  25. package/lib/spec/html.js +1 -0
  26. package/lib/spec/react.js +1 -0
  27. package/lib/spec/svg.js +1 -0
  28. package/lib/v/index.js +23 -0
  29. package/lib/value/expression.js +11 -8
  30. package/lib/value/mirror.js +6 -8
  31. package/lib/value/reference.js +3 -7
  32. package/lib/views/array-view.js +6 -10
  33. package/lib/views/base-view.js +12 -23
  34. package/lib/views/map-view.js +4 -9
  35. package/lib/views/object-view.js +5 -8
  36. package/lib/views/repeat-node.js +20 -60
  37. package/lib/views/repeater.js +7 -7
  38. package/lib/views/set-view.js +4 -11
  39. package/package.json +7 -6
  40. package/types/binding/attribute.d.ts +2 -8
  41. package/types/binding/binding.d.ts +4 -13
  42. package/types/binding/class.d.ts +7 -19
  43. package/types/binding/style.d.ts +0 -6
  44. package/types/core/core.d.ts +40 -54
  45. package/types/core/destroyable.d.ts +2 -2
  46. package/types/core/ivalue.d.ts +13 -11
  47. package/types/functional/components.d.ts +4 -0
  48. package/types/functional/merge.d.ts +1 -0
  49. package/types/functional/models.d.ts +10 -0
  50. package/types/functional/options.d.ts +23 -0
  51. package/types/functional/reactivity.d.ts +11 -0
  52. package/types/functional/stack.d.ts +24 -0
  53. package/types/index.d.ts +3 -7
  54. package/types/models/array-model.d.ts +3 -2
  55. package/types/models/map-model.d.ts +2 -2
  56. package/types/models/model.d.ts +3 -1
  57. package/types/models/object-model.d.ts +4 -2
  58. package/types/models/set-model.d.ts +2 -2
  59. package/types/node/app.d.ts +21 -19
  60. package/types/node/node.d.ts +97 -422
  61. package/types/node/watch.d.ts +9 -15
  62. package/types/spec/html.d.ts +975 -0
  63. package/types/spec/react.d.ts +4 -0
  64. package/types/spec/svg.d.ts +314 -0
  65. package/types/v/index.d.ts +32 -0
  66. package/types/value/expression.d.ts +7 -20
  67. package/types/value/mirror.d.ts +3 -3
  68. package/types/value/reference.d.ts +5 -5
  69. package/types/views/array-view.d.ts +3 -4
  70. package/types/views/base-view.d.ts +9 -17
  71. package/types/views/map-view.d.ts +2 -3
  72. package/types/views/object-view.d.ts +2 -3
  73. package/types/views/repeat-node.d.ts +8 -9
  74. package/types/views/set-view.d.ts +2 -3
  75. package/types/core/executor.d.ts +0 -87
  76. package/types/core/signal.d.ts +0 -35
  77. package/types/core/slot.d.ts +0 -45
  78. package/types/node/interceptor.d.ts +0 -50
  79. package/types/views/repeater.d.ts +0 -38
@@ -12,21 +12,20 @@ export class AttributeBinding extends Binding {
12
12
  * @param value {IValue} value to bind
13
13
  */
14
14
  constructor(node, name, value) {
15
- super(node, name, value);
16
- }
17
- /**
18
- * Generates a function which updates the attribute value
19
- * @param name {String} The name of attribute
20
- * @returns {Function} a function which will update attribute value
21
- */
22
- bound(name) {
23
- return function (node, value) {
15
+ super(value);
16
+ this.init((value) => {
24
17
  if (value) {
25
- node.app.$run.setAttribute(node.node, name, value);
18
+ if (typeof value === 'boolean') {
19
+ node.node.setAttribute(name, "");
20
+ }
21
+ else {
22
+ node.node.setAttribute(name, `${value}`);
23
+ }
26
24
  }
27
25
  else {
28
- node.app.$run.removeAttribute(node.node, name);
26
+ node.node.removeAttribute(name);
29
27
  }
30
- };
28
+ });
29
+ this.seal();
31
30
  }
32
31
  }
@@ -1,5 +1,4 @@
1
1
  import { Destroyable } from "../core/destroyable";
2
- import { notOverwritten } from "../core/errors";
3
2
  /**
4
3
  * Describe a common binding logic
5
4
  * @class Binding
@@ -8,32 +7,23 @@ import { notOverwritten } from "../core/errors";
8
7
  export class Binding extends Destroyable {
9
8
  /**
10
9
  * Constructs a common binding logic
11
- * @param node {INode} the vasille node
12
- * @param name {String} the name of property/attribute/class
13
10
  * @param value {IValue} the value to bind
14
11
  */
15
- constructor(node, name, value) {
12
+ constructor(value) {
16
13
  super();
17
- this.updateFunc = this.bound(name).bind(null, node);
18
14
  this.binding = value;
19
- this.binding.on(this.updateFunc);
20
- this.updateFunc(this.binding.$);
21
- this.$seal();
15
+ this.seal();
22
16
  }
23
- /**
24
- * Is a virtual function to get the specific bind function
25
- * @param name {String} the name of attribute/property
26
- * @returns {Function} a function to update attribute/property value
27
- * @throws Always throws and must be overloaded in child class
28
- */
29
- bound(name) {
30
- throw notOverwritten();
17
+ init(bounded) {
18
+ this.func = bounded;
19
+ this.binding.on(this.func);
20
+ this.func(this.binding.$);
31
21
  }
32
22
  /**
33
23
  * Just clear bindings
34
24
  */
35
- $destroy() {
36
- this.binding.off(this.updateFunc);
37
- super.$destroy();
25
+ destroy() {
26
+ this.binding.off(this.func);
27
+ super.destroy();
38
28
  }
39
29
  }
@@ -1,51 +1,43 @@
1
1
  import { Binding } from "./binding";
2
- /**
3
- * Represents a HTML class binding description
4
- * @class ClassBinding
5
- * @extends Binding
6
- */
7
- export class ClassBinding extends Binding {
8
- /**
9
- * Constructs an HTML class binding description
10
- * @param node {INode} the vasille node
11
- * @param name {String} the name of class
12
- * @param value {IValue} the value to bind
13
- */
2
+ function addClass(node, cl) {
3
+ node.node.classList.add(cl);
4
+ }
5
+ function removeClass(node, cl) {
6
+ node.node.classList.remove(cl);
7
+ }
8
+ export class StaticClassBinding extends Binding {
14
9
  constructor(node, name, value) {
15
- super(node, name, value);
16
- this.$seal();
17
- }
18
- /**
19
- * Generates a function which updates the html class value
20
- * @param name {String} The name of attribute
21
- * @returns {Function} a function which will update attribute value
22
- */
23
- bound(name) {
24
- let current = null;
25
- function addClass(node, cl) {
26
- node.app.$run.addClass(node.node, cl);
27
- }
28
- function removeClass(node, cl) {
29
- node.app.$run.removeClass(node.node, cl);
30
- }
31
- return (node, value) => {
32
- if (value !== current) {
33
- if (typeof current === "string" && current !== "") {
34
- removeClass(node, current);
10
+ super(value);
11
+ this.current = false;
12
+ this.init((value) => {
13
+ if (value !== this.current) {
14
+ if (value) {
15
+ addClass(node, name);
16
+ }
17
+ else {
18
+ removeClass(node, name);
35
19
  }
36
- if (typeof value === "boolean") {
37
- if (value) {
38
- addClass(node, name);
39
- }
40
- else {
41
- removeClass(node, name);
42
- }
20
+ this.current = value;
21
+ }
22
+ });
23
+ this.seal();
24
+ }
25
+ }
26
+ export class DynamicalClassBinding extends Binding {
27
+ constructor(node, value) {
28
+ super(value);
29
+ this.current = "";
30
+ this.init((value) => {
31
+ if (this.current != value) {
32
+ if (this.current.length) {
33
+ removeClass(node, this.current);
43
34
  }
44
- else if (typeof value === "string" && value !== "") {
35
+ if (value.length) {
45
36
  addClass(node, value);
46
37
  }
47
- current = value;
38
+ this.current = value;
48
39
  }
49
- };
40
+ });
41
+ this.seal();
50
42
  }
51
43
  }
@@ -12,18 +12,12 @@ export class StyleBinding extends Binding {
12
12
  * @param value {IValue} the value to bind
13
13
  */
14
14
  constructor(node, name, value) {
15
- super(node, name, value);
16
- }
17
- /**
18
- * Generates a function to update style property value
19
- * @param name {string}
20
- * @returns {Function} a function to update style property
21
- */
22
- bound(name) {
23
- return function (node, value) {
15
+ super(value);
16
+ this.init((value) => {
24
17
  if (node.node instanceof HTMLElement) {
25
- node.app.$run.setStyle(node.node, name, value);
18
+ node.node.style.setProperty(name, value);
26
19
  }
27
- };
20
+ });
21
+ this.seal();
28
22
  }
29
23
  }
package/lib/core/core.js CHANGED
@@ -1,10 +1,18 @@
1
1
  import { Destroyable } from "./destroyable.js";
2
2
  import { wrongBinding } from "./errors";
3
- import { IValue } from "./ivalue.js";
4
3
  import { Expression } from "../value/expression";
5
4
  import { Reference } from "../value/reference";
6
5
  import { Pointer } from "../value/pointer";
7
6
  import { Mirror } from "../value/mirror";
7
+ export let current = null;
8
+ const currentStack = [];
9
+ function stack(node) {
10
+ currentStack.push(current);
11
+ current = node;
12
+ }
13
+ function unstack() {
14
+ current = currentStack.pop();
15
+ }
8
16
  /**
9
17
  * Private stuff of a reactive object
10
18
  * @class ReactivePrivate
@@ -37,16 +45,18 @@ export class ReactivePrivate extends Destroyable {
37
45
  * @type {boolean}
38
46
  */
39
47
  this.frozen = false;
40
- this.$seal();
48
+ this.seal();
41
49
  }
42
- $destroy() {
43
- var _a;
44
- this.watch.forEach(value => value.$destroy());
50
+ destroy() {
51
+ this.watch.forEach(value => value.destroy());
45
52
  this.watch.clear();
46
- this.bindings.forEach(binding => binding.$destroy());
53
+ this.bindings.forEach(binding => binding.destroy());
47
54
  this.bindings.clear();
48
- (_a = this.freezeExpr) === null || _a === void 0 ? void 0 : _a.$destroy();
49
- super.$destroy();
55
+ this.models.forEach(model => model.disableReactivity());
56
+ this.models.clear();
57
+ this.freezeExpr && this.freezeExpr.destroy();
58
+ this.onDestroy && this.onDestroy();
59
+ super.destroy();
50
60
  }
51
61
  }
52
62
  /**
@@ -55,15 +65,23 @@ export class ReactivePrivate extends Destroyable {
55
65
  * @extends Destroyable
56
66
  */
57
67
  export class Reactive extends Destroyable {
58
- constructor($) {
68
+ constructor(input, $) {
59
69
  super();
70
+ this.input = input;
60
71
  this.$ = $ || new ReactivePrivate;
72
+ this.seal();
73
+ }
74
+ /**
75
+ * Get parent node
76
+ */
77
+ get parent() {
78
+ return this.$.parent;
61
79
  }
62
80
  /**
63
81
  * Create a reference
64
82
  * @param value {*} value to reference
65
83
  */
66
- $ref(value) {
84
+ ref(value) {
67
85
  const $ = this.$;
68
86
  const ref = new Reference(value);
69
87
  $.watch.add(ref);
@@ -73,7 +91,7 @@ export class Reactive extends Destroyable {
73
91
  * Create a mirror
74
92
  * @param value {IValue} value to mirror
75
93
  */
76
- $mirror(value) {
94
+ mirror(value) {
77
95
  const mirror = new Mirror(value, false);
78
96
  this.$.watch.add(mirror);
79
97
  return mirror;
@@ -82,7 +100,7 @@ export class Reactive extends Destroyable {
82
100
  * Create a forward-only mirror
83
101
  * @param value {IValue} value to mirror
84
102
  */
85
- $forward(value) {
103
+ forward(value) {
86
104
  const mirror = new Mirror(value, true);
87
105
  this.$.watch.add(mirror);
88
106
  return mirror;
@@ -92,14 +110,9 @@ export class Reactive extends Destroyable {
92
110
  * @param value {*} default value to point
93
111
  * @param forwardOnly {boolean} forward only sync
94
112
  */
95
- $point(value, forwardOnly = false) {
113
+ point(value, forwardOnly = false) {
96
114
  const $ = this.$;
97
- const ref = value instanceof IValue ? value : new Reference(value);
98
- const pointer = new Pointer(ref, forwardOnly);
99
- // when value is an ivalue will be equal to ref
100
- if (value !== ref) {
101
- $.watch.add(ref);
102
- }
115
+ const pointer = new Pointer(value, forwardOnly);
103
116
  $.watch.add(pointer);
104
117
  return pointer;
105
118
  }
@@ -107,16 +120,27 @@ export class Reactive extends Destroyable {
107
120
  * Register a model
108
121
  * @param model
109
122
  */
110
- $register(model) {
123
+ register(model) {
111
124
  this.$.models.add(model);
112
125
  return model;
113
126
  }
114
- $watch(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
127
+ /**
128
+ * Creates a watcher
129
+ * @param func {function} function to run on any argument change
130
+ * @param values
131
+ */
132
+ watch(func, ...values) {
115
133
  const $ = this.$;
116
- $.watch.add(new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9));
134
+ $.watch.add(new Expression(func, !this.$.frozen, ...values));
117
135
  }
118
- $bind(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
119
- const res = new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9);
136
+ /**
137
+ * Creates a computed value
138
+ * @param func {function} function to run on any argument change
139
+ * @param values
140
+ * @return {IValue} the created ivalue
141
+ */
142
+ expr(func, ...values) {
143
+ const res = new Expression(func, !this.$.frozen, ...values);
120
144
  const $ = this.$;
121
145
  $.watch.add(res);
122
146
  return res;
@@ -124,7 +148,7 @@ export class Reactive extends Destroyable {
124
148
  /**
125
149
  * Enable reactivity of fields
126
150
  */
127
- $enable() {
151
+ enable() {
128
152
  const $ = this.$;
129
153
  if (!$.enabled) {
130
154
  $.watch.forEach(watcher => {
@@ -139,7 +163,7 @@ export class Reactive extends Destroyable {
139
163
  /**
140
164
  * Disable reactivity of fields
141
165
  */
142
- $disable() {
166
+ disable() {
143
167
  const $ = this.$;
144
168
  if ($.enabled) {
145
169
  $.watch.forEach(watcher => {
@@ -157,7 +181,7 @@ export class Reactive extends Destroyable {
157
181
  * @param onOff {function} on show feedback
158
182
  * @param onOn {function} on hide feedback
159
183
  */
160
- $bindAlive(cond, onOff, onOn) {
184
+ bindAlive(cond, onOff, onOn) {
161
185
  const $ = this.$;
162
186
  if ($.freezeExpr) {
163
187
  throw wrongBinding("this component already have a freeze state");
@@ -169,18 +193,40 @@ export class Reactive extends Destroyable {
169
193
  $.frozen = !cond;
170
194
  if (cond) {
171
195
  onOn === null || onOn === void 0 ? void 0 : onOn();
172
- this.$enable();
196
+ this.enable();
173
197
  }
174
198
  else {
175
199
  onOff === null || onOff === void 0 ? void 0 : onOff();
176
- this.$disable();
200
+ this.disable();
177
201
  }
178
202
  }, true, cond);
179
203
  return this;
180
204
  }
181
- $destroy() {
182
- super.$destroy();
183
- this.$.$destroy();
205
+ init() {
206
+ this.applyOptions(this.input);
207
+ this.compose(this.input);
208
+ }
209
+ applyOptions(input) {
210
+ // empty
211
+ }
212
+ compose(input) {
213
+ // empty
214
+ }
215
+ runFunctional(f, ...args) {
216
+ stack(this);
217
+ // yet another ts bug
218
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
219
+ // @ts-ignore
220
+ const result = f(...args);
221
+ unstack();
222
+ return result;
223
+ }
224
+ runOnDestroy(func) {
225
+ this.$.onDestroy = func;
226
+ }
227
+ destroy() {
228
+ super.destroy();
229
+ this.$.destroy();
184
230
  this.$ = null;
185
231
  }
186
232
  }
@@ -7,7 +7,7 @@ export class Destroyable {
7
7
  * Make object fields non configurable
8
8
  * @protected
9
9
  */
10
- $seal() {
10
+ seal() {
11
11
  const $ = this;
12
12
  Object.keys($).forEach(i => {
13
13
  // eslint-disable-next-line no-prototype-builtins
@@ -39,7 +39,7 @@ export class Destroyable {
39
39
  /**
40
40
  * Garbage collector method
41
41
  */
42
- $destroy() {
42
+ destroy() {
43
43
  // nothing here
44
44
  }
45
45
  }
@@ -1,11 +1,25 @@
1
1
  import { Destroyable } from "./destroyable.js";
2
2
  import { notOverwritten } from "./errors";
3
+ export class Switchable extends Destroyable {
4
+ /**
5
+ * Enable update handlers triggering
6
+ */
7
+ enable() {
8
+ throw notOverwritten();
9
+ }
10
+ /**
11
+ * disable update handlers triggering
12
+ */
13
+ disable() {
14
+ throw notOverwritten();
15
+ }
16
+ }
3
17
  /**
4
18
  * Interface which describes a value
5
19
  * @class IValue
6
20
  * @extends Destroyable
7
21
  */
8
- export class IValue extends Destroyable {
22
+ export class IValue extends Switchable {
9
23
  /**
10
24
  * @param isEnabled {boolean} initial is enabled state
11
25
  */
@@ -41,16 +55,4 @@ export class IValue extends Destroyable {
41
55
  off(handler) {
42
56
  throw notOverwritten();
43
57
  }
44
- /**
45
- * Enable update handlers triggering
46
- */
47
- enable() {
48
- throw notOverwritten();
49
- }
50
- /**
51
- * disable update handlers triggering
52
- */
53
- disable() {
54
- throw notOverwritten();
55
- }
56
58
  }
@@ -0,0 +1,17 @@
1
+ import { Fragment } from "../node/node";
2
+ import { current } from "../core/core";
3
+ import { userError } from "../core/errors";
4
+ export function text(text) {
5
+ if (!(current instanceof Fragment))
6
+ throw userError('missing parent node', 'out-of-context');
7
+ ;
8
+ current.text(text);
9
+ }
10
+ export function debug(text) {
11
+ if (!(current instanceof Fragment))
12
+ throw userError('missing parent node', 'out-of-context');
13
+ current.debug(text);
14
+ }
15
+ export function predefine(slot, predefined) {
16
+ return slot || predefined;
17
+ }
@@ -0,0 +1,41 @@
1
+ import { IValue } from "../core/ivalue";
2
+ export function merge(main, ...targets) {
3
+ function refactorClass(obj) {
4
+ if (Array.isArray(obj.class)) {
5
+ const out = {
6
+ $: []
7
+ };
8
+ obj.class.forEach(item => {
9
+ if (item instanceof IValue) {
10
+ out.$.push(item);
11
+ }
12
+ else if (typeof item === 'string') {
13
+ out[item] = true;
14
+ }
15
+ else if (typeof item === 'object') {
16
+ Object.assign(out, item);
17
+ }
18
+ });
19
+ obj.class = out;
20
+ }
21
+ }
22
+ refactorClass(main);
23
+ targets.forEach(target => {
24
+ Reflect.ownKeys(target).forEach((prop) => {
25
+ if (!Reflect.has(main, prop)) {
26
+ main[prop] = target[prop];
27
+ }
28
+ else if (typeof main[prop] === 'object' && typeof target[prop] === 'object') {
29
+ if (prop === 'class') {
30
+ refactorClass(target);
31
+ }
32
+ if (prop === '$' && Array.isArray(main[prop]) && Array.isArray(target[prop])) {
33
+ main.$.push(...target.$);
34
+ }
35
+ else {
36
+ merge(main[prop], target[prop]);
37
+ }
38
+ }
39
+ });
40
+ });
41
+ }
@@ -0,0 +1,26 @@
1
+ import { ArrayModel } from "../models/array-model";
2
+ import { MapModel } from "../models/map-model";
3
+ import { SetModel } from "../models/set-model";
4
+ import { ObjectModel } from "../models/object-model";
5
+ import { current } from "../core/core";
6
+ import { userError } from "../core/errors";
7
+ export function arrayModel(arr = []) {
8
+ if (!current)
9
+ throw userError('missing parent node', 'out-of-context');
10
+ return current.register(new ArrayModel(arr)).proxy();
11
+ }
12
+ export function mapModel(map = []) {
13
+ if (!current)
14
+ throw userError('missing parent node', 'out-of-context');
15
+ return current.register(new MapModel(map));
16
+ }
17
+ export function setModel(arr = []) {
18
+ if (!current)
19
+ throw userError('missing parent node', 'out-of-context');
20
+ return current.register(new SetModel(arr));
21
+ }
22
+ export function objectModel(obj = {}) {
23
+ if (!current)
24
+ throw userError('missing parent node', 'out-of-context');
25
+ return current.register(new ObjectModel(obj));
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { IValue } from "../core/ivalue";
2
+ import { Pointer } from "../value/pointer";
3
+ import { current } from "../core/core";
4
+ export function ref(value) {
5
+ const ref = current.ref(value);
6
+ return [ref, (value) => ref.$ = value];
7
+ }
8
+ export function mirror(value) {
9
+ return current.mirror(value);
10
+ }
11
+ export function forward(value) {
12
+ return current.forward(value);
13
+ }
14
+ export function point(value) {
15
+ return current.point(value);
16
+ }
17
+ export function expr(func, ...values) {
18
+ return current.expr(func, ...values);
19
+ }
20
+ export function watch(func, ...values) {
21
+ current.watch(func, ...values);
22
+ }
23
+ export function valueOf(value) {
24
+ return value.$;
25
+ }
26
+ export function setValue(ref, value) {
27
+ if (ref instanceof Pointer && value instanceof IValue) {
28
+ ref.point(value);
29
+ }
30
+ else {
31
+ ref.$ = value instanceof IValue ? value.$ : value;
32
+ }
33
+ }