@zajno/common 1.2.8 → 1.3.2
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 +587 -275
- package/coverage/coverage-final.json +39 -30
- package/coverage/lcov-report/NumberModel.ts.html +188 -0
- package/coverage/lcov-report/arrays.ts.html +602 -0
- package/coverage/lcov-report/calc.ts.html +278 -0
- package/coverage/lcov-report/enumHelper.ts.html +449 -0
- package/coverage/lcov-report/index.html +48 -33
- package/coverage/lcov-report/src/__tests__/helpers/index.html +1 -1
- package/coverage/lcov-report/src/__tests__/helpers/main.ts.html +2 -2
- 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 +41 -11
- package/coverage/lcov-report/src/lazy.light.ts.html +155 -0
- package/coverage/lcov-report/src/logger/batch.ts.html +107 -0
- package/coverage/lcov-report/src/logger/console.ts.html +10 -25
- package/coverage/lcov-report/src/logger/index.html +54 -39
- package/coverage/lcov-report/src/logger/index.ts.html +88 -61
- package/coverage/lcov-report/src/logger/named.ts.html +31 -31
- package/coverage/lcov-report/src/logger/proxy.ts.html +13 -13
- package/coverage/lcov-report/src/math/arrays.ts.html +269 -32
- package/coverage/lcov-report/src/math/calc.ts.html +11 -11
- package/coverage/lcov-report/src/math/distribution.ts.html +2 -2
- package/coverage/lcov-report/src/math/index.html +11 -11
- package/coverage/lcov-report/src/math/index.ts.html +6 -6
- package/coverage/lcov-report/src/transitionObserver.ts.html +5 -5
- package/coverage/lcov-report/src/types.ts.html +158 -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 +212 -0
- package/coverage/lcov-report/src/viewModels/LabeledFlagModel.ts.html +137 -0
- package/coverage/lcov-report/src/viewModels/MultiSelectModel.ts.html +563 -0
- package/coverage/lcov-report/src/viewModels/NumberModel.ts.html +197 -0
- package/coverage/lcov-report/src/viewModels/SelectModel.ts.html +464 -0
- package/coverage/lcov-report/src/viewModels/SelectViewModel.ts.html +437 -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/labeled.ts.html +128 -0
- package/coverage/lcov-report/src/viewModels/wrappers.ts.html +227 -0
- package/coverage/lcov-report/transitionObserver.ts.html +41 -77
- package/coverage/lcov.info +1128 -438
- package/lib/event.d.ts.map +1 -1
- package/lib/event.js +1 -1
- package/lib/event.js.map +1 -1
- package/lib/logger/batch.d.ts +3 -0
- package/lib/logger/batch.d.ts.map +1 -0
- package/lib/logger/batch.js +12 -0
- package/lib/logger/batch.js.map +1 -0
- package/lib/logger/console.d.ts +0 -1
- package/lib/logger/console.d.ts.map +1 -1
- package/lib/logger/console.js +0 -3
- package/lib/logger/console.js.map +1 -1
- package/lib/logger/file.d.ts +15 -0
- package/lib/logger/file.d.ts.map +1 -0
- package/lib/logger/file.js +43 -0
- package/lib/logger/file.js.map +1 -0
- package/lib/logger/index.d.ts +7 -6
- package/lib/logger/index.d.ts.map +1 -1
- package/lib/logger/index.js +34 -21
- package/lib/logger/index.js.map +1 -1
- package/lib/logger/named.js +3 -3
- package/lib/logger/named.js.map +1 -1
- package/lib/logger/proxy.d.ts +1 -1
- package/lib/logger/proxy.d.ts.map +1 -1
- package/lib/logger/proxy.js +2 -2
- package/lib/logger/proxy.js.map +1 -1
- package/lib/math/arrays.d.ts +15 -0
- package/lib/math/arrays.d.ts.map +1 -1
- package/lib/math/arrays.js +69 -1
- package/lib/math/arrays.js.map +1 -1
- package/lib/transitionObserver.d.ts.map +1 -1
- package/lib/transitionObserver.js +2 -2
- package/lib/transitionObserver.js.map +1 -1
- package/lib/types.d.ts +9 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +18 -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 +39 -0
- package/lib/viewModels/FlagModel.js.map +1 -0
- package/lib/viewModels/MultiSelectModel.d.ts +45 -0
- package/lib/viewModels/MultiSelectModel.d.ts.map +1 -0
- package/lib/viewModels/MultiSelectModel.js +162 -0
- package/lib/viewModels/MultiSelectModel.js.map +1 -0
- package/lib/viewModels/NumberModel.d.ts +18 -0
- package/lib/viewModels/NumberModel.d.ts.map +1 -0
- package/lib/viewModels/NumberModel.js +41 -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/SelectModel.d.ts +33 -0
- package/lib/viewModels/SelectModel.d.ts.map +1 -0
- package/lib/viewModels/SelectModel.js +110 -0
- package/lib/viewModels/SelectModel.js.map +1 -0
- package/lib/viewModels/{TextInputViewModel.d.ts → TextModel.d.ts} +12 -10
- package/lib/viewModels/TextModel.d.ts.map +1 -0
- package/lib/viewModels/{TextInputViewModel.js → TextModel.js} +13 -28
- 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 +26 -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 +8 -5
- package/lib/viewModels/index.d.ts.map +1 -1
- package/lib/viewModels/index.js +8 -5
- package/lib/viewModels/index.js.map +1 -1
- package/lib/viewModels/types.d.ts +16 -0
- package/lib/viewModels/types.d.ts.map +1 -0
- package/lib/viewModels/types.js +3 -0
- package/lib/viewModels/types.js.map +1 -0
- package/lib/viewModels/wrappers.d.ts +12 -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/event.ts +2 -2
- package/src/logger/__tests__/{index.test.ts → logger.test.ts} +97 -41
- package/src/logger/batch.ts +9 -0
- package/src/logger/console.ts +0 -5
- package/src/logger/file.ts +46 -0
- package/src/logger/index.ts +37 -28
- package/src/logger/named.ts +3 -3
- package/src/logger/proxy.ts +2 -2
- package/src/math/__tests__/arrays.test.ts +53 -0
- package/src/math/arrays.ts +79 -0
- package/src/transitionObserver.ts +2 -2
- package/src/types.ts +21 -0
- package/src/viewModels/FlagModel.ts +44 -0
- package/src/viewModels/MultiSelectModel.ts +161 -0
- package/src/viewModels/NumberModel.ts +39 -0
- package/src/viewModels/PromptModal.ts +65 -0
- package/src/viewModels/SelectModel.ts +128 -0
- package/src/viewModels/{TextInputViewModel.ts → TextModel.ts} +25 -28
- package/src/viewModels/Validatable.ts +26 -11
- package/src/viewModels/ValuesCollector.ts +81 -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 +10 -5
- package/src/viewModels/types.ts +19 -0
- package/src/viewModels/wrappers.ts +49 -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 +0 -25
- 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
- package/yarn-error.log +0 -3709
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { action, makeObservable, observable } from 'mobx';
|
|
2
|
+
import { IResetableModel } from 'viewModels';
|
|
3
|
+
import { ILabel, IValueModel } from './types';
|
|
4
|
+
|
|
5
|
+
export interface IFlagModel extends IValueModel<boolean>, IResetableModel {
|
|
6
|
+
toggle(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type IFlagModelReadonly = {
|
|
10
|
+
readonly value: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type ILabeledFlagModel = IFlagModel & ILabel<string>;
|
|
14
|
+
|
|
15
|
+
export class FlagModel implements IFlagModel, IFlagModelReadonly {
|
|
16
|
+
|
|
17
|
+
@observable
|
|
18
|
+
private _value: boolean = false;
|
|
19
|
+
|
|
20
|
+
constructor(initial = false) {
|
|
21
|
+
makeObservable(this);
|
|
22
|
+
this._value = initial;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get value() {
|
|
26
|
+
return this._value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set value(value: boolean) {
|
|
30
|
+
this._value = value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get isDefault() { return this._value === false; }
|
|
34
|
+
|
|
35
|
+
@action
|
|
36
|
+
toggle = () => {
|
|
37
|
+
this._value = !this._value;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
@action
|
|
41
|
+
reset = () => {
|
|
42
|
+
this._value = false;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
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 './types';
|
|
6
|
+
import { withLabel } from './wrappers';
|
|
7
|
+
import { ICountableModel, IResetableModel } from 'viewModels';
|
|
8
|
+
import { arraysCompareDistinct } from '../math';
|
|
9
|
+
|
|
10
|
+
export class MultiSelect<T = any> extends ValidatableModel<ReadonlyArray<T>> implements IValueModel<readonly string[]>, IResetableModel, ICountableModel {
|
|
11
|
+
|
|
12
|
+
@observable
|
|
13
|
+
private readonly _indexes = new Set<number>();
|
|
14
|
+
|
|
15
|
+
public readonly opened = new FlagModel();
|
|
16
|
+
private readonly _initial: number[] = null;
|
|
17
|
+
|
|
18
|
+
private readonly _flags = createLazy(() => this.createFlags());
|
|
19
|
+
private _indexesLocked = false;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
private readonly _items: readonly T[],
|
|
23
|
+
private readonly _accessor: (item: T) => string,
|
|
24
|
+
...selected: number[]
|
|
25
|
+
) {
|
|
26
|
+
super();
|
|
27
|
+
makeObservable(this);
|
|
28
|
+
this._initial = selected;
|
|
29
|
+
this.setInitialIndexes();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@computed
|
|
33
|
+
get selectedIndexes(): ReadonlyArray<number> { return Array.from(this._indexes); }
|
|
34
|
+
|
|
35
|
+
get items(): ReadonlyArray<T> { return this._items; }
|
|
36
|
+
|
|
37
|
+
get flags() { return this._flags.value; }
|
|
38
|
+
|
|
39
|
+
@computed
|
|
40
|
+
get values(): ReadonlyArray<string> {
|
|
41
|
+
return this._items.map(i => this._accessor(i));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@computed
|
|
45
|
+
get selectedItems(): ReadonlyArray<T> {
|
|
46
|
+
return this.selectedIndexes.map(i => this._items[i]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@computed
|
|
50
|
+
get selectedValues(): ReadonlyArray<string> {
|
|
51
|
+
const values = this.values;
|
|
52
|
+
return this.selectedIndexes.map(i => values[i]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get value() { return this.selectedValues; }
|
|
56
|
+
set value(v: readonly string[]) { this.selectValues(v); }
|
|
57
|
+
|
|
58
|
+
isIndexSelected(index: number) { return this._indexes.has(index); }
|
|
59
|
+
isValueSelected(value: string) { return this.values.includes(value); }
|
|
60
|
+
|
|
61
|
+
get count() { return this._items.length; }
|
|
62
|
+
get selectedCount() { return this._indexes.size; }
|
|
63
|
+
get isEmpty() { return this.selectedCount === 0; }
|
|
64
|
+
|
|
65
|
+
@computed
|
|
66
|
+
get isDefault() { return arraysCompareDistinct(this.selectedIndexes, this._initial)?.diff === 0; }
|
|
67
|
+
|
|
68
|
+
protected get valueToValidate() { return this.selectedItems; }
|
|
69
|
+
|
|
70
|
+
setItemSelected = (item: T, selected: boolean) => {
|
|
71
|
+
const i = this.items.indexOf(item);
|
|
72
|
+
if (i >= 0) {
|
|
73
|
+
this.setIndexSelected(i, selected);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
selectItem = (item: T) => this.setItemSelected(item, true);
|
|
78
|
+
deSelectItem = (item: T) => this.setItemSelected(item, false);
|
|
79
|
+
|
|
80
|
+
@action
|
|
81
|
+
selectItems = (items: readonly T[]) => {
|
|
82
|
+
items.forEach(this.selectItem);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
setValueSelected = (value: string, selected: boolean) => {
|
|
86
|
+
const i = this.values.indexOf(value);
|
|
87
|
+
if (i >= 0) {
|
|
88
|
+
this.setIndexSelected(i, selected);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
selectValue = (value: string) => this.setValueSelected(value, true);
|
|
93
|
+
deSelectValue = (value: string) => this.setValueSelected(value, false);
|
|
94
|
+
|
|
95
|
+
@action
|
|
96
|
+
selectValues = (values: readonly string[]) => {
|
|
97
|
+
values.forEach(this.selectValue);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
@action
|
|
101
|
+
setIndexSelected = (index: number, selected: boolean) => {
|
|
102
|
+
if (this._indexesLocked) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (selected) {
|
|
107
|
+
this._indexes.add(index);
|
|
108
|
+
} else {
|
|
109
|
+
this._indexes.delete(index);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!this._flags.hasValue) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
this._indexesLocked = true;
|
|
118
|
+
this._flags.value[index].value = selected;
|
|
119
|
+
} finally {
|
|
120
|
+
this._indexesLocked = false;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
reset = () => {
|
|
125
|
+
super.reset();
|
|
126
|
+
this.setInitialIndexes();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
private setInitialIndexes() {
|
|
130
|
+
this._indexes.clear();
|
|
131
|
+
this._initial.forEach(i => this._indexes.add(i));
|
|
132
|
+
|
|
133
|
+
if (this._flags.hasValue) {
|
|
134
|
+
this._flags.value.forEach((flag, index) => flag.value = this._indexes.has(index));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private createFlags() {
|
|
139
|
+
const flags: ReadonlyArray<ILabeledFlagModel> = this._items
|
|
140
|
+
.map((item, index) => {
|
|
141
|
+
const flag = withLabel(
|
|
142
|
+
new FlagModel(this._indexes.has(index)),
|
|
143
|
+
() => this._accessor(item),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// react on every flag is changed directly
|
|
147
|
+
reaction(() => flag.value, isSelected => {
|
|
148
|
+
this.setIndexSelected(index, isSelected);
|
|
149
|
+
});
|
|
150
|
+
return flag;
|
|
151
|
+
});
|
|
152
|
+
return flags;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export class MultiSelectString<T extends string = string> extends MultiSelect<T> {
|
|
157
|
+
|
|
158
|
+
constructor(items: ReadonlyArray<T>, ...selected: number[]) {
|
|
159
|
+
super(items, v => v, ...selected);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { action, makeObservable, observable } from 'mobx';
|
|
2
|
+
import { IResetableModel } from 'viewModels';
|
|
3
|
+
import { IValueModel } from './types';
|
|
4
|
+
|
|
5
|
+
export interface INumberModel extends IResetableModel {
|
|
6
|
+
value: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class NumberModel implements INumberModel, IValueModel<number> {
|
|
10
|
+
|
|
11
|
+
@observable
|
|
12
|
+
private _value: number = 0;
|
|
13
|
+
|
|
14
|
+
private _initial: number = 0;
|
|
15
|
+
|
|
16
|
+
constructor(initial: number = 0) {
|
|
17
|
+
makeObservable(this);
|
|
18
|
+
this._initial = initial;
|
|
19
|
+
this._value = this._initial;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get value() { return this._value; }
|
|
23
|
+
set value(v: number) { this._value = v; }
|
|
24
|
+
|
|
25
|
+
get isDefault() { return this._value === this._initial; }
|
|
26
|
+
|
|
27
|
+
@action
|
|
28
|
+
reset = () => {
|
|
29
|
+
this._value = this._initial;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
@action
|
|
33
|
+
increment = (d = 1) => this.value += d;
|
|
34
|
+
|
|
35
|
+
@action
|
|
36
|
+
decrement = (d = 1) => this.value -= d;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
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,128 @@
|
|
|
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 './types';
|
|
6
|
+
import { withLabel } from './wrappers';
|
|
7
|
+
import { IResetableModel } from 'viewModels';
|
|
8
|
+
|
|
9
|
+
export class Select<T = any> extends ValidatableModel<T> implements IValueModel<string>, IResetableModel {
|
|
10
|
+
@observable
|
|
11
|
+
private _index: number = undefined;
|
|
12
|
+
|
|
13
|
+
public readonly opened = new FlagModel();
|
|
14
|
+
private _indexLocked = false;
|
|
15
|
+
private _initialIndex: number = null;
|
|
16
|
+
|
|
17
|
+
private readonly _flags = createLazy(() => this.createFlags());
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly _items: readonly T[],
|
|
21
|
+
private readonly _accessor: (item: T) => string,
|
|
22
|
+
initialIndex: number = 0,
|
|
23
|
+
) {
|
|
24
|
+
super();
|
|
25
|
+
makeObservable(this);
|
|
26
|
+
|
|
27
|
+
this._initialIndex = initialIndex;
|
|
28
|
+
this._index = initialIndex;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected get valueToValidate() { return this.selectedItem; }
|
|
32
|
+
|
|
33
|
+
@computed
|
|
34
|
+
get values(): readonly string[] {
|
|
35
|
+
return this._items.map(i => this._accessor(i));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get flags() {
|
|
39
|
+
return this._flags.value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get items() {
|
|
43
|
+
return this._items;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get value() { return this.selectedValue; }
|
|
47
|
+
get selectedValue() {
|
|
48
|
+
const vs = this.values;
|
|
49
|
+
return vs.length ? vs[this._index] : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
set value(v: string) { this.selectedValue = v; }
|
|
53
|
+
set selectedValue(value: string) {
|
|
54
|
+
const index = this.values.indexOf(value);
|
|
55
|
+
if (index >= 0) {
|
|
56
|
+
this.index = index;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get selectedItem(): T {
|
|
61
|
+
return this._items.length ? this._items[this._index] : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
set selectedItem(item: T) {
|
|
65
|
+
const index = this._items.indexOf(item);
|
|
66
|
+
if (index >= 0) {
|
|
67
|
+
this.index = index;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get isDefault() { return this._index === this._initialIndex; }
|
|
72
|
+
|
|
73
|
+
get index() {
|
|
74
|
+
return this._index;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
set index(val: number) {
|
|
78
|
+
if (this._indexLocked) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this._index = val;
|
|
83
|
+
|
|
84
|
+
// update all flags to be properly selected
|
|
85
|
+
try {
|
|
86
|
+
this._indexLocked = true;
|
|
87
|
+
|
|
88
|
+
if (this._flags.hasValue) {
|
|
89
|
+
this._flags.value.forEach((f, i) => f.value = (i === this._index));
|
|
90
|
+
}
|
|
91
|
+
} finally {
|
|
92
|
+
this._indexLocked = false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
reset = () => {
|
|
97
|
+
super.reset();
|
|
98
|
+
this.index = this._initialIndex;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
private createFlags() {
|
|
102
|
+
const flags: ReadonlyArray<ILabeledFlagModel> = this._items
|
|
103
|
+
.map((item, index) => {
|
|
104
|
+
const flag: ILabeledFlagModel = withLabel(
|
|
105
|
+
new FlagModel(index === this.index),
|
|
106
|
+
() => this._accessor(item),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// react on every flag is changed directly
|
|
110
|
+
reaction(() => flag.value, isSelected => {
|
|
111
|
+
if (isSelected) {
|
|
112
|
+
this.index = index;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return flag;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return flags;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
export class SelectString<T extends string = string> extends Select<T> {
|
|
125
|
+
constructor(items: readonly T[], initialIndex: number = 0) {
|
|
126
|
+
super(items, v => v, initialIndex);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,40 +1,38 @@
|
|
|
1
|
-
import { observable,
|
|
1
|
+
import { observable, computed, makeObservable, reaction } from 'mobx';
|
|
2
|
+
import { Getter } from '../types';
|
|
3
|
+
import { IValueModel } from './types';
|
|
2
4
|
import logger from '../logger';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export type StringGetter = (() => string) | string;
|
|
5
|
+
import { ValidatableModel, ValidationConfig } from './Validatable';
|
|
6
|
+
import { IResetableModel } from 'viewModels';
|
|
6
7
|
|
|
7
8
|
export type TextInputConfig = {
|
|
8
|
-
name?:
|
|
9
|
-
title?:
|
|
10
|
-
value?:
|
|
9
|
+
name?: Getter<string>;
|
|
10
|
+
title?: Getter<string>;
|
|
11
|
+
value?: Getter<string>;
|
|
11
12
|
async?: boolean;
|
|
12
13
|
|
|
13
|
-
validation?: ValidationConfig
|
|
14
|
+
validation?: ValidationConfig<string>;
|
|
14
15
|
noSubscribe?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
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);
|
|
18
|
+
function FromGetter(getter: Getter<string>, setter: (val: string) => void, autorunDelay: number = null, noAutorun: boolean = null) {
|
|
19
|
+
if (noAutorun || typeof getter !== 'function') {
|
|
20
|
+
setter(Getter.getValue(getter));
|
|
21
|
+
return null;
|
|
29
22
|
}
|
|
30
|
-
|
|
23
|
+
|
|
24
|
+
return reaction(
|
|
25
|
+
() => Getter.getValue(getter),
|
|
26
|
+
setter,
|
|
27
|
+
{ delay: autorunDelay, fireImmediately: true },
|
|
28
|
+
);
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
export class Text {
|
|
34
32
|
@observable
|
|
35
33
|
private _value: string = null;
|
|
36
34
|
|
|
37
|
-
constructor(config: { value:
|
|
35
|
+
constructor(config: { value: Getter<string>, async?: boolean, noSubscribe?: boolean }) {
|
|
38
36
|
makeObservable(this);
|
|
39
37
|
FromGetter(config.value, val => this._value = val, config.async ? 100 : null, config.noSubscribe);
|
|
40
38
|
}
|
|
@@ -42,7 +40,7 @@ export class Text {
|
|
|
42
40
|
get value() { return this._value; }
|
|
43
41
|
}
|
|
44
42
|
|
|
45
|
-
export class TextInputVM extends
|
|
43
|
+
export class TextInputVM extends ValidatableModel implements IValueModel<string>, IResetableModel {
|
|
46
44
|
@observable
|
|
47
45
|
private _value = '';
|
|
48
46
|
|
|
@@ -55,7 +53,7 @@ export class TextInputVM extends ValidatableViewModel {
|
|
|
55
53
|
@observable
|
|
56
54
|
private _title: string = null;
|
|
57
55
|
|
|
58
|
-
private readonly _valueObserving:
|
|
56
|
+
private readonly _valueObserving: () => void = null;
|
|
59
57
|
|
|
60
58
|
constructor(config?: TextInputConfig) {
|
|
61
59
|
super(config && config.validation);
|
|
@@ -100,17 +98,16 @@ export class TextInputVM extends ValidatableViewModel {
|
|
|
100
98
|
super.reset();
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
protected get valueToValidate() { return this.value; }
|
|
101
|
+
protected get valueToValidate() { return (this.value ?? '').trim(); }
|
|
104
102
|
|
|
105
103
|
private onBlur() {
|
|
106
104
|
this.validate();
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
|
|
110
|
-
reset() {
|
|
107
|
+
reset = () => {
|
|
111
108
|
this._value = '';
|
|
112
109
|
this._focused = false;
|
|
113
110
|
super.reset();
|
|
114
|
-
}
|
|
111
|
+
};
|
|
115
112
|
|
|
116
113
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { observable, makeObservable } from 'mobx';
|
|
1
|
+
import { observable, makeObservable, action } from 'mobx';
|
|
2
2
|
import { ValidatorFunction, ValidatorFunctionAsync, ValidationErrors, ValidationError } from '../validation';
|
|
3
3
|
import { someAsync } from '../async/arrays';
|
|
4
4
|
|
|
5
|
-
export type ValueValidator = ValidatorFunction | ValidatorFunctionAsync
|
|
5
|
+
export type ValueValidator<T> = ValidatorFunction<T> | ValidatorFunctionAsync<T>;
|
|
6
6
|
export type ValidationErrorsStrings = { [code: number]: string };
|
|
7
7
|
|
|
8
|
-
export type ValidationConfig = {
|
|
8
|
+
export type ValidationConfig<T> = {
|
|
9
|
+
validator: ValueValidator<Readonly<T>>,
|
|
10
|
+
errors: ValidationErrorsStrings,
|
|
11
|
+
};
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
const EmptyValidator = () => ValidationErrors.None;
|
|
14
|
+
export abstract class ValidatableModel<T = string> {
|
|
11
15
|
|
|
12
|
-
private _validator: ValueValidator = null;
|
|
16
|
+
private _validator: ValueValidator<Readonly<T>> = null;
|
|
13
17
|
private _strings: ValidationErrorsStrings = null;
|
|
14
18
|
|
|
15
19
|
@observable
|
|
@@ -17,25 +21,30 @@ export abstract class ValidatableViewModel {
|
|
|
17
21
|
|
|
18
22
|
private _validationError: ValidationError = null;
|
|
19
23
|
|
|
20
|
-
constructor(config?: ValidationConfig) {
|
|
24
|
+
constructor(config?: ValidationConfig<T>) {
|
|
21
25
|
makeObservable(this);
|
|
22
|
-
this.
|
|
23
|
-
this._strings = config && config.errors;
|
|
26
|
+
this.setValidationConfig(config);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
protected abstract get valueToValidate():
|
|
29
|
+
protected abstract get valueToValidate(): Readonly<T>;
|
|
27
30
|
|
|
28
31
|
get isValid() { return !this._error; }
|
|
29
32
|
|
|
30
33
|
get error() { return this._error; }
|
|
31
34
|
|
|
35
|
+
public setValidationConfig(config?: ValidationConfig<T>) {
|
|
36
|
+
this._validator = config?.validator || EmptyValidator;
|
|
37
|
+
this._strings = config?.errors;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
async validate() {
|
|
33
42
|
if (!this._validator) {
|
|
34
43
|
return true;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
try {
|
|
38
|
-
const valid = await this._validator(
|
|
47
|
+
const valid = await this._validator(this.valueToValidate);
|
|
39
48
|
this._validationError = valid === ValidationErrors.None
|
|
40
49
|
? null
|
|
41
50
|
: new ValidationError('Unknown error', valid);
|
|
@@ -52,12 +61,18 @@ export abstract class ValidatableViewModel {
|
|
|
52
61
|
return this._validationError == null;
|
|
53
62
|
}
|
|
54
63
|
|
|
64
|
+
async getIsInvalid() {
|
|
65
|
+
const valid = await this.validate();
|
|
66
|
+
return !valid;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@action
|
|
55
70
|
reset() {
|
|
56
71
|
this._validationError = null;
|
|
57
72
|
this._error = null;
|
|
58
73
|
}
|
|
59
74
|
|
|
60
|
-
static async IsSomeInvalid(validatables:
|
|
75
|
+
static async IsSomeInvalid(validatables: ReadonlyArray<Readonly<ValidatableModel>>, stopOnFail = true) {
|
|
61
76
|
if (stopOnFail) {
|
|
62
77
|
return someAsync(validatables, async v => !(await v.validate()));
|
|
63
78
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IValueModel } from './types';
|
|
2
|
+
|
|
3
|
+
export interface IValueCollector<TSource, TValue> {
|
|
4
|
+
getValue(source: TSource): TValue;
|
|
5
|
+
setValue(source: TSource, value: TValue): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type SimpleCollector<T> = {
|
|
9
|
+
get: () => T,
|
|
10
|
+
set: (t: T) => void,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type SimpleCollectorsMap<T> = {
|
|
14
|
+
[P in keyof T]?: SimpleCollector<T[P]>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ModelCollectorsMap<T> = {
|
|
18
|
+
[P in keyof T]?: IValueModel<T[P]>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type CollectorsMap<T> = {
|
|
22
|
+
[P in keyof T]?: SimpleCollector<T[P]>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class ModelCollector<T extends Object> {
|
|
26
|
+
|
|
27
|
+
private readonly _collectors: SimpleCollectorsMap<T> = { };
|
|
28
|
+
|
|
29
|
+
public addModels(models: ModelCollectorsMap<T>) {
|
|
30
|
+
Object.entries(models).forEach(pair => this.addModel(pair[0] as keyof T, pair[1]));
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public addModel<TKey extends keyof T, TSource extends IValueModel<T[TKey]>>(key: TKey, source: TSource) {
|
|
35
|
+
this._collectors[key] = {
|
|
36
|
+
get: () => source.value,
|
|
37
|
+
set: v => { source.value = v; },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public addCollector<TKey extends keyof T, TModel, TCollector extends IValueCollector<TModel, T[TKey]>>(key: TKey, model: TModel, collector: TCollector) {
|
|
44
|
+
this._collectors[key] = {
|
|
45
|
+
get: () => collector.getValue(model),
|
|
46
|
+
set: v => collector.setValue(model, v),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public remove(key: keyof T) {
|
|
53
|
+
delete this._collectors[key];
|
|
54
|
+
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public collect(): T {
|
|
59
|
+
const res = { } as T;
|
|
60
|
+
|
|
61
|
+
Object.entries(this._collectors).forEach(pair => {
|
|
62
|
+
const key = pair[0] as keyof T;
|
|
63
|
+
const collector = pair[1] as SimpleCollector<T[keyof T]>;
|
|
64
|
+
res[key] = collector.get();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return res;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public populate(data: T) {
|
|
71
|
+
Object.entries(data).forEach(pair => {
|
|
72
|
+
const key = pair[0] as keyof T;
|
|
73
|
+
const value = pair[1] as T[keyof T];
|
|
74
|
+
|
|
75
|
+
const collector = this._collectors[key];
|
|
76
|
+
if (collector) {
|
|
77
|
+
collector.set(value);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|