@websolutespa/bom-mixer-forms 0.3.1 → 0.3.3

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/CHANGELOG.md CHANGED
@@ -1,46 +1,63 @@
1
- # @websolutespa/bom-mixer-forms
2
-
3
- ## 0.3.1
4
-
5
- ### Patch Changes
6
-
7
- - Updating: dependencies
8
- - Updated dependencies
9
- - @websolutespa/bom-mixer-hooks@1.7.2
10
- - @websolutespa/bom-core@1.7.3
11
-
12
- ## 0.3.0
13
-
14
- ### Minor Changes
15
-
16
- - Updating: next 13.
17
-
18
- ## 0.2.2
19
-
20
- ### Patch Changes
21
-
22
- - Removed: unnecessary method deepCopy.
23
-
24
- ## 0.2.1
25
-
26
- ### Patch Changes
27
-
28
- - Added: source files.
29
-
30
- ## 0.2.0
31
-
32
- ### Minor Changes
33
-
34
- - Added: splat routes.
35
-
36
- ## 0.1.0
37
-
38
- ### Minor Changes
39
-
40
- - Added: @websolutespa/bom-core.
41
-
42
- ## 0.0.2
43
-
44
- ### Patch Changes
45
-
46
- - Added: first release.
1
+ # @websolutespa/bom-mixer-forms
2
+
3
+ ## 0.3.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Modified: validators, useFormBuilder
8
+ - Updated dependencies
9
+ - @websolutespa/bom-core@1.7.9
10
+
11
+ ## 0.3.2
12
+
13
+ ### Patch Changes
14
+
15
+ - Fixing: downgrading eslint to v8.56.0
16
+ - Updated dependencies
17
+ - @websolutespa/bom-mixer-hooks@1.7.4
18
+ - @websolutespa/bom-core@1.7.8
19
+
20
+ ## 0.3.1
21
+
22
+ ### Patch Changes
23
+
24
+ - Updating: dependencies
25
+ - Updated dependencies
26
+ - @websolutespa/bom-mixer-hooks@1.7.2
27
+ - @websolutespa/bom-core@1.7.3
28
+
29
+ ## 0.3.0
30
+
31
+ ### Minor Changes
32
+
33
+ - Updating: next 13.
34
+
35
+ ## 0.2.2
36
+
37
+ ### Patch Changes
38
+
39
+ - Removed: unnecessary method deepCopy.
40
+
41
+ ## 0.2.1
42
+
43
+ ### Patch Changes
44
+
45
+ - Added: source files.
46
+
47
+ ## 0.2.0
48
+
49
+ ### Minor Changes
50
+
51
+ - Added: splat routes.
52
+
53
+ ## 0.1.0
54
+
55
+ ### Minor Changes
56
+
57
+ - Added: @websolutespa/bom-core.
58
+
59
+ ## 0.0.2
60
+
61
+ ### Patch Changes
62
+
63
+ - Added: first release.
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ declare class FormAbstractCollection<T extends FormControls> extends FormAbstrac
16
16
  constructor(controls: T, validators?: (FormValidator | FormValidator[]));
17
17
  initControl_(controlOrValue: FormAbstract | any, key: any): FormAbstract;
18
18
  protected setInitialOptions(options?: FormOptions): void;
19
- protected checkAsyncPropState_(key: string, option?: FormActivator, root?: FormCollection): Promise<boolean>;
19
+ protected checkAsyncPropState_(key: keyof FormFlags, option?: FormActivator, root?: FormCollection): Promise<boolean>;
20
20
  updateState_(): void;
21
21
  revalidate_(): Promise<void>;
22
22
  protected validate_(root?: FormCollection): Promise<void>;
@@ -43,10 +43,10 @@ declare class FormAbstractCollection<T extends FormControls> extends FormAbstrac
43
43
  set submitted(submitted: boolean);
44
44
  set touched(touched: boolean);
45
45
  get value(): {
46
- [key: string]: any;
46
+ [key: string]: FormValue;
47
47
  };
48
48
  set value(value: {
49
- [key: string]: any;
49
+ [key: string]: FormValue;
50
50
  });
