cx 22.3.3 → 22.4.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/src/data/View.js CHANGED
@@ -1,182 +1,182 @@
1
- import { Binding } from "./Binding";
2
- import { isArray } from "../util/isArray";
3
- import { isDefined } from "../util/isDefined";
4
- import { StoreRef } from "./StoreRef";
5
- import { isObject } from "../util/isObject";
6
- import { isFunction } from "../util/isFunction";
7
-
8
- export class View {
9
- constructor(config) {
10
- Object.assign(this, config);
11
- this.cache = {
12
- version: -1,
13
- };
14
- if (this.store) this.setStore(this.store);
15
- }
16
-
17
- getData() {
18
- throw new Error("abstract method");
19
- }
20
-
21
- init(path, value) {
22
- if (typeof path == "object" && path != null) {
23
- let changed = false;
24
- for (let key in path)
25
- if (path.hasOwnProperty(key) && this.get(key) === undefined && this.setItem(key, path[key])) changed = true;
26
- return changed;
27
- }
28
- let binding = Binding.get(path);
29
- if (this.get(binding.path) === undefined) return this.setItem(binding.path, value);
30
- return false;
31
- }
32
-
33
- set(path, value) {
34
- if (isObject(path)) {
35
- let changed = false;
36
- for (let key in path) if (path.hasOwnProperty(key) && this.setItem(key, path[key])) changed = true;
37
- return changed;
38
- }
39
- let binding = Binding.get(path);
40
- return this.setItem(binding.path, value);
41
- }
42
-
43
- copy(from, to) {
44
- let value = this.get(from);
45
- this.set(to, value);
46
- }
47
-
48
- move(from, to) {
49
- this.batch(() => {
50
- this.copy(from, to);
51
- this.delete(from);
52
- });
53
- }
54
-
55
- //protected
56
- setItem(path, value) {
57
- if (this.store) return this.store.setItem(path, value);
58
- throw new Error("abstract method");
59
- }
60
-
61
- delete(path) {
62
- if (arguments.length > 1) path = Array.from(arguments);
63
- if (isArray(path)) return path.map((arg) => this.delete(arg)).some(Boolean);
64
-
65
- let binding = Binding.get(path);
66
- return this.deleteItem(binding.path);
67
- }
68
-
69
- //protected
70
- deleteItem(path) {
71
- if (this.store) return this.store.deleteItem(path);
72
-
73
- throw new Error("abstract method");
74
- }
75
-
76
- clear() {
77
- if (this.store) return this.store.clear();
78
-
79
- throw new Error("abstract method");
80
- }
81
-
82
- get(path) {
83
- let storeData = this.getData();
84
-
85
- if (arguments.length > 1) path = Array.from(arguments);
86
-
87
- if (isArray(path)) return path.map((arg) => Binding.get(arg).value(storeData));
88
-
89
- return Binding.get(path).value(storeData);
90
- }
91
-
92
- toggle(path) {
93
- return this.set(path, !this.get(path));
94
- }
95
-
96
- update(path, updateFn, ...args) {
97
- if (arguments.length == 1 && isFunction(path))
98
- return this.load(path.apply(null, [this.getData(), updateFn, ...args]));
99
- return this.set(path, updateFn.apply(null, [this.get(path), ...args]));
100
- }
101
-
102
- batch(callback) {
103
- let dirty = this.silently(callback);
104
- if (dirty) this.notify();
105
- return dirty;
106
- }
107
-
108
- silently(callback) {
109
- if (this.store) return this.store.silently(callback);
110
-
111
- throw new Error("abstract method");
112
- }
113
-
114
- notify(path) {
115
- if (this.notificationsSuspended) this.dirty = true;
116
- else this.doNotify(path);
117
- }
118
-
119
- doNotify(path) {
120
- if (this.store) return this.store.notify(path);
121
-
122
- throw new Error("abstract method");
123
- }
124
-
125
- subscribe(callback) {
126
- if (this.store) return this.store.subscribe(callback);
127
-
128
- throw new Error("abstract method");
129
- }
130
-
131
- load(data) {
132
- return this.batch((store) => {
133
- for (let key in data) store.set(key, data[key]);
134
- });
135
- }
136
-
137
- dispatch(action) {
138
- if (this.store) return this.store.dispatch(action);
139
-
140
- throw new Error("The underlying store doesn't support dispatch.");
141
- }
142
-
143
- getMeta() {
144
- return this.meta;
145
- }
146
-
147
- setStore(store) {
148
- this.store = store;
149
- this.meta = store.getMeta();
150
- }
151
-
152
- ref(path, defaultValue) {
153
- if (isDefined(defaultValue)) this.init(path, defaultValue);
154
- return StoreRef.create({
155
- store: this,
156
- path,
157
- });
158
- }
159
-
160
- getMethods() {
161
- return {
162
- getData: this.getData.bind(this),
163
- set: this.set.bind(this),
164
- get: this.get.bind(this),
165
- update: this.update.bind(this),
166
- delete: this.delete.bind(this),
167
- toggle: this.toggle.bind(this),
168
- init: this.init.bind(this),
169
- ref: this.ref.bind(this),
170
- mutate: this.ref.bind(this),
171
- };
172
- }
173
- }
174
-
175
- View.prototype.sealed = false; //indicate that data should be copied before virtual items are added
176
-
177
- //Immer integration point
178
- View.prototype.mutate = function () {
179
- throw new Error(
180
- "Mutate requires Immer. Please install 'immer' and 'cx-immer' packages and enable store mutation by calling enableImmerMutate()."
181
- );
182
- };
1
+ import { Binding } from "./Binding";
2
+ import { isArray } from "../util/isArray";
3
+ import { isDefined } from "../util/isDefined";
4
+ import { StoreRef } from "./StoreRef";
5
+ import { isObject } from "../util/isObject";
6
+ import { isFunction } from "../util/isFunction";
7
+
8
+ export class View {
9
+ constructor(config) {
10
+ Object.assign(this, config);
11
+ this.cache = {
12
+ version: -1,
13
+ };
14
+ if (this.store) this.setStore(this.store);
15
+ }
16
+
17
+ getData() {
18
+ throw new Error("abstract method");
19
+ }
20
+
21
+ init(path, value) {
22
+ if (typeof path == "object" && path != null) {
23
+ let changed = false;
24
+ for (let key in path)
25
+ if (path.hasOwnProperty(key) && this.get(key) === undefined && this.setItem(key, path[key])) changed = true;
26
+ return changed;
27
+ }
28
+ let binding = Binding.get(path);
29
+ if (this.get(binding.path) === undefined) return this.setItem(binding.path, value);
30
+ return false;
31
+ }
32
+
33
+ set(path, value) {
34
+ if (isObject(path)) {
35
+ let changed = false;
36
+ for (let key in path) if (path.hasOwnProperty(key) && this.setItem(key, path[key])) changed = true;
37
+ return changed;
38
+ }
39
+ let binding = Binding.get(path);
40
+ return this.setItem(binding.path, value);
41
+ }
42
+
43
+ copy(from, to) {
44
+ let value = this.get(from);
45
+ this.set(to, value);
46
+ }
47
+
48
+ move(from, to) {
49
+ this.batch(() => {
50
+ this.copy(from, to);
51
+ this.delete(from);
52
+ });
53
+ }
54
+
55
+ //protected
56
+ setItem(path, value) {
57
+ if (this.store) return this.store.setItem(path, value);
58
+ throw new Error("abstract method");
59
+ }
60
+
61
+ delete(path) {
62
+ if (arguments.length > 1) path = Array.from(arguments);
63
+ if (isArray(path)) return path.map((arg) => this.delete(arg)).some(Boolean);
64
+
65
+ let binding = Binding.get(path);
66
+ return this.deleteItem(binding.path);
67
+ }
68
+
69
+ //protected
70
+ deleteItem(path) {
71
+ if (this.store) return this.store.deleteItem(path);
72
+
73
+ throw new Error("abstract method");
74
+ }
75
+
76
+ clear() {
77
+ if (this.store) return this.store.clear();
78
+
79
+ throw new Error("abstract method");
80
+ }
81
+
82
+ get(path) {
83
+ let storeData = this.getData();
84
+
85
+ if (arguments.length > 1) path = Array.from(arguments);
86
+
87
+ if (isArray(path)) return path.map((arg) => Binding.get(arg).value(storeData));
88
+
89
+ return Binding.get(path).value(storeData);
90
+ }
91
+
92
+ toggle(path) {
93
+ return this.set(path, !this.get(path));
94
+ }
95
+
96
+ update(path, updateFn, ...args) {
97
+ if (arguments.length == 1 && isFunction(path))
98
+ return this.load(path.apply(null, [this.getData(), updateFn, ...args]));
99
+ return this.set(path, updateFn.apply(null, [this.get(path), ...args]));
100
+ }
101
+
102
+ batch(callback) {
103
+ let dirty = this.silently(callback);
104
+ if (dirty) this.notify();
105
+ return dirty;
106
+ }
107
+
108
+ silently(callback) {
109
+ if (this.store) return this.store.silently(callback);
110
+
111
+ throw new Error("abstract method");
112
+ }
113
+
114
+ notify(path) {
115
+ if (this.notificationsSuspended) this.dirty = true;
116
+ else this.doNotify(path);
117
+ }
118
+
119
+ doNotify(path) {
120
+ if (this.store) return this.store.notify(path);
121
+
122
+ throw new Error("abstract method");
123
+ }
124
+
125
+ subscribe(callback) {
126
+ if (this.store) return this.store.subscribe(callback);
127
+
128
+ throw new Error("abstract method");
129
+ }
130
+
131
+ load(data) {
132
+ return this.batch((store) => {
133
+ for (let key in data) store.set(key, data[key]);
134
+ });
135
+ }
136
+
137
+ dispatch(action) {
138
+ if (this.store) return this.store.dispatch(action);
139
+
140
+ throw new Error("The underlying store doesn't support dispatch.");
141
+ }
142
+
143
+ getMeta() {
144
+ return this.meta;
145
+ }
146
+
147
+ setStore(store) {
148
+ this.store = store;
149
+ this.meta = store.getMeta();
150
+ }
151
+
152
+ ref(path, defaultValue) {
153
+ if (isDefined(defaultValue)) this.init(path, defaultValue);
154
+ return StoreRef.create({
155
+ store: this,
156
+ path,
157
+ });
158
+ }
159
+
160
+ getMethods() {
161
+ return {
162
+ getData: this.getData.bind(this),
163
+ set: this.set.bind(this),
164
+ get: this.get.bind(this),
165
+ update: this.update.bind(this),
166
+ delete: this.delete.bind(this),
167
+ toggle: this.toggle.bind(this),
168
+ init: this.init.bind(this),
169
+ ref: this.ref.bind(this),
170
+ mutate: this.ref.bind(this),
171
+ };
172
+ }
173
+ }
174
+
175
+ View.prototype.sealed = false; //indicate that data should be copied before virtual items are added
176
+
177
+ //Immer integration point
178
+ View.prototype.mutate = function () {
179
+ throw new Error(
180
+ "Mutate requires Immer. Please install 'immer' and 'cx-immer' packages and enable store mutation by calling enableImmerMutate()."
181
+ );
182
+ };
@@ -1,15 +1,15 @@
1
- import { getSelector } from './getSelector'
1
+ import { getSelector } from "./getSelector";
2
2
  import { isDefined } from "../util/isDefined";
