@reactables/forms 0.5.2-alpha.0 → 0.5.4-alpha.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/README.md CHANGED
@@ -2,14 +2,119 @@
2
2
 
3
3
  ## Description
4
4
 
5
- State management for building a comprehensive form library using [Reactables Core](https://github.com/reactables/reactables/tree/main/packages/core).
5
+ State Management of reactive forms with [Reactables](https://github.com/reactables/reactables/tree/main/packages/core).
6
6
 
7
- ## Architecture (WIP see https://github.com/reactables/reactables/issues/8)
7
+ ## Table of Contents
8
8
 
9
- The following diagram visualizes the architecture of [Reactables Forms](https://github.com/reactables/reactables/tree/main/packages/forms) - a state management model for building reactive forms.
9
+ 1. [Installation](#installation)
10
+ 1. [Examples](#examples)
11
+ 1. [Form Control](#form-control)
12
+ 1. [Form Array](#form-array)
13
+ 1. [Form Group](#form-group)
10
14
 
11
- There are two sets of hub and stores. The first set is responsible for handling user input and updating the form.
15
+ 1. [API](#api)
16
+ 1. [RxActions](#api-actions)
17
+ 1. [build](#api-build)
18
+ 1. [control](#api-control)
19
+ 1. [group](#api-group)
20
+ 1. [array](#api-array)
21
+ 1. [Other Interfaces](#interfaces)
22
+ 1. [EffectsAndSources](#effects-sources)
12
23
 
13
- The second set is responsible for reacting to the form change in the first store and asynchronous validation.
14
24
 
15
- ![Reactables architecture](https://raw.githubusercontent.com/reactables/reactables/main/documentation/Slide10ReactablesForms.jpg)
25
+ ## Installation <a name="installation"></a>
26
+
27
+ Installation will require [RxJS](https://rxjs.dev/) if not already installed.
28
+
29
+ `npm i rxjs @reactables/forms`
30
+
31
+ ## Examples <a name="examples"></a>
32
+
33
+ WIP
34
+
35
+ ## API <a name="api"></a>
36
+
37
+ The API for building Reactable Forms is very similar to [Angular FormBuilder](https://angular.io/api/forms/FormBuilder). It has been adapted to support Reactable features.
38
+
39
+ ### `RxActions` <a name="api-actions"></a>
40
+
41
+ Actions available to trigger state changes on Reactable.
42
+
43
+ ```typescript
44
+ type RxFormActions = {
45
+ updateValues: <T>(payload: ControlChange<T>) => void;
46
+ addControl: (payload: AddControl) => void;
47
+ pushControl: (payload: PushControl) => void;
48
+ removeControl: (payload: ControlRef) => void;
49
+ markControlAsPristine: (payload: ControlRef) => void;
50
+ markControlAsTouched: (payload: MarkTouched) => void;
51
+ markControlAsUntouched: (payload: ControlRef) => void;
52
+ resetControl: (payload: ControlRef) => void;
53
+ };
54
+ ```
55
+
56
+ ### `build` <a name="api-build"></a>
57
+
58
+ ```typescript
59
+ type build = (config: AbstractControlConfig, options?: EffectsAndSources) => Reactable<Form<unknown>, RxFormActions>
60
+ ```
61
+
62
+ Factory method for creating a form Reactable. Accepts a configuration object generated by one or more helper methods - [`control`](#api-control), [`group`](#api-group), [`array`](#api-array).
63
+
64
+ Options can also be provided to declare [Effects and Sources](#effects-sources) for the form Reactable.
65
+
66
+ ### `control` <a name="api-control"></a>
67
+
68
+ Function to create a `FormControlConfig` configuration object. Accepts a configuration object or a tuple.
69
+ ```typescript
70
+ type control = <T>(config: FormControlConfig<T> | FbControl<T>) => FormControlConfig<T>
71
+
72
+ interface FormControlConfig<T> {
73
+ initialValue: T;
74
+ validators?: ValidatorFn[];
75
+ asyncValidators?: ValidatorAsyncFn[];
76
+ }
77
+
78
+ type FbControl<T> = [T, (ValidatorFn | ValidatorFn[])?, (ValidatorAsyncFn | ValidatorAsyncFn[])?];
79
+ ```
80
+
81
+ ### `group` <a name="api-group"></a>
82
+
83
+ Function to create a `FormGroupConfig` configuration object. Accepts a configuration object containing a `controls` dictionary of additional configuration objects generated by [`control`](#api-control), [`group`](#api-group), or [`array`](#api-array).
84
+
85
+ ```typescript
86
+ type group = (config: FormGroupConfig) => FormGroupConfig
87
+
88
+ interface FormGroupConfig{
89
+ validators?: ValidatorFn[];
90
+ asyncValidators?: ValidatorAsyncFn[];
91
+ controls: { [key: string]: AbstractControlConfig };
92
+ }
93
+ ```
94
+ ### `array` <a name="api-array"></a>
95
+
96
+ Function to create a `FormArrayConfig` configuration object. Accepts a configuration object containing a `controls` array of additional configuration objects generated by [`control`](#api-control), [`group`](#api-group), or [`array`](#api-array).
97
+
98
+ ```typescript
99
+ type array = (config: FormArrayConfig) => FormArrayConfig
100
+
101
+ interface FormArrayConfig {
102
+ validators?: ValidatorFn[];
103
+ asyncValidators?: ValidatorAsyncFn[];
104
+ controls: AbstractControlConfig[];
105
+ }
106
+ ```
107
+
108
+ ### Other Interfaces <a name="interfaces"></a>
109
+
110
+ #### EffectsAndSources <a name="effects-sources"></a>
111
+ ```typescript
112
+ interface EffectsAndSources {
113
+ effects?: Effect<unknown, unknown>[];
114
+ sources?: Observable<Action<unknown>>[] | { [key: string]: Observable<unknown> };
115
+ }
116
+ ```
117
+ | Property | Description |
118
+ | -------- | ----------- |
119
+ | effects (optional) | Array of [Effects](https://github.com/reactables/reactables/tree/main/packages/core#api-effect) to be registered to the Reactable |
120
+ | sources (optional) | Additional [Action](https://github.com/reactables/reactables/tree/main/packages/core#action-) Observables the Reactable is listening to. Can be an array or a dictionary where key is the action type and value is the Observable emitting the payload |
@@ -1,5 +1,27 @@
1
1
  import { Form, BaseForm } from '../../Models/Controls';
2
2
  import { ControlRef } from '../../Models/ControlRef';
3
+ import { FormErrors } from '../../Models/FormErrors';
3
4
  export declare const mergePushControl: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => {
5
+ [x: string]: import("../../Models/Controls").FormControl<unknown> | {
6
+ errors: {
7
+ [x: string]: boolean;
8
+ };
9
+ valid: boolean;
10
+ childrenValid: boolean;
11
+ pristineValue: unknown;
12
+ controlRef: ControlRef;
13
+ value: unknown;
14
+ dirty: boolean;
15
+ touched: boolean;
16
+ validatorErrors: FormErrors;
17
+ config: import("../..").AbstractControlConfig;
18
+ key: string;
19
+ asyncValidatorErrors: FormErrors;
20
+ asyncValidateInProgress: {
21
+ [key: string]: boolean;
22
+ [key: number]: boolean;
23
+ };
24
+ pending?: boolean;
25
+ };
4
26
  root?: import("../../Models/Controls").FormControl<unknown>;
5
27
  };
@@ -5,6 +5,9 @@ import { FormControlConfig, FormArrayConfig, FormGroupConfig, AbstractControlCon
5
5
  import { ValidatorFn, ValidatorAsyncFn } from '../Models/Validators';
6
6
  import { Form } from '../Models/Controls';
7
7
  type FbControl<T> = [T, (ValidatorFn | ValidatorFn[])?, (ValidatorAsyncFn | ValidatorAsyncFn[])?];
8
+ export declare const control: <T>(config: FormControlConfig<T> | FbControl<T>) => FormControlConfig<T>;
9
+ export declare const array: (config: FormArrayConfig) => FormArrayConfig;
10
+ export declare const group: (config: FormGroupConfig) => FormGroupConfig;
8
11
  export type RxFormActions = {
9
12
  updateValues: <T>(payload: ControlChange<T>) => void;
10
13
  addControl: (payload: AddControl) => void;
@@ -15,10 +18,5 @@ export type RxFormActions = {
15
18
  markControlAsUntouched: (payload: ControlRef) => void;
16
19
  resetControl: (payload: ControlRef) => void;
17
20
  };
18
- export declare const RxForm: {
19
- group: (config: FormGroupConfig) => FormGroupConfig;
20
- array: (config: FormArrayConfig) => FormArrayConfig;
21
- control: <T>(config: FormControlConfig<T> | FbControl<T>) => FormControlConfig<T>;
22
- build: (config: AbstractControlConfig, options?: EffectsAndSources) => Reactable<Form<unknown>, RxFormActions>;
23
- };
21
+ export declare const build: (config: AbstractControlConfig, options?: EffectsAndSources) => Reactable<Form<unknown>, RxFormActions>;
24
22
  export {};
@@ -1 +1 @@
1
- export { RxForm, RxFormActions } from './RxForm';
1
+ export { build, group, array, control, RxFormActions } from './RxForm';
package/dist/index.js CHANGED
@@ -875,12 +875,9 @@ var mergePushControl = function (state, form, controlRef) {
875
875
  var ancestors = getAncestorControls(controlRef, state)
876
876
  .reverse()
877
877
  .reduce(function (acc, control, index, arr) {
878
- var _a, _b;
878
+ var _a;
879
879
  var formKey = getFormKey(control.controlRef);
880
880
  var errors = __assign(__assign({}, form[formKey].validatorErrors), control.asyncValidatorErrors);
881
- if (!control.childrenValid)
882
- // If the ancestor control's children were not valid, pushing an item won't change its valid status
883
- return __assign(__assign({}, acc), (_a = {}, _a[formKey] = __assign(__assign(__assign({}, control), form[formKey]), { errors: errors }), _a));
884
881
  var selfValid = !hasErrors(errors);
885
882
  var childrenValid = true;
886
883
  if (index === 0) {
@@ -889,9 +886,24 @@ var mergePushControl = function (state, form, controlRef) {
889
886
  mergedDescendants[getFormKey(controlRef.concat(newItemIndex))].valid;
890
887
  }
891
888
  else {
892
- childrenValid = control.childrenValid && arr[index - 1].valid;
889
+ if (Array.isArray(control.config.controls)) {
890
+ // If control is a FormArray
891
+ childrenValid = control.value.every(function (item, index) {
892
+ var formKey = getFormKey(control.controlRef.concat(index));
893
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
894
+ return valid;
895
+ });
896
+ }
897
+ else if (control.config.controls) {
898
+ // If control is a FormGroup
899
+ childrenValid = Object.keys(control.value).every(function (childKey) {
900
+ var formKey = getFormKey(control.controlRef.concat(childKey));
901
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
902
+ return valid;
903
+ });
904
+ }
893
905
  }
894
- return __assign(__assign({}, acc), (_b = {}, _b[formKey] = __assign(__assign(__assign({}, control), form[formKey]), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _b));
906
+ return __assign(__assign({}, acc), (_a = {}, _a[formKey] = __assign(__assign(__assign({}, control), form[formKey]), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _a));
895
907
  }, {});
896
908
  var controlBranchUpdated = __assign(__assign({}, ancestors), mergedDescendants);
897
909
  return __assign(__assign({}, state), controlBranchUpdated);
@@ -980,12 +992,6 @@ var build = function (config, options) {
980
992
  state$: rxHub2.state$.pipe(operators.filter(function (form) { return form !== null; })),
981
993
  actions: rxHub1.actions
982
994
  };
983
- };
984
- var RxForm = {
985
- group: group,
986
- array: array,
987
- control: control,
988
- build: build
989
995
  };
990
996
 
991
997
  var getArrayItems = function (controlRef, form) {
@@ -998,6 +1004,9 @@ var getArrayItems = function (controlRef, form) {
998
1004
  };
999
1005
 
1000
1006
  exports.ControlModels = Controls;
1001
- exports.RxForm = RxForm;
1002
1007
  exports.Validators = index;
1008
+ exports.array = array;
1009
+ exports.build = build;
1010
+ exports.control = control;
1003
1011
  exports.getArrayItems = getArrayItems;
1012
+ exports.group = group;
package/package.json CHANGED
@@ -14,12 +14,14 @@
14
14
  "author": "David Lai",
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
- "@reactables/core": "^0.5.2-alpha.0",
18
- "lodash.clonedeep": "^4.5.0",
17
+ "@reactables/core": "^0.5.4-alpha.0",
19
18
  "lodash.isequal": "^4.5.0"
20
19
  },
21
20
  "peerDependencies": {
22
21
  "rxjs": "^6.0.0 || ^7.0.0"
23
22
  },
24
- "version": "0.5.2-alpha.0"
23
+ "devDependencies": {
24
+ "lodash.clonedeep": "^4.5.0"
25
+ },
26
+ "version": "0.5.4-alpha.0"
25
27
  }