51
51
  get errors(): {
52
52
  [key: string]: any;
@@ -60,7 +60,7 @@ declare class FormArray extends FormAbstractCollection<FormAbstract[]> {
60
60
  constructor(controls?: FormAbstract[], validators?: FormValidator | FormValidator[], initialOptions?: FormOptions);
61
61
  forEach_(callback: (control: FormAbstract, key: number) => any): void;
62
62
  map_(): FormAbstract[];
63
- get value(): any[];
63
+ get value(): FormValue[];
64
64
  get length(): number;
65
65
  protected init(control: FormAbstract, key: number): void;
66
66
  set(control: FormAbstract, key: number): void;
@@ -74,9 +74,9 @@ declare class FormArray extends FormAbstractCollection<FormAbstract[]> {
74
74
  declare function formArray(controls?: FormAbstract[], validators?: FormValidator | FormValidator[]): FormArray;
75
75
 
76
76
  declare class FormControl extends FormAbstract {
77
- constructor(value?: any, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions);
77
+ constructor(value?: FormValue, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions);
78
78
  }
79
- declare function formControl(value?: any, validators?: FormValidator | FormValidator[]): FormControl;
79
+ declare function formControl(value?: FormValue, validators?: FormValidator | FormValidator[]): FormControl;
80
80
 
81
81
  declare class FormGroup extends FormAbstractCollection<{
82
82
  [key: string]: FormAbstract;
@@ -86,9 +86,14 @@ declare class FormGroup extends FormAbstractCollection<{
86
86
  }, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions);
87
87
  }
88
88
  declare function formGroup(controls?: {
89
- [key: string]: FormAbstract | any;
89
+ [key: string]: FormAbstract | FormValue;
90
90
  }, validators?: FormValidator | FormValidator[]): FormGroup;
91
91
 
92
+ type FormValue = any;
93
+ type FormValueGroup = {
94
+ [key: string]: FormValue;
95
+ };
96
+ type FormValueArray = FormValue[];
92
97
  type IControlParam = {
93
98
  uid: number;
94
99
  control: FormControl;
@@ -101,7 +106,7 @@ type FormOptions = {
101
106
  schema?: ControlType;
102
107
  name?: string;
103
108
  label?: string;
104
- value?: string;
109
+ value?: FormValue;
105
110
  placeholder?: string;
106
111
  required?: FormActivator;
107
112
  hidden?: FormActivator;
@@ -116,21 +121,34 @@ type ValidationError = {
116
121
  [key: string]: any;
117
122
  };
118
123
  type FormControls = {
119
- [key: string]: FormAbstract;
124
+ [key: string]: FormAbstract | FormValue;
120
125
  } | FormAbstract[];
121
126
  type FormCollection = FormAbstractCollection<FormControls>;
122
- type FormActivator = boolean | ((value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => boolean | Promise<boolean>);
123
- type FormValidator = (value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => null | ValidationError;
124
- type FormAsyncValidator = (value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => Promise<null | ValidationError>;
127
+ type FormActivator = boolean | ((value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => boolean | Promise<boolean>);
128
+ type FormValidator = (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => null | ValidationError;
129
+ type FormAsyncValidator = (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => Promise<null | ValidationError>;
125
130
  type FormFlags = {
126
- [key: string]: boolean;
131
+ invalid: boolean;
132
+ disabled: boolean;
133
+ hidden: boolean;
134
+ readonly: boolean;
135
+ dirty: boolean;
136
+ touched: boolean;
137
+ submitted: boolean;
138
+ valid: boolean;
139
+ enabled: boolean;
140
+ visible: boolean;
141
+ writeable: boolean;
142
+ pristine: boolean;
143
+ untouched: boolean;
144
+ unsubmitted: boolean;
127
145
  };
128
146
  type FormErrors = {
129
147
  [key: string]: any;
130
148
  };
131
149
  type FormValidationError = {
132
150
  key: string;
133
- value: any;
151
+ value: FormValue;
134
152
  };
135
153
  type FormValidationErrors = FormValidationError[];
136
154
  type FormState<T> = {
@@ -143,7 +161,7 @@ type IFormBuilderControlSchema = {
143
161
  schema: ControlType;
144
162
  name?: string;
145
163
  label?: string;
146
- value?: string;
164
+ value?: FormValue;
147
165
  placeholder?: string;
148
166
  required?: FormActivator;
149
167
  hidden?: FormActivator;
@@ -164,15 +182,12 @@ type IFormBuilderGroupValues = {
164
182
  [key: string]: FormGroup | FormArray | FormControl;
165
183
  };
166
184
  type IFormBuilderSchema = IFormBuilderGroupSchema | IFormBuilderArraySchema;
167
- type StateValue = StateValue[] | {
168
- [key: string]: StateValue;
169
- } | number | string | boolean | null | undefined;
170
185
 
171
186
  declare class FormAbstract extends EventEmitter {
172
187
  errors_: ValidationError;
173
- value_: any;
188
+ value_: FormValue;
174
189
  validators_: FormValidator[];
175
- state_: any;
190
+ state_: FormFlags;
176
191
  name?: string | number;
177
192
  parent?: FormCollection;
178
193
  schema: ControlType;
@@ -182,10 +197,10 @@ declare class FormAbstract extends EventEmitter {
182
197
  };
183
198
  protected initialOptions_?: FormOptions;
184
199
  private markAsDirty_;
185
- constructor(value: any, validators?: (FormValidator | FormValidator[]));
200
+ constructor(value: FormValue, validators?: (FormValidator | FormValidator[]));
186
201
  protected setInitialOptions(options?: FormOptions): void;
187
202
  protected checkAsyncState_(root?: FormCollection): Promise<boolean>;
188
- protected checkAsyncPropState_(key: string, option?: FormActivator, root?: FormCollection): Promise<boolean>;
203
+ protected checkAsyncPropState_(key: keyof FormFlags, option?: FormActivator, root?: FormCollection): Promise<boolean>;
189
204
  protected revalidate_(): Promise<void>;
190
205
  protected validate_(root?: FormCollection): Promise<void>;
191
206
  validateAndChange_(root?: FormCollection): Promise<void>;
@@ -193,7 +208,7 @@ declare class FormAbstract extends EventEmitter {
193
208
  protected change_(propagate?: boolean): void;
194
209
  protected updateState_(): void;
195
210
  reset(): void;
196
- patch(value: any): void;
211
+ patch(value: FormValue): void;
197
212
  addValidators(...validators: FormValidator[]): void;
198
213
  replaceValidators(...validators: FormValidator[]): void;
199
214
  clearValidators(): void;
@@ -207,34 +222,33 @@ declare class FormAbstract extends EventEmitter {
207
222
  set placeholder(placeholder: string);
208
223
  get validators(): FormValidator[];
209
224
  set validators(validators: FormValidator[]);
210
- get state(): any;
225
+ get state(): FormFlags;
211
226
  get errors(): ValidationError;
212
- get invalid(): any;
213
- get disabled(): any;
214
- set disabled(disabled: any);
215
- get hidden(): any;
216
- set hidden(hidden: any);
217
- get readonly(): any;
218
- set readonly(readonly: any);
219
- get dirty(): any;
220
- set dirty(dirty: any);
221
- get touched(): any;
222
- set touched(touched: any);
223
- get submitted(): any;
224
- set submitted(submitted: any);
225
- get valid(): any;
226
- get enabled(): any;
227
- get visible(): any;
228
- get writeable(): any;
229
- get pristine(): any;
230
- get untouched(): any;
231
- get unsubmitted(): any;
227
+ get invalid(): boolean;
228
+ get disabled(): boolean;
229
+ set disabled(disabled: boolean);
230
+ get hidden(): boolean;
231
+ set hidden(hidden: boolean);
232
+ get readonly(): boolean;
233
+ set readonly(readonly: boolean);
234
+ get dirty(): boolean;
235
+ set dirty(dirty: boolean);
236
+ get touched(): boolean;
237
+ set touched(touched: boolean);
238
+ get submitted(): boolean;
239
+ set submitted(submitted: boolean);
240
+ get valid(): boolean;
241
+ get enabled(): boolean;
242
+ get visible(): boolean;
243
+ get writeable(): boolean;
244
+ get pristine(): boolean;
245
+ get untouched(): boolean;
246
+ get unsubmitted(): boolean;
232
247
  get value(): any;
233
248
  set value(value: any);
234
249
  }
235
250
 
236
- declare function validValue(value: any): any;
237
- declare function isThenable(result: any): any;
251
+ declare function validValue(value: FormValue): any;
238
252
  declare function mapErrors_(errors: FormErrors): FormValidationError[];
239
253
  declare function valueToString(value: IOption | IOption[] | IEquatable | IEquatable[] | null): string | string[] | undefined;
240
254
  declare function stringToValue(value: string | string[] | undefined, options?: IOption[], optionsExtra?: {
@@ -249,7 +263,7 @@ declare function EmailValidator(): FormValidator;
249
263
  /**
250
264
  * an equality match validation on another field
251
265
  */
252
- declare function MatchValidator(getOtherValue: (value: any, rootValue: any, control?: FormAbstract, root?: FormAbstract) => any): FormValidator;
266
+ declare function MatchValidator(getOtherValue: (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormAbstract) => any): FormValidator;
253
267
 
254
268
  /**
255
269
  * a max string length validator
@@ -284,7 +298,7 @@ declare function PatternValidator(pattern: string | RegExp): FormValidator;
284
298
  /**
285
299
  * a required dependant on another field
286
300
  */
287
- declare function RequiredIfValidator(condition: (value: any, rootValue: any, control?: FormAbstract, root?: FormAbstract) => boolean): FormValidator;
301
+ declare function RequiredIfValidator(condition: (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormAbstract) => boolean): FormValidator;
288
302
 
289
303
  /**
290
304
  * a required and true validator
@@ -302,4 +316,4 @@ declare function useForm<T, U extends (FormGroup | FormArray)>(factory: () => U,
302
316
 
303
317
  declare function useFormBuilder<T, U extends (FormGroup | FormArray)>(schema: IFormBuilderSchema, deps?: DependencyList): [FormState<T>, (value: Partial<T>) => void, () => void, () => void, U];
304
318
 
305
- export { ControlType, EmailValidator, FormAbstract, FormAbstractCollection, FormActivator, FormArray, FormAsyncValidator, FormCollection, FormControl, FormControls, FormErrors, FormFlags, FormGroup, FormOptions, FormState, FormValidationError, FormValidationErrors, FormValidator, IControlParam, IFormBuilderArraySchema, IFormBuilderControlSchema, IFormBuilderGroupSchema, IFormBuilderGroupValues, IFormBuilderSchema, IFormOption, MatchValidator, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NullValidator, PatternValidator, RequiredIfValidator, RequiredTrueValidator, RequiredValidator, StateValue, ValidationError, formArray, formControl, formGroup, isThenable, mapErrors_, stringToValue, useControl, useForm, useFormBuilder, validValue, valueToString };
319
+ export { ControlType, EmailValidator, FormAbstract, FormAbstractCollection, FormActivator, FormArray, FormAsyncValidator, FormCollection, FormControl, FormControls, FormErrors, FormFlags, FormGroup, FormOptions, FormState, FormValidationError, FormValidationErrors, FormValidator, FormValue, FormValueArray, FormValueGroup, IControlParam, IFormBuilderArraySchema, IFormBuilderControlSchema, IFormBuilderGroupSchema, IFormBuilderGroupValues, IFormBuilderSchema, IFormOption, MatchValidator, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NullValidator, PatternValidator, RequiredIfValidator, RequiredTrueValidator, RequiredValidator, ValidationError, formArray, formControl, formGroup, mapErrors_, stringToValue, useControl, useForm, useFormBuilder, validValue, valueToString };
package/dist/index.js CHANGED
@@ -73,7 +73,6 @@ __export(src_exports, {
73
73
  formArray: () => formArray,
74
74
  formControl: () => formControl,
75
75
  formGroup: () => formGroup,
76
- isThenable: () => isThenable,
77
76
  mapErrors_: () => mapErrors_,
78
77
  stringToValue: () => stringToValue,
79
78
  useControl: () => useControl,
@@ -84,6 +83,9 @@ __export(src_exports, {
84
83
  });
85
84
  module.exports = __toCommonJS(src_exports);
86
85
 
86
+ // src/forms/form-abstract.ts
87
+ var import_bom_core = require("@websolutespa/bom-core");
88
+
87
89
  // src/forms/event-emitter.ts
88
90
  var EventEmitter = class {
89
91
  constructor() {
@@ -123,9 +125,6 @@ var EventEmitter = class {
123
125
  function validValue(value) {
124
126
  return value !== void 0 && value !== "" ? value : null;
125
127
  }
126
- function isThenable(result) {
127
- return result && typeof result.then === "function";
128
- }
129
128
  function mapErrors_(errors) {
130
129
  return Object.keys(errors).map((key) => ({ key, value: errors[key] }));
131
130
  }
@@ -233,7 +232,7 @@ var FormAbstract = class extends EventEmitter {
233
232
  let dirty = false;
234
233
  if (typeof option === "function") {
235
234
  let result = option(this.value_, root == null ? void 0 : root.value, this, root);
236
- result = isThenable(result) ? yield result : result;
235
+ result = (0, import_bom_core.isPromise)(result) ? yield result : result;
237
236
  if (this.state_[key] !== result) {
238
237
  this.state_[key] = result;
239
238
  dirty = true;
@@ -259,7 +258,7 @@ var FormAbstract = class extends EventEmitter {
259
258
  } else {
260
259
  const validations = this.validators_.map((x) => x(this.value_, root == null ? void 0 : root.value, this, root)).filter((x) => x);
261
260
  const { results, promises } = validations.reduce((p, c) => {
262
- isThenable(c) ? p.promises.push(c) : p.results.push(c);
261
+ (0, import_bom_core.isPromise)(c) ? p.promises.push(c) : p.results.push(c);
263
262
  return p;
264
263
  }, { results: [], promises: [] });
265
264
  promises.forEach((x) => x.then((result) => {
@@ -522,6 +521,9 @@ var FormAbstract = class extends EventEmitter {
522
521
  */
523
522
  };
524
523
 
524
+ // src/forms/form-abstract-collection.ts
525
+ var import_bom_core2 = require("@websolutespa/bom-core");
526
+
525
527
  // src/forms/form-control.ts
526
528
  var FormControl = class extends FormAbstract {
527
529
  constructor(value = null, validators, initialOptions) {
@@ -593,7 +595,7 @@ var FormAbstractCollection = class extends FormAbstract {
593
595
  let dirty = false;
594
596
  if (typeof option === "function") {
595
597
  let result = option(this.value_, root == null ? void 0 : root.value, this, root);
596
- result = isThenable(result) ? yield result : result;
598
+ result = (0, import_bom_core2.isPromise)(result) ? yield result : result;
597
599
  this.forEach_((control) => {
598
600
  if (control.state_[key] !== result) {
599
601
  control.state_[key] = result;
@@ -859,10 +861,11 @@ function formGroup(controls = {}, validators) {
859
861
  function EmailValidator() {
860
862
  const regex = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
861
863
  return function(value) {
862
- if (!value) {
864
+ if (typeof value === "string") {
865
+ return regex.test(value) ? null : { email: true };
866
+ } else {
863
867
  return null;
864
868
  }
865
- return regex.test(value) ? null : { email: true };
866
869
  };
867
870
  }
868
871
 
@@ -878,21 +881,25 @@ function MatchValidator(getOtherValue) {
878
881
  // src/forms/validators/max-length.validator.ts
879
882
  function MaxLengthValidator(maxlength) {
880
883
  return function(value) {
881
- if (value == null || maxlength == null) {
884
+ if (maxlength == null) {
885
+ return null;
886
+ }
887
+ if (typeof value === "string") {
888
+ const length = value ? value.length : 0;
889
+ return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
890
+ } else {
882
891
  return null;
883
892
  }
884
- const length = value ? value.length : 0;
885
- return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
886
893
  };
887
894
  }
888
895
 
889
896
  // src/forms/validators/max.validator.ts
890
897
  function MaxValidator(max) {
891
898
  return function(value) {
899
+ value = typeof value === "string" ? parseFloat(value) : typeof value === "number" ? value : null;
892
900
  if (value == null || max == null) {
893
901
  return null;
894
902
  }
895
- value = parseFloat(value);
896
903
  return !isNaN(value) && value > max ? { max: { max, actual: value } } : null;
897
904
  };
898
905
  }
@@ -900,21 +907,25 @@ function MaxValidator(max) {
900
907
  // src/forms/validators/min-length.validator.ts
901
908
  function MinLengthValidator(minlength) {
902
909
  return function(value) {
903
- if (value == null || minlength == null) {
910
+ if (minlength == null) {
911
+ return null;
912
+ }
913
+ if (typeof value === "string") {
914
+ const length = value ? value.length : 0;
915
+ return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
916
+ } else {
904
917
  return null;
905
918
  }
906
- const length = value ? value.length : 0;
907
- return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
908
919
  };
909
920
  }
910
921
 
911
922
  // src/forms/validators/min.validator.ts
912
923
  function MinValidator(min) {
913
924
  return function(value) {
925
+ value = typeof value === "string" ? parseFloat(value) : typeof value === "number" ? value : null;
914
926
  if (value == null || min == null) {
915
927
  return null;
916
928
  }
917
- value = parseFloat(value);
918
929
  return !isNaN(value) && value < min ? { min: { min, actual: value } } : null;
919
930
  };
920
931
  }
@@ -929,11 +940,15 @@ function NullValidator() {
929
940
  // src/forms/validators/pattern.validator.ts
930
941
  function PatternValidator(pattern) {
931
942
  return function(value) {
932
- if (value == null || pattern == null) {
943
+ if (pattern == null) {
944
+ return null;
945
+ }
946
+ if (typeof value === "string") {
947
+ const regex = patternToRegEx(pattern);
948
+ return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
949
+ } else {
933
950
  return null;
934
951
  }
935
- const regex = patternToRegEx(pattern);
936
- return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
937
952
  };
938
953
  }
939
954
  function patternToRegEx(pattern) {
@@ -949,10 +964,16 @@ function patternToRegEx(pattern) {
949
964
  }
950
965
 
951
966
  // src/forms/validators/required-if.validator.ts
967
+ var import_bom_core3 = require("@websolutespa/bom-core");
952
968
  function RequiredIfValidator(condition) {
953
969
  return function(value, rootValue, control, root) {
970
+ console.log("RequiredIfValidator", value, Boolean(condition(value, rootValue, control, root)));
954
971
  if (Boolean(condition(value, rootValue, control, root)) === true) {
955
- return value == null || value.length === 0 ? { required: true } : null;
972
+ if ((0, import_bom_core3.isArray)(value) || typeof value === "string") {
973
+ return value.length === 0 ? { required: true } : null;
974
+ } else {
975
+ return value == null ? { required: true } : null;
976
+ }
956
977
  } else {
957
978
  return null;
958
979
  }
@@ -967,9 +988,14 @@ function RequiredTrueValidator() {
967
988
  }
968
989
 
969
990
  // src/forms/validators/required.validator.ts
991
+ var import_bom_core4 = require("@websolutespa/bom-core");
970
992
  function RequiredValidator() {
971
993
  return function(value) {
972
- return value == null || value.length === 0 ? { required: true } : null;
994
+ if ((0, import_bom_core4.isArray)(value) || typeof value === "string") {
995
+ return value.length === 0 ? { required: true } : null;
996
+ } else {
997
+ return value == null ? { required: true } : null;
998
+ }
973
999
  };
974
1000
  }
975
1001
 
@@ -1053,7 +1079,7 @@ function useFormBuilder(schema, deps = []) {
1053
1079
  setState(newState);
1054
1080
  };
1055
1081
  collection.on("change", onChange);
1056
- collection.validateAndChange_();
1082
+ collection.revalidate_();
1057
1083
  return () => collection.off("change", onChange);
1058
1084
  }, deps);
1059
1085
  return [state, setValue, setTouched, reset, collection];
@@ -1105,7 +1131,6 @@ function mapSchema_(schema) {
1105
1131
  formArray,
1106
1132
  formControl,
1107
1133
  formGroup,
1108
- isThenable,
1109
1134
  mapErrors_,
1110
1135
  stringToValue,
1111
1136
  useControl,
package/dist/index.mjs CHANGED
@@ -35,6 +35,9 @@ var __async = (__this, __arguments, generator) => {
35
35
  });
36
36
  };
37
37
 
38
+ // src/forms/form-abstract.ts
39
+ import { isPromise } from "@websolutespa/bom-core";
40
+
38
41
  // src/forms/event-emitter.ts
39
42
  var EventEmitter = class {
40
43
  constructor() {
@@ -74,9 +77,6 @@ var EventEmitter = class {
74
77
  function validValue(value) {
75
78
  return value !== void 0 && value !== "" ? value : null;
76
79
  }
77
- function isThenable(result) {
78
- return result && typeof result.then === "function";
79
- }
80
80
  function mapErrors_(errors) {
81
81
  return Object.keys(errors).map((key) => ({ key, value: errors[key] }));
82
82
  }
@@ -184,7 +184,7 @@ var FormAbstract = class extends EventEmitter {
184
184
  let dirty = false;
185
185
  if (typeof option === "function") {
186
186
  let result = option(this.value_, root == null ? void 0 : root.value, this, root);
187
- result = isThenable(result) ? yield result : result;
187
+ result = isPromise(result) ? yield result : result;
188
188
  if (this.state_[key] !== result) {
189
189
  this.state_[key] = result;
190
190
  dirty = true;
@@ -210,7 +210,7 @@ var FormAbstract = class extends EventEmitter {
210
210
  } else {
211
211
  const validations = this.validators_.map((x) => x(this.value_, root == null ? void 0 : root.value, this, root)).filter((x) => x);
212
212
  const { results, promises } = validations.reduce((p, c) => {
213
- isThenable(c) ? p.promises.push(c) : p.results.push(c);
213
+ isPromise(c) ? p.promises.push(c) : p.results.push(c);
214
214
  return p;
215
215
  }, { results: [], promises: [] });
216
216
  promises.forEach((x) => x.then((result) => {
@@ -473,6 +473,9 @@ var FormAbstract = class extends EventEmitter {
473
473
  */
474
474
  };
475
475
 
476
+ // src/forms/form-abstract-collection.ts
477
+ import { isPromise as isPromise2 } from "@websolutespa/bom-core";
478
+
476
479
  // src/forms/form-control.ts
477
480
  var FormControl = class extends FormAbstract {
478
481
  constructor(value = null, validators, initialOptions) {
@@ -544,7 +547,7 @@ var FormAbstractCollection = class extends FormAbstract {
544
547
  let dirty = false;
545
548
  if (typeof option === "function") {
546
549
  let result = option(this.value_, root == null ? void 0 : root.value, this, root);
547
- result = isThenable(result) ? yield result : result;
550
+ result = isPromise2(result) ? yield result : result;
548
551
  this.forEach_((control) => {
549
552
  if (control.state_[key] !== result) {
550
553
  control.state_[key] = result;
@@ -810,10 +813,11 @@ function formGroup(controls = {}, validators) {
810
813
  function EmailValidator() {
811
814
  const regex = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
812
815
  return function(value) {
813
- if (!value) {
816
+ if (typeof value === "string") {
817
+ return regex.test(value) ? null : { email: true };
818
+ } else {
814
819
  return null;
815
820
  }
816
- return regex.test(value) ? null : { email: true };
817
821
  };
818
822
  }
819
823
 
@@ -829,21 +833,25 @@ function MatchValidator(getOtherValue) {
829
833
  // src/forms/validators/max-length.validator.ts
830
834
  function MaxLengthValidator(maxlength) {
831
835
  return function(value) {
832
- if (value == null || maxlength == null) {
836
+ if (maxlength == null) {
837
+ return null;
838
+ }
839
+ if (typeof value === "string") {
840
+ const length = value ? value.length : 0;
841
+ return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
842
+ } else {
833
843
  return null;
834
844
  }
835
- const length = value ? value.length : 0;
836
- return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
837
845
  };
838
846
  }
839
847
 
840
848
  // src/forms/validators/max.validator.ts
841
849
  function MaxValidator(max) {
842
850
  return function(value) {
851
+ value = typeof value === "string" ? parseFloat(value) : typeof value === "number" ? value : null;
843
852
  if (value == null || max == null) {
844
853
  return null;
845
854
  }
846
- value = parseFloat(value);
847
855
  return !isNaN(value) && value > max ? { max: { max, actual: value } } : null;
848
856
  };
849
857
  }
@@ -851,21 +859,25 @@ function MaxValidator(max) {
851
859
  // src/forms/validators/min-length.validator.ts
852
860
  function MinLengthValidator(minlength) {
853
861
  return function(value) {
854
- if (value == null || minlength == null) {
862
+ if (minlength == null) {
863
+ return null;
864
+ }
865
+ if (typeof value === "string") {
866
+ const length = value ? value.length : 0;
867
+ return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
868
+ } else {
855
869
  return null;
856
870
  }
857
- const length = value ? value.length : 0;
858
- return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
859
871
  };
860
872
  }
861
873
 
862
874
  // src/forms/validators/min.validator.ts
863
875
  function MinValidator(min) {
864
876
  return function(value) {
877
+ value = typeof value === "string" ? parseFloat(value) : typeof value === "number" ? value : null;
865
878
  if (value == null || min == null) {
866
879
  return null;
867
880
  }
868
- value = parseFloat(value);
869
881
  return !isNaN(value) && value < min ? { min: { min, actual: value } } : null;
870
882
  };
871
883
  }
@@ -880,11 +892,15 @@ function NullValidator() {
880
892
  // src/forms/validators/pattern.validator.ts
881
893
  function PatternValidator(pattern) {
882
894
  return function(value) {
883
- if (value == null || pattern == null) {
895
+ if (pattern == null) {
896
+ return null;
897
+ }
898
+ if (typeof value === "string") {
899
+ const regex = patternToRegEx(pattern);
900
+ return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
901
+ } else {
884
902
  return null;
885
903
  }
886
- const regex = patternToRegEx(pattern);
887
- return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
888
904
  };
889
905
  }
890
906
  function patternToRegEx(pattern) {
@@ -900,10 +916,16 @@ function patternToRegEx(pattern) {
900
916
  }
901
917
 
902
918
  // src/forms/validators/required-if.validator.ts
919
+ import { isArray } from "@websolutespa/bom-core";
903
920
  function RequiredIfValidator(condition) {
904
921
  return function(value, rootValue, control, root) {
922
+ console.log("RequiredIfValidator", value, Boolean(condition(value, rootValue, control, root)));
905
923
  if (Boolean(condition(value, rootValue, control, root)) === true) {
906
- return value == null || value.length === 0 ? { required: true } : null;
924
+ if (isArray(value) || typeof value === "string") {
925
+ return value.length === 0 ? { required: true } : null;
926
+ } else {
927
+ return value == null ? { required: true } : null;
928
+ }
907
929
  } else {
908
930
  return null;
909
931
  }
@@ -918,9 +940,14 @@ function RequiredTrueValidator() {
918
940
  }
919
941
 
920
942
  // src/forms/validators/required.validator.ts
943
+ import { isArray as isArray2 } from "@websolutespa/bom-core";
921
944
  function RequiredValidator() {
922
945
  return function(value) {
923
- return value == null || value.length === 0 ? { required: true } : null;
946
+ if (isArray2(value) || typeof value === "string") {
947
+ return value.length === 0 ? { required: true } : null;
948
+ } else {
949
+ return value == null ? { required: true } : null;
950
+ }
924
951
  };
925
952
  }
926
953
 
@@ -1004,7 +1031,7 @@ function useFormBuilder(schema, deps = []) {
1004
1031
  setState(newState);
1005
1032
  };
1006
1033
  collection.on("change", onChange);
1007
- collection.validateAndChange_();
1034
+ collection.revalidate_();
1008
1035
  return () => collection.off("change", onChange);
1009
1036
  }, deps);
1010
1037
  return [state, setValue, setTouched, reset, collection];
@@ -1055,7 +1082,6 @@ export {
1055
1082
  formArray,
1056
1083
  formControl,
1057
1084
  formGroup,
1058
- isThenable,
1059
1085
  mapErrors_,
1060
1086
  stringToValue,
1061
1087
  useControl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-mixer-forms",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Mixer Forms module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -34,7 +34,7 @@
34
34
  "@websolutespa/bom-cli": "*",
35
35
  "@websolutespa/test": "*",
36
36
  "@websolutespa/tsconfig": "*",
37
- "eslint": "^9.0.0",
37
+ "eslint": "^8.56.0",
38
38
  "eslint-config-websolute": "*",
39
39
  "raw-loader": "^4.0.2",
40
40
  "ts-node": "^10.9.2",
@@ -1,7 +1,7 @@
1
+ import { isPromise } from '@websolutespa/bom-core';
1
2
  import { FormAbstract } from './form-abstract';
2
3
  import { FormControl } from './form-control';
3
- import { FormActivator, FormCollection, FormControls, FormOptions, FormValidator } from './types';
4
- import { isThenable } from './utils';
4
+ import { FormActivator, FormCollection, FormControls, FormFlags, FormOptions, FormValidator, FormValue } from './types';
5
5
 
6
6
  export class FormAbstractCollection<T extends FormControls> extends FormAbstract {
7
7
 
@@ -72,12 +72,12 @@ export class FormAbstractCollection<T extends FormControls> extends FormAbstract
72
72
  this.updateState_();
73
73
  }
74
74
 
75
- protected async checkAsyncPropState_(key: string, option?: FormActivator, root?: FormCollection): Promise<boolean> {
75
+ protected async checkAsyncPropState_(key: keyof FormFlags, option?: FormActivator, root?: FormCollection): Promise<boolean> {
76
76
  let dirty = false;
77
77
  if (typeof option === 'function') {
78
78
  let result = option(this.value_, root?.value, this, root);
79
79
  // console.log('checkAsyncPropState_', result);
80
- result = isThenable(result) ? await result : result;
80
+ result = isPromise(result) ? await result : result;
81
81
  this.forEach_((control: FormAbstract) => {
82
82
  if (control.state_[key] !== result) {
83
83
  control.state_[key] = result;
@@ -280,8 +280,8 @@ export class FormAbstractCollection<T extends FormControls> extends FormAbstract
280
280
  });
281
281
  }
282
282
 
283
- get value(): { [key: string]: any } {
284
- return this.reduce_((result: { [key: string]: any }, control: FormAbstract, key: string) => {
283
+ get value(): { [key: string]: FormValue } {
284
+ return this.reduce_((result: { [key: string]: FormValue }, control: FormAbstract, key: string) => {
285
285
  if (control.enabled) {
286
286
  result[key] = control.value;
287
287
  }
@@ -289,7 +289,7 @@ export class FormAbstractCollection<T extends FormControls> extends FormAbstract
289
289
  }, {});
290
290
  }
291
291
 
292
- set value(value: { [key: string]: any }) {
292
+ set value(value: { [key: string]: FormValue }) {
293
293
  this.forEach_((control: FormAbstract, key: string) => {
294
294
  control.value = value[key];
295
295
  });
@@ -1,15 +1,15 @@
1
- import { IOption } from '@websolutespa/bom-core';
1
+ import { IOption, isPromise } from '@websolutespa/bom-core';
2
2
  import { EventEmitter } from './event-emitter';
3
- import { ControlType, FormActivator, FormCollection, FormOptions, FormValidator, ValidationError } from './types';
4
- import { isThenable, validValue } from './utils';
3
+ import { ControlType, FormActivator, FormCollection, FormFlags, FormOptions, FormValidator, FormValue, ValidationError } from './types';
4
+ import { validValue } from './utils';
5
5
 
6
6
  export class FormAbstract extends EventEmitter {
7
7
 
8
8
  // callbacks_: Function[] = [];
9
9
  errors_: ValidationError;
10
- value_: any;
10
+ value_: FormValue;
11
11
  validators_: FormValidator[];
12
- state_: any;
12
+ state_: FormFlags;
13
13
  name?: string | number;
14
14
  parent?: FormCollection;
15
15
 
@@ -20,7 +20,7 @@ export class FormAbstract extends EventEmitter {
20
20
  protected initialOptions_?: FormOptions;
21
21
  private markAsDirty_: boolean = false;
22
22
 
23
- constructor(value: any, validators?: (FormValidator | FormValidator[])) {
23
+ constructor(value: FormValue, validators?: (FormValidator | FormValidator[])) {
24
24
  super();
25
25
  this.errors_ = {};
26
26
  this.value_ = validValue(value);
@@ -164,11 +164,11 @@ export class FormAbstract extends EventEmitter {
164
164
  return dirty;
165
165
  }
166
166
 
167
- protected async checkAsyncPropState_(key: string, option?: FormActivator, root?: FormCollection): Promise<boolean> {
167
+ protected async checkAsyncPropState_(key: keyof FormFlags, option?: FormActivator, root?: FormCollection): Promise<boolean> {
168
168
  let dirty = false;
169
169
  if (typeof option === 'function') {
170
170
  let result = option(this.value_, root?.value, this, root);
171
- result = isThenable(result) ? await result : result;
171
+ result = isPromise(result) ? await result : result;
172
172
  if (this.state_[key] !== result) {
173
173
  this.state_[key] = result;
174
174
  dirty = true;
@@ -193,7 +193,7 @@ export class FormAbstract extends EventEmitter {
193
193
  } else {
194
194
  const validations = this.validators_.map((x) => x(this.value_, root?.value, this, root)).filter((x) => x);
195
195
  const { results, promises } = validations.reduce((p: { results: (null | ValidationError)[], promises: Promise<null | ValidationError>[] }, c: (null | ValidationError) | Promise<null | ValidationError>) => {
196
- isThenable(c) ? p.promises.push(c as Promise<null | ValidationError>) : p.results.push(c);
196
+ isPromise(c) ? p.promises.push(c as Promise<null | ValidationError>) : p.results.push(c);
197
197
  return p;
198
198
  }, { results: [], promises: [] });
199
199
  promises.forEach(x => x.then((result: null | ValidationError) => {
@@ -310,7 +310,7 @@ export class FormAbstract extends EventEmitter {
310
310
  this.revalidate_();
311
311
  }
312
312
 
313
- patch(value: any) {
313
+ patch(value: FormValue) {
314
314
  this.value = value;
315
315
  }
316
316
 
@@ -1,6 +1,6 @@
1
1
  import { FormAbstract } from './form-abstract';
2
2
  import { FormAbstractCollection } from './form-abstract-collection';
3
- import { FormOptions, FormValidator } from './types';
3
+ import { FormOptions, FormValidator, FormValue } from './types';
4
4
 
5
5
  export class FormArray extends FormAbstractCollection<FormAbstract[]> {
6
6
 
@@ -18,8 +18,8 @@ export class FormArray extends FormAbstractCollection<FormAbstract[]> {
18
18
  return this.controls;
19
19
  }
20
20
 
21
- get value(): any[] {
22
- return this.reduce_((result: any[], control: FormAbstract, key: number) => {
21
+ get value(): FormValue[] {
22
+ return this.reduce_((result: FormValue[], control: FormAbstract, key: number) => {
23
23
  result[key] = control.value;
24
24
  return result;
25
25
  }, []); // init as array
@@ -1,14 +1,14 @@
1
1
  import { FormAbstract } from './form-abstract';
2
- import { FormOptions, FormValidator } from './types';
2
+ import { FormOptions, FormValidator, FormValue } from './types';
3
3
 
4
4
  export class FormControl extends FormAbstract {
5
- constructor(value: any = null, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions) {
5
+ constructor(value: FormValue = null, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions) {
6
6
  super(value, validators);
7
7
  this.setInitialOptions(initialOptions);
8
8
  // this.revalidate_();
9
9
  }
10
10
  }
11
11
 
12
- export function formControl(value: any = null, validators?: FormValidator | FormValidator[]) {
12
+ export function formControl(value: FormValue = null, validators?: FormValidator | FormValidator[]) {
13
13
  return new FormControl(value, validators);
14
14
  }
@@ -1,6 +1,6 @@
1
1
  import { FormAbstract } from './form-abstract';
2
2
  import { FormAbstractCollection } from './form-abstract-collection';
3
- import { FormOptions, FormValidator } from './types';
3
+ import { FormOptions, FormValidator, FormValue } from './types';
4
4
 
5
5
  export class FormGroup extends FormAbstractCollection<{ [key: string]: FormAbstract }> {
6
6
  constructor(controls: { [key: string]: FormAbstract | any } = {}, validators?: FormValidator | FormValidator[], initialOptions?: FormOptions) {
@@ -10,6 +10,6 @@ export class FormGroup extends FormAbstractCollection<{ [key: string]: FormAbstr
10
10
  }
11
11
  }
12
12
 
13
- export function formGroup(controls: { [key: string]: FormAbstract | any } = {}, validators?: FormValidator | FormValidator[]) {
13
+ export function formGroup(controls: { [key: string]: FormAbstract | FormValue } = {}, validators?: FormValidator | FormValidator[]) {
14
14
  return new FormGroup(controls, validators);
15
15
  }
@@ -5,6 +5,12 @@ import { FormArray } from './form-array';
5
5
  import { FormControl } from './form-control';
6
6
  import { FormGroup } from './form-group';
7
7
 
8
+ export type FormValue = any; // string | number | boolean | null | Date | FormValueGroup | FormValueArray;
9
+
10
+ export type FormValueGroup = { [key: string]: FormValue };
11
+
12
+ export type FormValueArray = FormValue[];
13
+
8
14
  export type IControlParam = { uid: number, control: FormControl };
9
15
 
10
16
  export type IFormOption = { id: IEquatable, name: string };
@@ -13,7 +19,7 @@ export type FormOptions = {
13
19
  schema?: ControlType;
14
20
  name?: string,
15
21
  label?: string,
16
- value?: string;
22
+ value?: FormValue;
17
23
  placeholder?: string,
18
24
  required?: FormActivator,
19
25
  hidden?: FormActivator,
@@ -27,15 +33,31 @@ export type ValidationError = {
27
33
  [key: string]: any
28
34
  };
29
35
 
30
- export type FormControls = { [key: string]: FormAbstract } | FormAbstract[];
36
+ export type FormControls = { [key: string]: FormAbstract | FormValue } | FormAbstract[];
31
37
  export type FormCollection = FormAbstractCollection<FormControls>;
32
- export type FormActivator = boolean | ((value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => boolean | Promise<boolean>);
33
- export type FormValidator = (value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => null | ValidationError;
34
- export type FormAsyncValidator = (value: any, rootValue: any, control?: FormAbstract, root?: FormCollection) => Promise<null | ValidationError>;
35
-
36
- export type FormFlags = { [key: string]: boolean };
38
+ export type FormActivator = boolean | ((value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => boolean | Promise<boolean>);
39
+ export type FormValidator = (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => null | ValidationError;
40
+ export type FormAsyncValidator = (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormCollection) => Promise<null | ValidationError>;
41
+ export type FormFlags = {
42
+ invalid: boolean;
43
+ disabled: boolean;
44
+ hidden: boolean;
45
+ readonly: boolean;
46
+ dirty: boolean;
47
+ touched: boolean;
48
+ submitted: boolean;
49
+ // derived
50
+ valid: boolean;
51
+ enabled: boolean;
52
+ visible: boolean;
53
+ writeable: boolean;
54
+ pristine: boolean;
55
+ untouched: boolean;
56
+ unsubmitted: boolean;
57
+ };
58
+ // export type FormFlags = { [key: string]: boolean };
37
59
  export type FormErrors = { [key: string]: any };
38
- export type FormValidationError = { key: string, value: any };
60
+ export type FormValidationError = { key: string, value: FormValue };
39
61
  export type FormValidationErrors = FormValidationError[];
40
62
 
41
63
  export type FormState<T> = {
@@ -50,7 +72,7 @@ export type IFormBuilderControlSchema = {
50
72
  schema: ControlType;
51
73
  name?: string;
52
74
  label?: string;
53
- value?: string;
75
+ value?: FormValue;
54
76
  placeholder?: string;
55
77
  required?: FormActivator;
56
78
  hidden?: FormActivator,
@@ -66,5 +88,3 @@ export type IFormBuilderGroupSchema = { [key: string]: IFormBuilderControlSchema
66
88
  export type IFormBuilderArraySchema = IFormBuilderControlSchema[];
67
89
  export type IFormBuilderGroupValues = { [key: string]: FormGroup | FormArray | FormControl };
68
90
  export type IFormBuilderSchema = IFormBuilderGroupSchema | IFormBuilderArraySchema;
69
-
70
- export type StateValue = StateValue[] | { [key: string]: StateValue } | number | string | boolean | null | undefined;
@@ -1,35 +1,14 @@
1
1
  import { IEquatable, IOption } from '@websolutespa/bom-core';
2
- import { FormErrors, FormValidationError } from './types';
2
+ import { FormErrors, FormValidationError, FormValue } from './types';
3
3
 
4
- export function validValue(value: any) {
4
+ export function validValue(value: FormValue) {
5
5
  return value !== undefined && value !== '' ? value : null;
6
6
  }
7
7
 
8
- export function isThenable(result: any) {
9
- return result && typeof result.then === 'function';
10
- }
11
-
12
8
  export function mapErrors_(errors: FormErrors): FormValidationError[] {
13
9
  return Object.keys(errors).map(key => ({ key, value: errors[key] }));
14
10
  }
15
11
 
16
- /*
17
- export function deepCopy<T>(source: T): T;
18
- export function deepCopy(source: StateValue): StateValue {
19
- if (Array.isArray(source)) {
20
- return source.map(x => deepCopy(x));
21
- } else if (source && typeof source === 'object') {
22
- const copy: { [key: string]: any } = {};
23
- Object.keys(source).forEach(key => {
24
- copy[key] = deepCopy(source[key]);
25
- });
26
- return copy;
27
- } else {
28
- return source;
29
- }
30
- }
31
- */
32
-
33
12
  export function valueToString(value: IOption | IOption[] | IEquatable | IEquatable[] | null): string | string[] | undefined {
34
13
  function mapValue(value: IOption | IEquatable | null): string | undefined {
35
14
  const stringValue = value != null ? (
@@ -6,9 +6,10 @@ import { FormValidator } from '../types';
6
6
  export function EmailValidator(): FormValidator {
7
7
  const regex = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
8
8
  return function (value) {
9
- if (!value) {
9
+ if (typeof value === 'string') {
10
+ return regex.test(value) ? null : { email: true };
11
+ } else {
10
12
  return null;
11
13
  }
12
- return regex.test(value) ? null : { email: true };
13
14
  };
14
15
  }
@@ -1,11 +1,11 @@
1
1
  import { FormAbstract } from '../form-abstract';
2
- import { FormValidator } from '../types';
2
+ import { FormValidator, FormValue } from '../types';
3
3
  import { validValue } from '../utils';
4
4
 
5
5
  /**
6
6
  * an equality match validation on another field
7
7
  */
8
- export function MatchValidator(getOtherValue: (value: any, rootValue: any, control?: FormAbstract, root?: FormAbstract) => any): FormValidator {
8
+ export function MatchValidator(getOtherValue: (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormAbstract) => any): FormValidator {
9
9
  return function (value, rootValue, control, root) {
10
10
  let otherValue = getOtherValue(value, rootValue, control, root);
11
11
  otherValue = validValue(otherValue);
@@ -5,10 +5,14 @@ import { FormValidator } from '../types';
5
5
  */
6
6
  export function MaxLengthValidator(maxlength: number): FormValidator {
7
7
  return function (value) {
8
- if (value == null || maxlength == null) { // loose
8
+ if (maxlength == null) {
9
+ return null;
10
+ }
11
+ if (typeof value === 'string') {
12
+ const length = value ? value.length : 0;
13
+ return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
14
+ } else {
9
15
  return null;
10
16
  }
11
- const length = value ? value.length : 0;
12
- return length > maxlength ? { minlength: { requiredLength: maxlength, actualLength: length } } : null;
13
17
  };
14
18
  }
@@ -5,10 +5,10 @@ import { FormValidator } from '../types';
5
5
  */
6
6
  export function MaxValidator(max: number): FormValidator {
7
7
  return function (value) {
8
+ value = typeof value === 'string' ? parseFloat(value) : typeof value === 'number' ? value : null;
8
9
  if (value == null || max == null) { // loose
9
10
  return null;
10
11
  }
11
- value = parseFloat(value);
12
12
  return !isNaN(value) && value > max ? { max: { max: max, actual: value } } : null;
13
13
  };
14
14
  }
@@ -5,10 +5,14 @@ import { FormValidator } from '../types';
5
5
  */
6
6
  export function MinLengthValidator(minlength: number): FormValidator {
7
7
  return function (value) {
8
- if (value == null || minlength == null) { // loose
8
+ if (minlength == null) {
9
+ return null;
10
+ }
11
+ if (typeof value === 'string') {
12
+ const length = value ? value.length : 0;
13
+ return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
14
+ } else {
9
15
  return null;
10
16
  }
11
- const length = value ? value.length : 0;
12
- return length < minlength ? { minlength: { requiredLength: minlength, actualLength: length } } : null;
13
17
  };
14
18
  }
@@ -5,10 +5,10 @@ import { FormValidator } from '../types';
5
5
  */
6
6
  export function MinValidator(min: number): FormValidator {
7
7
  return function (value) {
8
+ value = typeof value === 'string' ? parseFloat(value) : typeof value === 'number' ? value : null;
8
9
  if (value == null || min == null) { // loose
9
10
  return null;
10
11
  }
11
- value = parseFloat(value);
12
12
  return !isNaN(value) && value < min ? { min: { min: min, actual: value } } : null;
13
13
  };
14
14
  }
@@ -5,11 +5,15 @@ import { FormValidator } from '../types';
5
5
  */
6
6
  export function PatternValidator(pattern: string | RegExp): FormValidator {
7
7
  return function (value) {
8
- if (value == null || pattern == null) { // loose
8
+ if (pattern == null) { // loose
9
+ return null;
10
+ }
11
+ if (typeof value === 'string') {
12
+ const regex = patternToRegEx(pattern);
13
+ return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
14
+ } else {
9
15
  return null;
10
16
  }
11
- const regex = patternToRegEx(pattern);
12
- return regex.test(value) ? null : { pattern: { requiredPattern: regex.toString(), actualValue: value } };
13
17
  };
14
18
  }
15
19
 
@@ -1,14 +1,19 @@
1
+ import { isArray } from '@websolutespa/bom-core';
1
2
  import { FormAbstract } from '../form-abstract';
2
- import { FormValidator } from '../types';
3
+ import { FormValidator, FormValue } from '../types';
3
4
 
4
5
  /**
5
6
  * a required dependant on another field
6
7
  */
7
- export function RequiredIfValidator(condition: (value: any, rootValue: any, control?: FormAbstract, root?: FormAbstract) => boolean): FormValidator {
8
+ export function RequiredIfValidator(condition: (value: FormValue, rootValue: FormValue, control?: FormAbstract, root?: FormAbstract) => boolean): FormValidator {
8
9
  return function (value, rootValue, control, root) {
9
- // console.log('RequiredIfValidator', value, Boolean(condition(value)));
10
+ console.log('RequiredIfValidator', value, Boolean(condition(value, rootValue, control, root)));
10
11
  if (Boolean(condition(value, rootValue, control, root)) === true) {
11
- return (value == null || value.length === 0) ? { required: true } : null;
12
+ if (isArray(value) || typeof value === 'string') {
13
+ return (value.length === 0) ? { required: true } : null;
14
+ } else {
15
+ return value == null ? { required: true } : null;
16
+ }
12
17
  } else {
13
18
  return null;
14
19
  }
@@ -1,3 +1,4 @@
1
+ import { isArray } from '@websolutespa/bom-core';
1
2
  import { FormValidator } from '../types';
2
3
 
3
4
  /**
@@ -6,7 +7,11 @@ import { FormValidator } from '../types';
6
7
  export function RequiredValidator(): FormValidator {
7
8
  return function (value) {
8
9
  // console.log('RequiredValidator', value, (value == null || value.length === 0) ? { required: true } : null);
9
- return value == null || value.length === 0 ? { required: true } : null;
10
+ if (isArray(value) || typeof value === 'string') {
11
+ return (value.length === 0) ? { required: true } : null;
12
+ } else {
13
+ return value == null ? { required: true } : null;
14
+ }
10
15
  };
11
16
  // return (value == null || value.length === 0) ? 'required' : null;
12
17
  }
@@ -36,17 +36,23 @@ export function useFormBuilder<T, U extends (FormGroup | FormArray)>(
36
36
 
37
37
  useEffect(() => {
38
38
  const onChange = (value: T) => {
39
+ // console.log('useFormBuilder.onChange', value);
39
40
  const newState = { value, flags: collection.state, errors: mapErrors_(collection.errors) };
40
- // console.log('useFormBuilder.onChange', newState);
41
41
  setState(newState);
42
42
  };
43
43
  collection.on('change', onChange);
44
- collection.validateAndChange_();
44
+ // collection.validateAndChange_();
45
+ collection.revalidate_();
46
+ // const value = collection.value;
47
+ // collection.reset();
48
+ // collection.patch(value);
45
49
  // console.log('subscribe');
46
50
  return () => collection.off('change', onChange);
47
51
  // eslint-disable-next-line react-hooks/exhaustive-deps
48
52
  }, deps);
49
53
 
54
+ // console.log('useFormBuilder', collection.value);
55
+
50
56
  return [state, setValue, setTouched, reset, collection];
51
57
  }
52
58