3
3
  import { defaultCompare } from "./defaultCompare";
4
4
 
5
5
  export function getComparer(sorters, dataAccessor, comparer) {
6
- let data = (sorters || []).map(s => {
7
- let selector = isDefined(s.value) ? getSelector(s.value) : s.field ? x => x[s.field] : () => null;
6
+ let data = (sorters || []).map((s) => {
7
+ let selector = isDefined(s.value) ? getSelector(s.value) : s.field ? (x) => x[s.field] : () => null;
8
8
  return {
9
- getter: dataAccessor ? x => selector(dataAccessor(x)) : selector,
10
- factor: s.direction && s.direction[0].toLowerCase() == 'd' ? -1 : 1,
11
- compare: s.comparer || s.compare || comparer || defaultCompare
12
- }
9
+ getter: dataAccessor ? (x) => selector(dataAccessor(x)) : selector,
10
+ factor: s.direction && s.direction[0].toLowerCase() == "d" ? -1 : 1,
11
+ compare: s.comparer || s.compare || comparer || defaultCompare,
12
+ };
13
13
  });
14
14
 
15
15
  return function (a, b) {
@@ -18,12 +18,17 @@ export function getComparer(sorters, dataAccessor, comparer) {
18
18
  d = data[i];
19
19
  av = d.getter(a);
20
20
  bv = d.getter(b);
21
+
22
+ // show nulls always on the bottom
23
+ if (av == null) return bv == null ? 0 : 1;
24
+ if (bv == null) return -1;
25
+
21
26
  let r = d.compare(av, bv);
22
27
  if (r == 0) continue;
23
28
  return d.factor * r;
24
29
  }
25
30
  return 0;
26
- }
31
+ };
27
32
  }
