@zajno/common 1.2.6 → 1.3.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/coverage/clover.xml +410 -144
- package/coverage/coverage-final.json +38 -30
- package/coverage/lcov-report/index.html +34 -19
- package/coverage/lcov-report/src/__tests__/helpers/index.html +1 -1
- package/coverage/lcov-report/src/__tests__/helpers/main.ts.html +1 -1
- package/coverage/lcov-report/src/async/arrays.ts.html +5 -5
- package/coverage/lcov-report/src/async/index.html +1 -1
- package/coverage/lcov-report/src/dates/calc.ts.html +1 -1
- package/coverage/lcov-report/src/dates/convert.ts.html +1 -1
- package/coverage/lcov-report/src/dates/datex.ts.html +1 -1
- package/coverage/lcov-report/src/dates/format.ts.html +1 -1
- package/coverage/lcov-report/src/dates/index.html +1 -1
- package/coverage/lcov-report/src/dates/index.ts.html +1 -1
- package/coverage/lcov-report/src/dates/parse.ts.html +1 -1
- package/coverage/lcov-report/src/dates/period.ts.html +1 -1
- package/coverage/lcov-report/src/dates/shift.ts.html +1 -1
- package/coverage/lcov-report/src/dates/types.ts.html +1 -1
- package/coverage/lcov-report/src/dates/yearDate.ts.html +1 -1
- package/coverage/lcov-report/src/enumHelper.ts.html +11 -11
- package/coverage/lcov-report/src/event.ts.html +3 -3
- package/coverage/lcov-report/src/index.html +49 -19
- package/coverage/lcov-report/src/lazy.light.ts.html +155 -0
- package/coverage/lcov-report/src/logger/console.ts.html +1 -1
- package/coverage/lcov-report/src/logger/index.html +1 -1
- package/coverage/lcov-report/src/logger/index.ts.html +1 -1
- package/coverage/lcov-report/src/logger/named.ts.html +1 -1
- package/coverage/lcov-report/src/logger/proxy.ts.html +1 -1
- package/coverage/lcov-report/src/math/arrays.ts.html +1 -1
- package/coverage/lcov-report/src/math/calc.ts.html +1 -1
- package/coverage/lcov-report/src/math/distribution.ts.html +1 -1
- package/coverage/lcov-report/src/math/index.html +1 -1
- package/coverage/lcov-report/src/math/index.ts.html +1 -1
- package/coverage/lcov-report/src/transitionObserver.ts.html +113 -41
- package/coverage/lcov-report/src/types.ts.html +143 -0
- package/coverage/lcov-report/src/validation/ValidationErrors.ts.html +22 -22
- package/coverage/lcov-report/src/validation/creditCard.ts.html +4 -4
- package/coverage/lcov-report/src/validation/helpers.ts.html +6 -6
- package/coverage/lcov-report/src/validation/index.html +1 -1
- package/coverage/lcov-report/src/validation/index.ts.html +6 -6
- package/coverage/lcov-report/src/validation/types.ts.html +2 -2
- package/coverage/lcov-report/src/validation/validators.ts.html +5 -5
- package/coverage/lcov-report/src/validation/wrappers.ts.html +5 -5
- package/coverage/lcov-report/src/viewModels/FlagModel.ts.html +209 -0
- package/coverage/lcov-report/src/viewModels/LabeledFlagModel.ts.html +146 -0
- package/coverage/lcov-report/src/viewModels/MultiSelectModel.ts.html +530 -0
- package/coverage/lcov-report/src/viewModels/NumberModel.ts.html +188 -0
- package/coverage/lcov-report/{enumHelper.ts.html → src/viewModels/SelectModel.ts.html} +158 -152
- package/coverage/lcov-report/src/viewModels/SelectViewModel.ts.html +434 -0
- package/coverage/lcov-report/src/viewModels/Validatable.ts.html +329 -0
- package/coverage/lcov-report/src/viewModels/index.html +186 -0
- package/coverage/lcov-report/src/viewModels/wrappers.ts.html +239 -0
- package/coverage/lcov-report/transitionObserver.ts.html +77 -41
- package/coverage/lcov.info +765 -184
- package/lib/timeHelper.d.ts +3 -0
- package/lib/timeHelper.d.ts.map +1 -1
- package/lib/timeHelper.js +3 -0
- package/lib/timeHelper.js.map +1 -1
- package/lib/transitionObserver.d.ts +3 -1
- package/lib/transitionObserver.d.ts.map +1 -1
- package/lib/transitionObserver.js +25 -5
- package/lib/transitionObserver.js.map +1 -1
- package/lib/types.d.ts +5 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +14 -0
- package/lib/types.js.map +1 -1
- package/lib/viewModels/FlagModel.d.ts +19 -0
- package/lib/viewModels/FlagModel.d.ts.map +1 -0
- package/lib/viewModels/FlagModel.js +38 -0
- package/lib/viewModels/FlagModel.js.map +1 -0
- package/lib/viewModels/MultiSelectModel.d.ts +41 -0
- package/lib/viewModels/MultiSelectModel.d.ts.map +1 -0
- package/lib/viewModels/MultiSelectModel.js +150 -0
- package/lib/viewModels/MultiSelectModel.js.map +1 -0
- package/lib/viewModels/NumberModel.d.ts +16 -0
- package/lib/viewModels/NumberModel.d.ts.map +1 -0
- package/lib/viewModels/NumberModel.js +40 -0
- package/lib/viewModels/NumberModel.js.map +1 -0
- package/lib/viewModels/PromptModal.d.ts +31 -0
- package/lib/viewModels/PromptModal.d.ts.map +1 -0
- package/lib/viewModels/PromptModal.js +57 -0
- package/lib/viewModels/PromptModal.js.map +1 -0
- package/lib/viewModels/{SelectViewModel.d.ts → SelectModel.d.ts} +14 -8
- package/lib/viewModels/SelectModel.d.ts.map +1 -0
- package/lib/viewModels/SelectModel.js +109 -0
- package/lib/viewModels/SelectModel.js.map +1 -0
- package/lib/viewModels/{TextInputViewModel.d.ts → TextModel.d.ts} +10 -9
- package/lib/viewModels/TextModel.d.ts.map +1 -0
- package/lib/viewModels/{TextInputViewModel.js → TextModel.js} +8 -23
- package/lib/viewModels/TextModel.js.map +1 -0
- package/lib/viewModels/Validatable.d.ts +9 -7
- package/lib/viewModels/Validatable.d.ts.map +1 -1
- package/lib/viewModels/Validatable.js +22 -8
- package/lib/viewModels/Validatable.js.map +1 -1
- package/lib/viewModels/ValuesCollector.d.ts +28 -0
- package/lib/viewModels/ValuesCollector.d.ts.map +1 -0
- package/lib/viewModels/ValuesCollector.js +51 -0
- package/lib/viewModels/ValuesCollector.js.map +1 -0
- package/lib/viewModels/index.d.ts +7 -5
- package/lib/viewModels/index.d.ts.map +1 -1
- package/lib/viewModels/index.js +7 -5
- package/lib/viewModels/index.js.map +1 -1
- package/lib/viewModels/wrappers.d.ts +15 -0
- package/lib/viewModels/wrappers.d.ts.map +1 -0
- package/lib/viewModels/wrappers.js +43 -0
- package/lib/viewModels/wrappers.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/transitionObserver.test.ts +10 -5
- package/src/timeHelper.ts +3 -0
- package/src/transitionObserver.ts +32 -8
- package/src/types.ts +16 -0
- package/src/viewModels/FlagModel.ts +43 -0
- package/src/viewModels/MultiSelectModel.ts +150 -0
- package/src/viewModels/NumberModel.ts +36 -0
- package/src/viewModels/PromptModal.ts +65 -0
- package/src/viewModels/SelectModel.ts +125 -0
- package/src/viewModels/{TextInputViewModel.ts → TextModel.ts} +22 -26
- package/src/viewModels/Validatable.ts +26 -11
- package/src/viewModels/ValuesCollector.ts +84 -0
- package/src/viewModels/__tests__/multiSelect.test.ts +23 -0
- package/src/viewModels/__tests__/select.test.ts +71 -0
- package/src/viewModels/__tests__/wrappers.test.ts +79 -0
- package/src/viewModels/index.ts +9 -5
- package/src/viewModels/wrappers.ts +53 -0
- package/yarn-error.log +3709 -0
- package/lib/viewModels/PromptModalViewModel.d.ts +0 -27
- package/lib/viewModels/PromptModalViewModel.d.ts.map +0 -1
- package/lib/viewModels/PromptModalViewModel.js +0 -56
- package/lib/viewModels/PromptModalViewModel.js.map +0 -1
- package/lib/viewModels/RadioButtonGroupViewModel.d.ts +0 -11
- package/lib/viewModels/RadioButtonGroupViewModel.d.ts.map +0 -1
- package/lib/viewModels/RadioButtonGroupViewModel.js +0 -51
- package/lib/viewModels/RadioButtonGroupViewModel.js.map +0 -1
- package/lib/viewModels/RadioButtonViewModel.d.ts +0 -9
- package/lib/viewModels/RadioButtonViewModel.d.ts.map +0 -1
- package/lib/viewModels/RadioButtonViewModel.js +0 -32
- package/lib/viewModels/RadioButtonViewModel.js.map +0 -1
- package/lib/viewModels/SelectViewModel.d.ts.map +0 -1
- package/lib/viewModels/SelectViewModel.js +0 -88
- package/lib/viewModels/SelectViewModel.js.map +0 -1
- package/lib/viewModels/TextInputViewModel.d.ts.map +0 -1
- package/lib/viewModels/TextInputViewModel.js.map +0 -1
- package/src/viewModels/PromptModalViewModel.ts +0 -71
- package/src/viewModels/RadioButtonGroupViewModel.ts +0 -47
- package/src/viewModels/RadioButtonViewModel.ts +0 -26
- package/src/viewModels/SelectViewModel.ts +0 -88
|
@@ -178,7 +178,7 @@ describe('TransitionObserver', () => {
|
|
|
178
178
|
expect(cb).not.toHaveBeenCalled();
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
it('
|
|
181
|
+
it('promises 2 times', async () => {
|
|
182
182
|
|
|
183
183
|
const store = createStore<boolean>(true);
|
|
184
184
|
const cb = jest.fn();
|
|
@@ -187,12 +187,17 @@ describe('TransitionObserver', () => {
|
|
|
187
187
|
.to(false)
|
|
188
188
|
.cb(cb);
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
for (let i = 1; i <= 2; ++i) {
|
|
191
|
+
store.setValue(true);
|
|
191
192
|
|
|
192
|
-
|
|
193
|
+
const p = to.getPromise();
|
|
193
194
|
|
|
194
|
-
|
|
195
|
-
|
|
195
|
+
store.setValue(false);
|
|
196
|
+
|
|
197
|
+
await expect(p).resolves.toBe(false);
|
|
198
|
+
expect(cb).not.toHaveBeenCalled();
|
|
199
|
+
cb.mockReset();
|
|
200
|
+
}
|
|
196
201
|
});
|
|
197
202
|
|
|
198
203
|
it('promising – aborting', async () => {
|
package/src/timeHelper.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { observable, makeObservable } from 'mobx';
|
|
2
2
|
|
|
3
|
+
/** @deprecated */
|
|
3
4
|
export function formatMS(ms: number): string {
|
|
4
5
|
if (!ms && ms !== 0) {
|
|
5
6
|
return '';
|
|
@@ -12,6 +13,7 @@ export function formatMS(ms: number): string {
|
|
|
12
13
|
return `${hours ? hours + ':' : ''}${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec}`;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/** @deprecated */
|
|
15
17
|
export function formatTime(n: number): string {
|
|
16
18
|
if (n < 10) {
|
|
17
19
|
return '0' + n;
|
|
@@ -20,6 +22,7 @@ export function formatTime(n: number): string {
|
|
|
20
22
|
return n.toString();
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
/** @deprecated */
|
|
23
26
|
export function secToFormattedMin(totalSec: number): string {
|
|
24
27
|
const sec = Math.round(totalSec) % 60;
|
|
25
28
|
const min = Math.floor((totalSec + 1) / 60);
|
|
@@ -17,8 +17,8 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
17
17
|
private _cb: (v: T) => any;
|
|
18
18
|
private _fireOnce = false;
|
|
19
19
|
|
|
20
|
-
private _promise: Promise<
|
|
21
|
-
private _promiseReject: (err
|
|
20
|
+
private _promise: Promise<T> = null;
|
|
21
|
+
private _promiseReject: (err?: any) => any = null;
|
|
22
22
|
|
|
23
23
|
private logger: ILogger = createLogger('', true);
|
|
24
24
|
|
|
@@ -31,6 +31,9 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
31
31
|
public get event(): IEvent<T> { return this._event; }
|
|
32
32
|
public get currentValue() { return this._prev; }
|
|
33
33
|
|
|
34
|
+
public get isObserving() { return this._disposer != null; }
|
|
35
|
+
private get isPromising() { return this._promiseReject != null; }
|
|
36
|
+
|
|
34
37
|
observe(getter: () => T) {
|
|
35
38
|
this.dispose();
|
|
36
39
|
this._getter = getter;
|
|
@@ -50,6 +53,9 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
cb(cb: (v: T) => any) {
|
|
56
|
+
if (this.isPromising) {
|
|
57
|
+
throw new Error('Cannot set callback when promise is running');
|
|
58
|
+
}
|
|
53
59
|
this._cb = cb;
|
|
54
60
|
return this;
|
|
55
61
|
}
|
|
@@ -75,12 +81,29 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
75
81
|
return this;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
getPromise() {
|
|
84
|
+
getPromise(timeout: number = null) {
|
|
79
85
|
if (!this._promise) {
|
|
80
|
-
this.
|
|
86
|
+
if (!this.isObserving) {
|
|
87
|
+
return Promise.reject(new Error('Cannot get promise for disposed TransitionObserver'));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this._promise = new Promise<T>((resolve, reject) => {
|
|
81
91
|
this._promiseReject = reject;
|
|
82
|
-
|
|
92
|
+
|
|
93
|
+
let timeoutHandle: any = null;
|
|
94
|
+
if (timeout) {
|
|
95
|
+
timeoutHandle = setTimeout(() => {
|
|
96
|
+
this._finishPromise(this._promiseReject, new Error(`TransitionObserver Aborted – timed out after ${timeout}ms`));
|
|
97
|
+
}, timeout);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this._cb = (v => {
|
|
101
|
+
clearTimeout(timeoutHandle);
|
|
102
|
+
this._finishPromise(resolve, v);
|
|
103
|
+
});
|
|
104
|
+
this.forceCheck();
|
|
83
105
|
});
|
|
106
|
+
this.logger.log('started a new promise...');
|
|
84
107
|
}
|
|
85
108
|
return this._promise;
|
|
86
109
|
}
|
|
@@ -100,8 +123,9 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
100
123
|
this.logger.log(' disposing... ');
|
|
101
124
|
if (this._disposer) {
|
|
102
125
|
this._disposer();
|
|
126
|
+
this._disposer = null;
|
|
103
127
|
}
|
|
104
|
-
if (this.
|
|
128
|
+
if (this.isPromising) {
|
|
105
129
|
this._finishPromise(this._promiseReject, new Error('TransitionObserver Aborted'));
|
|
106
130
|
}
|
|
107
131
|
};
|
|
@@ -141,12 +165,12 @@ export class TransitionObserver<T> implements IDisposable {
|
|
|
141
165
|
return trigger;
|
|
142
166
|
};
|
|
143
167
|
|
|
144
|
-
private _finishPromise(cb: (
|
|
168
|
+
private _finishPromise<T>(cb: (a?: T) => any, arg?: T) {
|
|
145
169
|
this._promise = null;
|
|
146
170
|
this._promiseReject = null;
|
|
147
171
|
this._cb = null;
|
|
148
172
|
if (cb) {
|
|
149
|
-
cb(
|
|
173
|
+
cb(arg);
|
|
150
174
|
}
|
|
151
175
|
}
|
|
152
176
|
}
|
package/src/types.ts
CHANGED
|
@@ -3,3 +3,19 @@ export { DeepPartial } from './deepPartial';
|
|
|
3
3
|
export type DeepReadonly<T> = {
|
|
4
4
|
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
|
5
5
|
};
|
|
6
|
+
|
|
7
|
+
export type Getter<T> = (() => T) | T | null;
|
|
8
|
+
|
|
9
|
+
export namespace Getter {
|
|
10
|
+
export function getValue<T>(getter: Getter<T>): T {
|
|
11
|
+
if (getter == null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (typeof getter === 'function') {
|
|
15
|
+
return (getter as () => T)();
|
|
16
|
+
}
|
|
17
|
+
return getter;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Predicate<T> = (value: T) => boolean;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { action, makeObservable, observable } from 'mobx';
|
|
2
|
+
import { ILabel } from './wrappers';
|
|
3
|
+
import { IValueModel } from './ValuesCollector';
|
|
4
|
+
|
|
5
|
+
export interface IFlagModel extends IValueModel<boolean> {
|
|
6
|
+
toggle(): void;
|
|
7
|
+
reset(): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type IFlagModelReadonly = {
|
|
11
|
+
readonly value: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ILabeledFlagModel = IFlagModel & ILabel<string>;
|
|
15
|
+
|
|
16
|
+
export class FlagModel implements IFlagModel, IFlagModelReadonly {
|
|
17
|
+
|
|
18
|
+
@observable
|
|
19
|
+
private _value: boolean = false;
|
|
20
|
+
|
|
21
|
+
constructor(initial = false) {
|
|
22
|
+
makeObservable(this);
|
|
23
|
+
this._value = initial;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get value() {
|
|
27
|
+
return this._value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
set value(value: boolean) {
|
|
31
|
+
this._value = value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@action
|
|
35
|
+
toggle = () => {
|
|
36
|
+
this._value = !this._value;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
@action
|
|
40
|
+
reset = () => {
|
|
41
|
+
this._value = false;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createLazy } from '../lazy.light';
|
|
2
|
+
import { action, computed, makeObservable, observable, reaction } from 'mobx';
|
|
3
|
+
import { FlagModel, ILabeledFlagModel } from './FlagModel';
|
|
4
|
+
import { ValidatableModel } from './Validatable';
|
|
5
|
+
import { IValueModel } from './ValuesCollector';
|
|
6
|
+
import { withLabel } from './wrappers';
|
|
7
|
+
|
|
8
|
+
export class MultiSelect<T = any> extends ValidatableModel<ReadonlyArray<T>> implements IValueModel<readonly string[]> {
|
|
9
|
+
|
|
10
|
+
@observable
|
|
11
|
+
private _indexes = new Set<number>();
|
|
12
|
+
|
|
13
|
+
public readonly opened = new FlagModel();
|
|
14
|
+
private readonly _initial: number[] = null;
|
|
15
|
+
|
|
16
|
+
private readonly _flags = createLazy(() => this.createFlags());
|
|
17
|
+
private _indexesLocked = false;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly _items: readonly T[],
|
|
21
|
+
private readonly _accessor: (item: T) => string,
|
|
22
|
+
...selected: number[]
|
|
23
|
+
) {
|
|
24
|
+
super();
|
|
25
|
+
makeObservable(this);
|
|
26
|
+
this._initial = selected;
|
|
27
|
+
this.setInitialIndexes();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@computed
|
|
31
|
+
get selectedIndexes(): ReadonlyArray<number> { return Array.from(this._indexes); }
|
|
32
|
+
|
|
33
|
+
get items(): ReadonlyArray<T> { return this._items; }
|
|
34
|
+
|
|
35
|
+
get flags() { return this._flags.value; }
|
|
36
|
+
|
|
37
|
+
@computed
|
|
38
|
+
get values(): ReadonlyArray<string> {
|
|
39
|
+
return this._items.map(i => this._accessor(i));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@computed
|
|
43
|
+
get selectedItems(): ReadonlyArray<T> {
|
|
44
|
+
return this.selectedIndexes.map(i => this._items[i]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@computed
|
|
48
|
+
get selectedValues(): ReadonlyArray<string> {
|
|
49
|
+
const values = this.values;
|
|
50
|
+
return this.selectedIndexes.map(i => values[i]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get value() { return this.selectedValues; }
|
|
54
|
+
set value(v: readonly string[]) { this.selectValues(v); }
|
|
55
|
+
|
|
56
|
+
isIndexSelected(index: number) { return this._indexes.has(index); }
|
|
57
|
+
isValueSelected(value: string) { return this.values.includes(value); }
|
|
58
|
+
|
|
59
|
+
get isEmpty() { return this._indexes.size === 0; }
|
|
60
|
+
|
|
61
|
+
protected get valueToValidate() { return this.selectedItems; }
|
|
62
|
+
|
|
63
|
+
setItemSelected = (item: T, selected: boolean) => {
|
|
64
|
+
const i = this.items.indexOf(item);
|
|
65
|
+
if (i >= 0) {
|
|
66
|
+
this.setIndexSelected(i, selected);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
selectItem = (item: T) => this.setItemSelected(item, true);
|
|
71
|
+
deSelectItem = (item: T) => this.setItemSelected(item, false);
|
|
72
|
+
|
|
73
|
+
@action
|
|
74
|
+
selectItems = (items: readonly T[]) => {
|
|
75
|
+
items.forEach(this.selectItem);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
setValueSelected = (value: string, selected: boolean) => {
|
|
79
|
+
const i = this.values.indexOf(value);
|
|
80
|
+
if (i >= 0) {
|
|
81
|
+
this.setIndexSelected(i, selected);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
selectValue = (value: string) => this.setValueSelected(value, true);
|
|
86
|
+
deSelectValue = (value: string) => this.setValueSelected(value, false);
|
|
87
|
+
|
|
88
|
+
@action
|
|
89
|
+
selectValues = (values: readonly string[]) => {
|
|
90
|
+
values.forEach(this.selectValue);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
@action
|
|
94
|
+
setIndexSelected = (index: number, selected: boolean) => {
|
|
95
|
+
if (this._indexesLocked) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (selected) {
|
|
100
|
+
this._indexes.add(index);
|
|
101
|
+
} else {
|
|
102
|
+
this._indexes.delete(index);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!this._flags.hasValue) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
this._indexesLocked = true;
|
|
111
|
+
this._flags.value[index].value = selected;
|
|
112
|
+
} finally {
|
|
113
|
+
this._indexesLocked = false;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
reset = () => {
|
|
118
|
+
super.reset();
|
|
119
|
+
this.setInitialIndexes();
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
private setInitialIndexes() {
|
|
123
|
+
this._indexes.clear();
|
|
124
|
+
this._initial.forEach(i => this._indexes.add(i));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private createFlags() {
|
|
128
|
+
const flags: ReadonlyArray<ILabeledFlagModel> = this._items
|
|
129
|
+
.map((item, index) => {
|
|
130
|
+
const flag = withLabel(
|
|
131
|
+
new FlagModel(this._indexes.has(index)),
|
|
132
|
+
() => this._accessor(item),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// react on every flag is changed directly
|
|
136
|
+
reaction(() => flag.value, isSelected => {
|
|
137
|
+
this.setIndexSelected(index, isSelected);
|
|
138
|
+
});
|
|
139
|
+
return flag;
|
|
140
|
+
});
|
|
141
|
+
return flags;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class MultiSelectString<T extends string = string> extends MultiSelect<T> {
|
|
146
|
+
|
|
147
|
+
constructor(items: ReadonlyArray<T>, ...selected: number[]) {
|
|
148
|
+
super(items, v => v, ...selected);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { action, makeObservable, observable } from 'mobx';
|
|
2
|
+
import { IValueModel } from './ValuesCollector';
|
|
3
|
+
|
|
4
|
+
export interface INumberModel {
|
|
5
|
+
value: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class NumberModel implements INumberModel, IValueModel<number> {
|
|
9
|
+
|
|
10
|
+
@observable
|
|
11
|
+
private _value: number = 0;
|
|
12
|
+
|
|
13
|
+
private _initial: number = 0;
|
|
14
|
+
|
|
15
|
+
constructor(initial: number = 0) {
|
|
16
|
+
makeObservable(this);
|
|
17
|
+
this._initial = initial;
|
|
18
|
+
this._value = this._initial;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get value() { return this._value; }
|
|
22
|
+
set value(v: number) { this._value = v; }
|
|
23
|
+
|
|
24
|
+
@action
|
|
25
|
+
reset = () => {
|
|
26
|
+
this._value = this._initial;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
@action
|
|
30
|
+
increment = (d = 1) => this.value += d;
|
|
31
|
+
|
|
32
|
+
@action
|
|
33
|
+
decrement = (d = 1) => this.value -= d;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default NumberModel;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { observable, makeObservable, action } from 'mobx';
|
|
2
|
+
import { FlagModel } from './FlagModel';
|
|
3
|
+
|
|
4
|
+
export type BaseModalAction = {
|
|
5
|
+
title?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export class ModalActionModel<T extends BaseModalAction = BaseModalAction> {
|
|
10
|
+
public readonly isActive = new FlagModel();
|
|
11
|
+
|
|
12
|
+
@observable.ref
|
|
13
|
+
private _currentAction: T = null;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
makeObservable(this);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get currentAction() { return this._currentAction; }
|
|
20
|
+
|
|
21
|
+
@action
|
|
22
|
+
public openModal = (action: T) => {
|
|
23
|
+
this._currentAction = action;
|
|
24
|
+
this.isActive.value = true;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
@action
|
|
28
|
+
public closeModal = () => {
|
|
29
|
+
this.isActive.value = false;
|
|
30
|
+
this._currentAction = null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
protected runAction = async (cb: () => Promise<void> | void, close = true, awaitAction = false) => {
|
|
34
|
+
if (cb) {
|
|
35
|
+
const promise = cb();
|
|
36
|
+
if (awaitAction) {
|
|
37
|
+
await promise;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (close) {
|
|
42
|
+
this.closeModal();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type PromptModalAction = BaseModalAction & {
|
|
48
|
+
confirmText?: string;
|
|
49
|
+
rejectText?: string;
|
|
50
|
+
onConfirm?: () => Promise<void> | void;
|
|
51
|
+
onReject?: () => Promise<void> | void;
|
|
52
|
+
awaitActions?: boolean;
|
|
53
|
+
modalImage?: any;
|
|
54
|
+
confirmColor?: string;
|
|
55
|
+
rejectColor?: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export class PromptModalViewModel extends ModalActionModel<PromptModalAction> {
|
|
59
|
+
get confirmColor() { return this.currentAction.confirmColor; }
|
|
60
|
+
|
|
61
|
+
get rejectColor() { return this.currentAction.rejectColor; }
|
|
62
|
+
|
|
63
|
+
onConfirm = () => this.runAction(this.currentAction.onConfirm, true, this.currentAction.awaitActions);
|
|
64
|
+
onReject = () => this.runAction(this.currentAction.onConfirm, true, this.currentAction.awaitActions);
|
|
65
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createLazy } from '../lazy.light';
|
|
2
|
+
import { observable, computed, makeObservable, reaction } from 'mobx';
|
|
3
|
+
import { FlagModel, ILabeledFlagModel } from './FlagModel';
|
|
4
|
+
import { ValidatableModel } from './Validatable';
|
|
5
|
+
import { IValueModel } from './ValuesCollector';
|
|
6
|
+
import { withLabel } from './wrappers';
|
|
7
|
+
|
|
8
|
+
export class Select<T = any> extends ValidatableModel<T> implements IValueModel<string> {
|
|
9
|
+
@observable
|
|
10
|
+
private _index: number = undefined;
|
|
11
|
+
|
|
12
|
+
public readonly opened = new FlagModel();
|
|
13
|
+
private _indexLocked = false;
|
|
14
|
+
private _initialIndex: number = null;
|
|
15
|
+
|
|
16
|
+
private readonly _flags = createLazy(() => this.createFlags());
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly _items: readonly T[],
|
|
20
|
+
private readonly _accessor: (item: T) => string,
|
|
21
|
+
initialIndex: number = 0,
|
|
22
|
+
) {
|
|
23
|
+
super();
|
|
24
|
+
makeObservable(this);
|
|
25
|
+
|
|
26
|
+
this._initialIndex = initialIndex;
|
|
27
|
+
this._index = initialIndex;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected get valueToValidate() { return this.selectedItem; }
|
|
31
|
+
|
|
32
|
+
@computed
|
|
33
|
+
get values(): readonly string[] {
|
|
34
|
+
return this._items.map(i => this._accessor(i));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get flags() {
|
|
38
|
+
return this._flags.value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get items() {
|
|
42
|
+
return this._items;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get value() { return this.selectedValue; }
|
|
46
|
+
get selectedValue() {
|
|
47
|
+
const vs = this.values;
|
|
48
|
+
return vs.length ? vs[this._index] : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
set value(v: string) { this.selectedValue = v; }
|
|
52
|
+
set selectedValue(value: string) {
|
|
53
|
+
const index = this.values.indexOf(value);
|
|
54
|
+
if (index >= 0) {
|
|
55
|
+
this.index = index;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get selectedItem(): T {
|
|
60
|
+
return this._items.length ? this._items[this._index] : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
set selectedItem(item: T) {
|
|
64
|
+
const index = this._items.indexOf(item);
|
|
65
|
+
if (index >= 0) {
|
|
66
|
+
this.index = index;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get index() {
|
|
71
|
+
return this._index;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
set index(val: number) {
|
|
75
|
+
if (this._indexLocked) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this._index = val;
|
|
80
|
+
|
|
81
|
+
// update all flags to be properly selected
|
|
82
|
+
try {
|
|
83
|
+
this._indexLocked = true;
|
|
84
|
+
|
|
85
|
+
if (this._flags.hasValue) {
|
|
86
|
+
this._flags.value.forEach((f, i) => f.value = (i === this._index));
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
this._indexLocked = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
reset = () => {
|
|
94
|
+
super.reset();
|
|
95
|
+
this.index = this._initialIndex;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
private createFlags() {
|
|
99
|
+
const flags: ReadonlyArray<ILabeledFlagModel> = this._items
|
|
100
|
+
.map((item, index) => {
|
|
101
|
+
const flag: ILabeledFlagModel = withLabel(
|
|
102
|
+
new FlagModel(index === this.index),
|
|
103
|
+
() => this._accessor(item),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// react on every flag is changed directly
|
|
107
|
+
reaction(() => flag.value, isSelected => {
|
|
108
|
+
if (isSelected) {
|
|
109
|
+
this.index = index;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return flag;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return flags;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
export class SelectString<T extends string = string> extends Select<T> {
|
|
122
|
+
constructor(items: readonly T[], initialIndex: number = 0) {
|
|
123
|
+
super(items, v => v, initialIndex);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
import { observable,
|
|
1
|
+
import { observable, computed, makeObservable, reaction } from 'mobx';
|
|
2
|
+
import { Getter } from '../types';
|
|
2
3
|
import logger from '../logger';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export type StringGetter = (() => string) | string;
|
|
4
|
+
import { ValidatableModel, ValidationConfig } from './Validatable';
|
|
5
|
+
import { IValueModel } from './ValuesCollector';
|
|
6
6
|
|
|
7
7
|
export type TextInputConfig = {
|
|
8
|
-
name?:
|
|
9
|
-
title?:
|
|
10
|
-
value?:
|
|
8
|
+
name?: Getter<string>;
|
|
9
|
+
title?: Getter<string>;
|
|
10
|
+
value?: Getter<string>;
|
|
11
11
|
async?: boolean;
|
|
12
12
|
|
|
13
|
-
validation?: ValidationConfig
|
|
13
|
+
validation?: ValidationConfig<string>;
|
|
14
14
|
noSubscribe?: boolean;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
function FromGetter(getter:
|
|
18
|
-
if (typeof getter
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} else {
|
|
22
|
-
autorun(() => {
|
|
23
|
-
setter(getter());
|
|
24
|
-
}, { delay: autorunDelay });
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
} else if (typeof getter === 'string') {
|
|
28
|
-
setter(getter);
|
|
17
|
+
function FromGetter(getter: Getter<string>, setter: (val: string) => void, autorunDelay: number = null, noAutorun: boolean = null) {
|
|
18
|
+
if (noAutorun || typeof getter !== 'function') {
|
|
19
|
+
setter(Getter.getValue(getter));
|
|
20
|
+
return null;
|
|
29
21
|
}
|
|
30
|
-
|
|
22
|
+
|
|
23
|
+
return reaction(
|
|
24
|
+
() => Getter.getValue(getter),
|
|
25
|
+
setter,
|
|
26
|
+
{ delay: autorunDelay, fireImmediately: true },
|
|
27
|
+
);
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
export class Text {
|
|
34
31
|
@observable
|
|
35
32
|
private _value: string = null;
|
|
36
33
|
|
|
37
|
-
constructor(config: { value:
|
|
34
|
+
constructor(config: { value: Getter<string>, async?: boolean, noSubscribe?: boolean }) {
|
|
38
35
|
makeObservable(this);
|
|
39
36
|
FromGetter(config.value, val => this._value = val, config.async ? 100 : null, config.noSubscribe);
|
|
40
37
|
}
|
|
@@ -42,7 +39,7 @@ export class Text {
|
|
|
42
39
|
get value() { return this._value; }
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
export class TextInputVM extends
|
|
42
|
+
export class TextInputVM extends ValidatableModel implements IValueModel<string> {
|
|
46
43
|
@observable
|
|
47
44
|
private _value = '';
|
|
48
45
|
|
|
@@ -55,7 +52,7 @@ export class TextInputVM extends ValidatableViewModel {
|
|
|
55
52
|
@observable
|
|
56
53
|
private _title: string = null;
|
|
57
54
|
|
|
58
|
-
private readonly _valueObserving:
|
|
55
|
+
private readonly _valueObserving: () => void = null;
|
|
59
56
|
|
|
60
57
|
constructor(config?: TextInputConfig) {
|
|
61
58
|
super(config && config.validation);
|
|
@@ -100,13 +97,12 @@ export class TextInputVM extends ValidatableViewModel {
|
|
|
100
97
|
super.reset();
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
protected get valueToValidate() { return this.value; }
|
|
100
|
+
protected get valueToValidate() { return (this.value ?? '').trim(); }
|
|
104
101
|
|
|
105
102
|
private onBlur() {
|
|
106
103
|
this.validate();
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
@action
|
|
110
106
|
reset() {
|
|
111
107
|
this._value = '';
|
|
112
108
|
this._focused = false;
|