28
33
 
29
34
  export function indexSorter(sorters, dataAccessor, compare) {
@@ -32,7 +37,7 @@ export function indexSorter(sorters, dataAccessor, compare) {
32
37
  let result = Array.from({ length: data.length }, (v, k) => k);
33
38
  result.sort((ia, ib) => cmp(data[ia], data[ib]));
34
39
  return result;
35
- }
40
+ };
36
41
  }
37
42
 
38
43
  export function sorter(sorters, dataAccessor, compare) {
@@ -42,5 +47,5 @@ export function sorter(sorters, dataAccessor, compare) {
42
47
  let result = [...data];
43
48
  result.sort(cmp);
44
49
  return result;
45
- }
50
+ };
46
51
  }
@@ -1,46 +1,46 @@
1
- import { AccessorChain, Record } from "../core";
2
- import { AccessorModel } from "./createAccessorModelProxy";
3
-
4
- interface Computable<V = any> {
5
- (data: Record): V;
6
- memoize(warmupData?: Record): (data: Record) => any;
7
- }
8
-
9
- export function computable(callback: () => any): Computable;
10
- export function computable(p1: string, computeFn: (v1: any) => any): Computable;
11
- export function computable(p1: string, p2: string, computeFn: (v1: any, v2: any) => any): Computable;
12
- export function computable(
13
- p1: string,
14
- p2: string,
15
- p3: string,
16
- computeFn: (v1: any, v2: any, v3: any) => any
17
- ): Computable;
18
- export function computable(
19
- p1: string,
20
- p2: string,
21
- p3: string,
22
- p4: string,
23
- computeFn: (v1: any, v2: any, v3: any, v4: any) => any
24
- ): Computable;
25
-
26
- export function computable<V1, R>(arg1: AccessorChain<V1>, compute: (v1: V1) => R): Computable<R>;
27
- export function computable<V1, V2, R>(
28
- arg1: AccessorChain<V1> | AccessorModel<V1>,
29
- arg2: AccessorChain<V2> | AccessorModel<V2>,
30
- compute: (v1: V1, v2: V2) => R
31
- ): Computable<R>;
32
-
33
- export function computable<V1, V2, V3, R>(
34
- arg1: AccessorChain<V1> | AccessorModel<V1>,
35
- arg2: AccessorChain<V2> | AccessorModel<V2>,
36
- arg3: AccessorChain<V3> | AccessorModel<V3>,
37
- compute: (v1: V1, v2: V2, v3: V3) => R
38
- ): Computable<R>;
39
-
40
- export function computable<V1, V2, V3, V4, R>(
41
- arg1: AccessorChain<V1>,
42
- arg2: AccessorChain<V2>,
43
- arg3: AccessorChain<V3>,
44
- arg4: AccessorChain<V4>,
45
- compute: (v1: V1, v2: V2, v3: V3, v4: V4) => R
46
- ): Computable<R>;
1
+ import { AccessorChain, Record } from "../core";
2
+ import { AccessorModel } from "./createAccessorModelProxy";
3
+
4
+ interface Computable<V = any> {
5
+ (data: Record): V;
6
+ memoize(warmupData?: Record): (data: Record) => any;
7
+ }
8
+
9
+ export function computable(callback: () => any): Computable;
10
+ export function computable(p1: string, computeFn: (v1: any) => any): Computable;
11
+ export function computable(p1: string, p2: string, computeFn: (v1: any, v2: any) => any): Computable;
12
+ export function computable(
13
+ p1: string,
14
+ p2: string,
15
+ p3: string,
16
+ computeFn: (v1: any, v2: any, v3: any) => any
17
+ ): Computable;
18
+ export function computable(
19
+ p1: string,
20
+ p2: string,
21
+ p3: string,
22
+ p4: string,
23
+ computeFn: (v1: any, v2: any, v3: any, v4: any) => any
24
+ ): Computable;
25
+
26
+ export function computable<V1, R>(arg1: AccessorChain<V1>, compute: (v1: V1) => R): Computable<R>;
27
+ export function computable<V1, V2, R>(
28
+ arg1: AccessorChain<V1> | AccessorModel<V1>,
29
+ arg2: AccessorChain<V2> | AccessorModel<V2>,
30
+ compute: (v1: V1, v2: V2) => R
31
+ ): Computable<R>;
32
+
33
+ export function computable<V1, V2, V3, R>(
34
+ arg1: AccessorChain<V1> | AccessorModel<V1>,
35
+ arg2: AccessorChain<V2> | AccessorModel<V2>,
36
+ arg3: AccessorChain<V3> | AccessorModel<V3>,
37
+ compute: (v1: V1, v2: V2, v3: V3) => R
38
+ ): Computable<R>;
39
+
40
+ export function computable<V1, V2, V3, V4, R>(
41
+ arg1: AccessorChain<V1>,
42
+ arg2: AccessorChain<V2>,
43
+ arg3: AccessorChain<V3>,
44
+ arg4: AccessorChain<V4>,
45
+ compute: (v1: V1, v2: V2, v3: V3, v4: V4) => R
46
+ ): Computable<R>;
@@ -1,6 +1,6 @@
1
- import { AccessorChain } from "../core";
2
-
3
- export function isAccessorChain(value: any): boolean;
4
- export function isAccessorChain<V>(value: AccessorChain<V>): true;
5
-
6
- export function createAccessorModelProxy<M>(): AccessorChain<M>;
1
+ import { AccessorChain } from "../core";
2
+
3
+ export function isAccessorChain(value: any): boolean;
4
+ export function isAccessorChain<V>(value: AccessorChain<V>): true;
5
+
6
+ export function createAccessorModelProxy<M>(): AccessorChain<M>;
@@ -1,61 +1,61 @@
1
- import { Binding, isBinding } from "./Binding";
2
- import { isSelector } from "./isSelector";
3
- import { getSelector } from "./getSelector";
4
- import { isObject } from "../util/isObject";
5
- import { isAccessorChain } from "./createAccessorModelProxy";
6
-
7
- /*
8
- Accessor provides a common ground between refs and bindings.
9
- Refs offer simplicity, bindings have better performance with more arguments.
10
- Accessor works as a common interface which works with both patterns.
11
- */
12
-
13
- export function getAccessor(accessor, options) {
14
- if (accessor == null) return null;
15
-
16
- if (isObject(accessor)) {
17
- if (accessor.isAccessor || accessor.isRef) return accessor;
18
- if (isBinding(accessor)) {
19
- let binding = Binding.get(accessor);
20
- return {
21
- get: binding.value,
22
- set: (v, store) => store.set(binding.path, v),
23
- isAccessor: true,
24
- };
25
- }
26
- }
27
-
28
- if (isAccessorChain(accessor)) {
29
- let binding = Binding.get(accessor);
30
- return {
31
- get: binding.value,
32
- set: (v, store) => store.set(binding.path, v),
33
- isAccessor: true,
34
- };
35
- }
36
-
37
- if (isSelector(accessor)) {
38
- let selector = getSelector(accessor);
39
- if (accessor && accessor.set)
40
- return {
41
- get: selector,
42
- isAccessor: true,
43
- bindInstance(instance) {
44
- return {
45
- get: selector,
46
- set: (value) => accessor.set(value, instance),
47
- isAccessor: true,
48
- };
49
- },
50
- };
51
-
52
- return {
53
- get: selector,
54
- isAccessor: true,
55
- };
56
- }
57
-
58
- return {
59
- get: () => accessor,
60
- };
61
- }
1
+ import { Binding, isBinding } from "./Binding";
2
+ import { isSelector } from "./isSelector";
3
+ import { getSelector } from "./getSelector";
4
+ import { isObject } from "../util/isObject";
5
+ import { isAccessorChain } from "./createAccessorModelProxy";
6
+
7
+ /*
8
+ Accessor provides a common ground between refs and bindings.
9
+ Refs offer simplicity, bindings have better performance with more arguments.
10
+ Accessor works as a common interface which works with both patterns.
11
+ */
12
+
13
+ export function getAccessor(accessor, options) {
14
+ if (accessor == null) return null;
15
+
16
+ if (isObject(accessor)) {
17
+ if (accessor.isAccessor || accessor.isRef) return accessor;
18
+ if (isBinding(accessor)) {
19
+ let binding = Binding.get(accessor);
20
+ return {
21
+ get: binding.value,
22
+ set: (v, store) => store.set(binding.path, v),
23
+ isAccessor: true,
24
+ };
25
+ }
26
+ }
27
+
28
+ if (isAccessorChain(accessor)) {
29
+ let binding = Binding.get(accessor);
30
+ return {
31
+ get: binding.value,
32
+ set: (v, store) => store.set(binding.path, v),
33
+ isAccessor: true,
34
+ };
35
+ }
36
+
37
+ if (isSelector(accessor)) {
38
+ let selector = getSelector(accessor);
39
+ if (accessor && accessor.set)
40
+ return {
41
+ get: selector,
42
+ isAccessor: true,
43
+ bindInstance(instance) {
44
+ return {
45
+ get: selector,
46
+ set: (value) => accessor.set(value, instance),
47
+ isAccessor: true,
48
+ };
49
+ },
50
+ };
51
+
52
+ return {
53
+ get: selector,
54
+ isAccessor: true,
55
+ };
56
+ }
57
+
58
+ return {
59
+ get: () => accessor,
60
+ };
61
+ }