mobx-formkit 1.0.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.
Files changed (256) hide show
  1. package/AGENTS.md +761 -0
  2. package/LICENSE +21 -0
  3. package/README.md +214 -0
  4. package/lib/ArrayMap.d.ts +50 -0
  5. package/lib/ArrayMap.d.ts.map +1 -0
  6. package/lib/ArrayMap.js +151 -0
  7. package/lib/ArrayMap.js.map +1 -0
  8. package/lib/Base.d.ts +237 -0
  9. package/lib/Base.d.ts.map +1 -0
  10. package/lib/Base.js +872 -0
  11. package/lib/Base.js.map +1 -0
  12. package/lib/Bindings.d.ts +28 -0
  13. package/lib/Bindings.d.ts.map +1 -0
  14. package/lib/Bindings.js +73 -0
  15. package/lib/Bindings.js.map +1 -0
  16. package/lib/Field.d.ts +195 -0
  17. package/lib/Field.d.ts.map +1 -0
  18. package/lib/Field.js +734 -0
  19. package/lib/Field.js.map +1 -0
  20. package/lib/Form.d.ts +75 -0
  21. package/lib/Form.d.ts.map +1 -0
  22. package/lib/Form.js +199 -0
  23. package/lib/Form.js.map +1 -0
  24. package/lib/Options.d.ts +9 -0
  25. package/lib/Options.d.ts.map +1 -0
  26. package/lib/Options.js +85 -0
  27. package/lib/Options.js.map +1 -0
  28. package/lib/State.d.ts +43 -0
  29. package/lib/State.d.ts.map +1 -0
  30. package/lib/State.js +147 -0
  31. package/lib/State.js.map +1 -0
  32. package/lib/Validator.d.ts +25 -0
  33. package/lib/Validator.d.ts.map +1 -0
  34. package/lib/Validator.js +143 -0
  35. package/lib/Validator.js.map +1 -0
  36. package/lib/compat.d.ts +29 -0
  37. package/lib/compat.d.ts.map +1 -0
  38. package/lib/compat.js +117 -0
  39. package/lib/compat.js.map +1 -0
  40. package/lib/composer.d.ts +26 -0
  41. package/lib/composer.d.ts.map +1 -0
  42. package/lib/composer.js +65 -0
  43. package/lib/composer.js.map +1 -0
  44. package/lib/esm/ArrayMap.js +146 -0
  45. package/lib/esm/ArrayMap.js.map +1 -0
  46. package/lib/esm/Base.js +868 -0
  47. package/lib/esm/Base.js.map +1 -0
  48. package/lib/esm/Bindings.js +69 -0
  49. package/lib/esm/Bindings.js.map +1 -0
  50. package/lib/esm/Field.js +730 -0
  51. package/lib/esm/Field.js.map +1 -0
  52. package/lib/esm/Form.js +195 -0
  53. package/lib/esm/Form.js.map +1 -0
  54. package/lib/esm/Options.js +81 -0
  55. package/lib/esm/Options.js.map +1 -0
  56. package/lib/esm/State.js +143 -0
  57. package/lib/esm/State.js.map +1 -0
  58. package/lib/esm/Validator.js +139 -0
  59. package/lib/esm/Validator.js.map +1 -0
  60. package/lib/esm/compat.js +96 -0
  61. package/lib/esm/compat.js.map +1 -0
  62. package/lib/esm/composer.js +63 -0
  63. package/lib/esm/composer.js.map +1 -0
  64. package/lib/esm/index.js +8 -0
  65. package/lib/esm/index.js.map +1 -0
  66. package/lib/esm/models/FieldProps.js +116 -0
  67. package/lib/esm/models/FieldProps.js.map +1 -0
  68. package/lib/esm/models/OptionsModel.js +51 -0
  69. package/lib/esm/models/OptionsModel.js.map +1 -0
  70. package/lib/esm/models/StateInterface.js +9 -0
  71. package/lib/esm/models/StateInterface.js.map +1 -0
  72. package/lib/esm/models/ValidatorInterface.js +8 -0
  73. package/lib/esm/models/ValidatorInterface.js.map +1 -0
  74. package/lib/esm/parser.js +235 -0
  75. package/lib/esm/parser.js.map +1 -0
  76. package/lib/esm/props.js +118 -0
  77. package/lib/esm/props.js.map +1 -0
  78. package/lib/esm/utils.js +156 -0
  79. package/lib/esm/utils.js.map +1 -0
  80. package/lib/esm/validators/AJV.js +105 -0
  81. package/lib/esm/validators/AJV.js.map +1 -0
  82. package/lib/esm/validators/DVR.js +104 -0
  83. package/lib/esm/validators/DVR.js.map +1 -0
  84. package/lib/esm/validators/JOI.js +54 -0
  85. package/lib/esm/validators/JOI.js.map +1 -0
  86. package/lib/esm/validators/VALIBOT.js +50 -0
  87. package/lib/esm/validators/VALIBOT.js.map +1 -0
  88. package/lib/esm/validators/VINEJS.js +60 -0
  89. package/lib/esm/validators/VINEJS.js.map +1 -0
  90. package/lib/esm/validators/VJF.js +88 -0
  91. package/lib/esm/validators/VJF.js.map +1 -0
  92. package/lib/esm/validators/YUP.js +69 -0
  93. package/lib/esm/validators/YUP.js.map +1 -0
  94. package/lib/esm/validators/ZOD.js +43 -0
  95. package/lib/esm/validators/ZOD.js.map +1 -0
  96. package/lib/index.d.ts +7 -0
  97. package/lib/index.d.ts.map +1 -0
  98. package/lib/index.js +15 -0
  99. package/lib/index.js.map +1 -0
  100. package/lib/models/BaseInterface.d.ts +40 -0
  101. package/lib/models/BaseInterface.d.ts.map +1 -0
  102. package/lib/models/BindingsInterface.d.ts +18 -0
  103. package/lib/models/BindingsInterface.d.ts.map +1 -0
  104. package/lib/models/FieldInterface.d.ts +88 -0
  105. package/lib/models/FieldInterface.d.ts.map +1 -0
  106. package/lib/models/FieldProps.d.ts +111 -0
  107. package/lib/models/FieldProps.d.ts.map +1 -0
  108. package/lib/models/FieldProps.js +116 -0
  109. package/lib/models/FieldProps.js.map +1 -0
  110. package/lib/models/FormInterface.d.ts +184 -0
  111. package/lib/models/FormInterface.d.ts.map +1 -0
  112. package/lib/models/OptionsInterface.d.ts +8 -0
  113. package/lib/models/OptionsInterface.d.ts.map +1 -0
  114. package/lib/models/OptionsModel.d.ts +99 -0
  115. package/lib/models/OptionsModel.d.ts.map +1 -0
  116. package/lib/models/OptionsModel.js +51 -0
  117. package/lib/models/OptionsModel.js.map +1 -0
  118. package/lib/models/SharedActionsInterface.d.ts +27 -0
  119. package/lib/models/SharedActionsInterface.d.ts.map +1 -0
  120. package/lib/models/SharedEventsInterface.d.ts +8 -0
  121. package/lib/models/SharedEventsInterface.d.ts.map +1 -0
  122. package/lib/models/SharedHelpersInterface.d.ts +26 -0
  123. package/lib/models/SharedHelpersInterface.d.ts.map +1 -0
  124. package/lib/models/SharedInitializerInterface.d.ts +6 -0
  125. package/lib/models/SharedInitializerInterface.d.ts.map +1 -0
  126. package/lib/models/SharedUtilsInterface.d.ts +10 -0
  127. package/lib/models/SharedUtilsInterface.d.ts.map +1 -0
  128. package/lib/models/StateInterface.d.ts +37 -0
  129. package/lib/models/StateInterface.d.ts.map +1 -0
  130. package/lib/models/StateInterface.js +9 -0
  131. package/lib/models/StateInterface.js.map +1 -0
  132. package/lib/models/ValidatorInterface.d.ts +74 -0
  133. package/lib/models/ValidatorInterface.d.ts.map +1 -0
  134. package/lib/models/ValidatorInterface.js +8 -0
  135. package/lib/models/ValidatorInterface.js.map +1 -0
  136. package/lib/parser.d.ts +13 -0
  137. package/lib/parser.d.ts.map +1 -0
  138. package/lib/parser.js +247 -0
  139. package/lib/parser.js.map +1 -0
  140. package/lib/props.d.ts +14 -0
  141. package/lib/props.d.ts.map +1 -0
  142. package/lib/props.js +120 -0
  143. package/lib/props.js.map +1 -0
  144. package/lib/utils.d.ts +34 -0
  145. package/lib/utils.d.ts.map +1 -0
  146. package/lib/utils.js +182 -0
  147. package/lib/utils.js.map +1 -0
  148. package/lib/validators/AJV.d.ts +4 -0
  149. package/lib/validators/AJV.d.ts.map +1 -0
  150. package/lib/validators/AJV.js +109 -0
  151. package/lib/validators/AJV.js.map +1 -0
  152. package/lib/validators/DVR.d.ts +4 -0
  153. package/lib/validators/DVR.d.ts.map +1 -0
  154. package/lib/validators/DVR.js +108 -0
  155. package/lib/validators/DVR.js.map +1 -0
  156. package/lib/validators/JOI.d.ts +4 -0
  157. package/lib/validators/JOI.d.ts.map +1 -0
  158. package/lib/validators/JOI.js +58 -0
  159. package/lib/validators/JOI.js.map +1 -0
  160. package/lib/validators/VALIBOT.d.ts +4 -0
  161. package/lib/validators/VALIBOT.d.ts.map +1 -0
  162. package/lib/validators/VALIBOT.js +73 -0
  163. package/lib/validators/VALIBOT.js.map +1 -0
  164. package/lib/validators/VINEJS.d.ts +4 -0
  165. package/lib/validators/VINEJS.d.ts.map +1 -0
  166. package/lib/validators/VINEJS.js +64 -0
  167. package/lib/validators/VINEJS.js.map +1 -0
  168. package/lib/validators/VJF.d.ts +4 -0
  169. package/lib/validators/VJF.d.ts.map +1 -0
  170. package/lib/validators/VJF.js +92 -0
  171. package/lib/validators/VJF.js.map +1 -0
  172. package/lib/validators/YUP.d.ts +4 -0
  173. package/lib/validators/YUP.d.ts.map +1 -0
  174. package/lib/validators/YUP.js +73 -0
  175. package/lib/validators/YUP.js.map +1 -0
  176. package/lib/validators/ZOD.d.ts +4 -0
  177. package/lib/validators/ZOD.d.ts.map +1 -0
  178. package/lib/validators/ZOD.js +47 -0
  179. package/lib/validators/ZOD.js.map +1 -0
  180. package/package.json +183 -0
  181. package/src/ArrayMap.ts +165 -0
  182. package/src/Base.ts +1229 -0
  183. package/src/Bindings.ts +85 -0
  184. package/src/Field.ts +1034 -0
  185. package/src/Form.ts +264 -0
  186. package/src/Options.ts +91 -0
  187. package/src/State.ts +183 -0
  188. package/src/Validator.ts +177 -0
  189. package/src/compat.ts +104 -0
  190. package/src/composer.ts +82 -0
  191. package/src/index.ts +7 -0
  192. package/src/models/BaseInterface.ts +45 -0
  193. package/src/models/BindingsInterface.ts +25 -0
  194. package/src/models/FieldInterface.ts +97 -0
  195. package/src/models/FieldProps.ts +116 -0
  196. package/src/models/FormInterface.ts +203 -0
  197. package/src/models/OptionsInterface.ts +9 -0
  198. package/src/models/OptionsModel.ts +100 -0
  199. package/src/models/SharedActionsInterface.ts +30 -0
  200. package/src/models/SharedEventsInterface.ts +8 -0
  201. package/src/models/SharedHelpersInterface.ts +12 -0
  202. package/src/models/SharedInitializerInterface.ts +6 -0
  203. package/src/models/SharedUtilsInterface.ts +10 -0
  204. package/src/models/StateInterface.ts +44 -0
  205. package/src/models/ValidatorInterface.ts +88 -0
  206. package/src/parser.ts +327 -0
  207. package/src/props.ts +127 -0
  208. package/src/utils.ts +218 -0
  209. package/src/validators/AJV.ts +140 -0
  210. package/src/validators/DVR.ts +145 -0
  211. package/src/validators/JOI.ts +79 -0
  212. package/src/validators/VALIBOT.ts +70 -0
  213. package/src/validators/VINEJS.ts +83 -0
  214. package/src/validators/VJF.ts +123 -0
  215. package/src/validators/YUP.ts +90 -0
  216. package/src/validators/ZOD.ts +66 -0
  217. package/umd/MobxFormkit.umd.js +3093 -0
  218. package/umd/MobxFormkit.umd.js.map +1 -0
  219. package/umd/MobxFormkit.umd.min.js +2 -0
  220. package/umd/MobxFormkit.umd.min.js.map +1 -0
  221. package/umd/MobxFormkitComposer.umd.js +183 -0
  222. package/umd/MobxFormkitComposer.umd.js.map +1 -0
  223. package/umd/MobxFormkitComposer.umd.min.js +2 -0
  224. package/umd/MobxFormkitComposer.umd.min.js.map +1 -0
  225. package/umd/MobxFormkitValidatorAJV.umd.js +113 -0
  226. package/umd/MobxFormkitValidatorAJV.umd.js.map +1 -0
  227. package/umd/MobxFormkitValidatorAJV.umd.min.js +2 -0
  228. package/umd/MobxFormkitValidatorAJV.umd.min.js.map +1 -0
  229. package/umd/MobxFormkitValidatorDVR.umd.js +110 -0
  230. package/umd/MobxFormkitValidatorDVR.umd.js.map +1 -0
  231. package/umd/MobxFormkitValidatorDVR.umd.min.js +2 -0
  232. package/umd/MobxFormkitValidatorDVR.umd.min.js.map +1 -0
  233. package/umd/MobxFormkitValidatorJOI.umd.js +62 -0
  234. package/umd/MobxFormkitValidatorJOI.umd.js.map +1 -0
  235. package/umd/MobxFormkitValidatorJOI.umd.min.js +2 -0
  236. package/umd/MobxFormkitValidatorJOI.umd.min.js.map +1 -0
  237. package/umd/MobxFormkitValidatorVALIBOT.umd.js +8032 -0
  238. package/umd/MobxFormkitValidatorVALIBOT.umd.js.map +1 -0
  239. package/umd/MobxFormkitValidatorVALIBOT.umd.min.js +2 -0
  240. package/umd/MobxFormkitValidatorVALIBOT.umd.min.js.map +1 -0
  241. package/umd/MobxFormkitValidatorVINEJS.umd.js +11737 -0
  242. package/umd/MobxFormkitValidatorVINEJS.umd.js.map +1 -0
  243. package/umd/MobxFormkitValidatorVINEJS.umd.min.js +2 -0
  244. package/umd/MobxFormkitValidatorVINEJS.umd.min.js.map +1 -0
  245. package/umd/MobxFormkitValidatorVJF.umd.js +96 -0
  246. package/umd/MobxFormkitValidatorVJF.umd.js.map +1 -0
  247. package/umd/MobxFormkitValidatorVJF.umd.min.js +2 -0
  248. package/umd/MobxFormkitValidatorVJF.umd.min.js.map +1 -0
  249. package/umd/MobxFormkitValidatorYUP.umd.js +77 -0
  250. package/umd/MobxFormkitValidatorYUP.umd.js.map +1 -0
  251. package/umd/MobxFormkitValidatorYUP.umd.min.js +2 -0
  252. package/umd/MobxFormkitValidatorYUP.umd.min.js.map +1 -0
  253. package/umd/MobxFormkitValidatorZOD.umd.js +49 -0
  254. package/umd/MobxFormkitValidatorZOD.umd.js.map +1 -0
  255. package/umd/MobxFormkitValidatorZOD.umd.min.js +2 -0
  256. package/umd/MobxFormkitValidatorZOD.umd.min.js.map +1 -0
package/src/Base.ts ADDED
@@ -0,0 +1,1229 @@
1
+ import {
2
+ observable,
3
+ computed,
4
+ action,
5
+ toJS,
6
+ observe,
7
+ intercept,
8
+ } from "mobx";
9
+ import { makeObservable } from "./compat";
10
+ import ArrayMap from "./ArrayMap";
11
+ import {
12
+ each,
13
+ forIn,
14
+ get,
15
+ has,
16
+ isPlainObject,
17
+ merge,
18
+ set,
19
+ transform,
20
+ } from "lodash";
21
+ import { BaseInterface } from "./models/BaseInterface";
22
+ import { StateInterface } from "./models/StateInterface";
23
+ import { FieldInterface } from "./models/FieldInterface";
24
+
25
+ import {
26
+ props,
27
+ allowedProps,
28
+ checkPropOccurrence,
29
+ throwError,
30
+ isArrayOfObjects,
31
+ getObservableMapValues,
32
+ maxKey,
33
+ $try,
34
+ isEvent,
35
+ hasIntKeys,
36
+ pathToStruct,
37
+ hasSome,
38
+ } from "./utils";
39
+
40
+ import {
41
+ mergeSchemaDefaults,
42
+ prepareFieldsData,
43
+ parsePath,
44
+ parseInput,
45
+ parseCheckArray,
46
+ parseCheckOutput,
47
+ pathToFieldsTree,
48
+ defaultValue,
49
+ } from "./parser";
50
+ import {
51
+ AllowedFieldPropsTypes,
52
+ FieldPropsEnum,
53
+ SeparatedPropsMode,
54
+ } from "./models/FieldProps";
55
+ import { OptionsEnum } from "./models/OptionsModel";
56
+ import { ValidateOptions, ValidationHooks } from "./models/ValidatorInterface";
57
+ import { SubmitHooks } from "./models/SharedActionsInterface";
58
+ export default abstract class Base<
59
+ F extends Record<string, any> = Record<string, any>,
60
+ > implements BaseInterface<F> {
61
+ noop = () => {};
62
+
63
+ state!: StateInterface;
64
+
65
+ fields: ArrayMap = new ArrayMap();
66
+ path: string | undefined | null;
67
+
68
+ $submitted: number = 0;
69
+ $submitting: boolean = false;
70
+
71
+ $validated: number = 0;
72
+ $validating: boolean = false;
73
+
74
+ $clearing: boolean = false;
75
+ $resetting: boolean = false;
76
+
77
+ $touched: boolean = false;
78
+ $changed: number = 0;
79
+
80
+ $hooks: any = {};
81
+ $handlers: any = {};
82
+
83
+ constructor() {
84
+ makeObservable(this, {
85
+ $submitted: observable,
86
+ $submitting: observable,
87
+ $validated: observable,
88
+ $validating: observable,
89
+ $clearing: observable,
90
+ $resetting: observable,
91
+ $touched: observable,
92
+ $changed: observable,
93
+ $hooks: observable,
94
+ $handlers: observable,
95
+ changed: computed,
96
+ submitted: computed,
97
+ submitting: computed,
98
+ validated: computed,
99
+ validating: computed,
100
+ clearing: computed,
101
+ resetting: computed,
102
+ hasIncrementalKeys: computed,
103
+ hasNestedFields: computed,
104
+ size: computed,
105
+ // initialization
106
+ initField: action,
107
+ // actions
108
+ submit: action,
109
+ deepUpdate: action,
110
+ set: action,
111
+ add: action,
112
+ del: action,
113
+ });
114
+ }
115
+
116
+ execHook = (name: string, fallback: any = {}, ...args: any[]): any =>
117
+ $try(fallback[name], this.$hooks[name], this.noop).apply(this, [this, ...args]);
118
+
119
+ execHandler = (
120
+ name: string,
121
+ args: any,
122
+ fallback: any = undefined,
123
+ hook: any = null,
124
+ execHook = true,
125
+ ): any => [
126
+ $try(
127
+ this.$handlers[name] && this.$handlers[name].apply(this, [this]),
128
+ fallback,
129
+ this.noop,
130
+ ).apply(this, [...args]),
131
+ execHook && this.execHook(hook || name, {}, ...args),
132
+ ];
133
+
134
+ get resetting(): boolean {
135
+ return this.hasNestedFields
136
+ ? this.check(FieldPropsEnum.resetting, true)
137
+ : this.$resetting;
138
+ }
139
+
140
+ get clearing(): boolean {
141
+ return this.hasNestedFields
142
+ ? this.check(FieldPropsEnum.clearing, true)
143
+ : this.$clearing;
144
+ }
145
+
146
+ get submitted(): number {
147
+ return toJS(this.$submitted);
148
+ }
149
+
150
+ get submitting(): boolean {
151
+ return toJS(this.$submitting);
152
+ }
153
+
154
+ get validated(): number {
155
+ return toJS(this.$validated);
156
+ }
157
+
158
+ get validating(): boolean {
159
+ return toJS(this.$validating);
160
+ }
161
+
162
+ get hasIncrementalKeys(): boolean {
163
+ return !!this.fields.size && hasIntKeys(this.fields);
164
+ }
165
+
166
+ get hasNestedFields(): boolean {
167
+ return this.fields.size !== 0;
168
+ }
169
+
170
+ get size(): number {
171
+ return this.fields.size;
172
+ }
173
+
174
+ get changed(): number {
175
+ return this.path != null && this.hasNestedFields
176
+ ? this.reduce(
177
+ (acc: number, field: FieldInterface) => acc + field.changed,
178
+ 0,
179
+ ) + this.$changed
180
+ : this.$changed;
181
+ }
182
+
183
+ /**
184
+ Interceptor
185
+ */
186
+ intercept = (opt: any): any =>
187
+ this.MOBXEvent(
188
+ typeof opt === "function"
189
+ ? { type: "interceptor", call: opt }
190
+ : { type: "interceptor", ...opt },
191
+ );
192
+
193
+ /**
194
+ Observer
195
+ */
196
+ observe = (opt: any): any =>
197
+ this.MOBXEvent(
198
+ typeof opt === "function"
199
+ ? { type: "observer", call: opt }
200
+ : { type: "observer", ...opt },
201
+ );
202
+
203
+ /**
204
+ Event Handler: On Clear
205
+ */
206
+ onClear = (...args: any): any =>
207
+ this.execHandler(FieldPropsEnum.onClear, args, (e: Event) => {
208
+ isEvent(e) && e.preventDefault();
209
+ (this as any).clear(true, false);
210
+ });
211
+
212
+ /**
213
+ Event Handler: On Reset
214
+ */
215
+ onReset = (...args: any): any =>
216
+ this.execHandler(FieldPropsEnum.onReset, args, (e: Event) => {
217
+ isEvent(e) && e.preventDefault();
218
+ (this as any).reset(true, false);
219
+ });
220
+
221
+ /**
222
+ Event Handler: On Submit
223
+ */
224
+ onSubmit = (...args: any): any =>
225
+ this.execHandler(
226
+ FieldPropsEnum.onSubmit,
227
+ args,
228
+ (e: Event, o = {}) => {
229
+ isEvent(e) && e.preventDefault();
230
+ this.submit(o);
231
+ },
232
+ null,
233
+ false,
234
+ );
235
+
236
+ /**
237
+ Event Handler: On Add
238
+ */
239
+ onAdd = (...args: any): any =>
240
+ this.execHandler(FieldPropsEnum.onAdd, args, (e: Event, val: any) => {
241
+ isEvent(e) && e.preventDefault();
242
+ this.add(isEvent(val) ? null : val, false);
243
+ });
244
+
245
+ /**
246
+ Event Handler: On Del
247
+ */
248
+ onDel = (...args: any): any =>
249
+ this.execHandler(FieldPropsEnum.onDel, args, (e: Event, path: string) => {
250
+ isEvent(e) && e.preventDefault();
251
+ this.del(isEvent(path) ? this.path : path, false);
252
+ });
253
+
254
+ /******************************************************************
255
+ Initializer
256
+ */
257
+ initFields(initial: any, update: boolean = false): void {
258
+ const fallback = this.state.options.get(OptionsEnum.fallback);
259
+ const $path = (key: string) =>
260
+ [this.path, key].join(".").replace(/^\.+/, "");
261
+
262
+ let fields;
263
+ fields = prepareFieldsData(initial, this.state.strict, fallback);
264
+ fields = mergeSchemaDefaults(fields, (this as any).validator);
265
+
266
+ // create fields
267
+ forIn(fields, (field, key) => {
268
+ const path = $path(key);
269
+ const $f = this.select(path, null, false);
270
+ if ($f == null) {
271
+ if (fallback) {
272
+ this.initField(key, path, field, update);
273
+ } else {
274
+ const structPath = pathToStruct(path);
275
+ const struct = this.state.struct();
276
+ const found = struct
277
+ .filter((s: any) => s.startsWith(structPath))
278
+ .find(
279
+ (s: any) =>
280
+ s.charAt(structPath.length) === "." ||
281
+ s.substring(structPath.length, structPath.length + 2) ===
282
+ "[]" ||
283
+ s === structPath,
284
+ );
285
+
286
+ if (found) this.initField(key, path, field, update);
287
+ }
288
+ }
289
+ });
290
+ }
291
+
292
+ initField(
293
+ key: string,
294
+ path: string,
295
+ data: any,
296
+ update: boolean = false,
297
+ ): any {
298
+ const initial = this.state.get("current", "props");
299
+ const struct = pathToStruct(path);
300
+ // try to get props from separated objects
301
+ const _try = (prop: string) => {
302
+ const t = get(initial[prop], struct);
303
+ if (
304
+ (
305
+ [
306
+ FieldPropsEnum.input,
307
+ FieldPropsEnum.output,
308
+ FieldPropsEnum.converter,
309
+ ] as string[]
310
+ ).includes(prop) &&
311
+ typeof t !== "function"
312
+ )
313
+ return undefined;
314
+
315
+ return t;
316
+ };
317
+
318
+ const props = {
319
+ $value: get(initial[SeparatedPropsMode.values], path),
320
+ $computed: _try(SeparatedPropsMode.computed),
321
+ $label: _try(SeparatedPropsMode.labels),
322
+ $placeholder: _try(SeparatedPropsMode.placeholders),
323
+ $default: _try(SeparatedPropsMode.defaults),
324
+ $initial: _try(SeparatedPropsMode.initials),
325
+ $disabled: _try(SeparatedPropsMode.disabled),
326
+ $deleted: _try(SeparatedPropsMode.deleted),
327
+ $type: _try(SeparatedPropsMode.types),
328
+ $related: _try(SeparatedPropsMode.related),
329
+ $rules: _try(SeparatedPropsMode.rules),
330
+ $options: _try(SeparatedPropsMode.options),
331
+ $bindings: _try(SeparatedPropsMode.bindings),
332
+ $extra: _try(SeparatedPropsMode.extra),
333
+ $hooks: _try(SeparatedPropsMode.hooks),
334
+ $handlers: _try(SeparatedPropsMode.handlers),
335
+ $validatedWith: _try(SeparatedPropsMode.validatedWith),
336
+ $validators: _try(SeparatedPropsMode.validators),
337
+ $observers: _try(SeparatedPropsMode.observers),
338
+ $interceptors: _try(SeparatedPropsMode.interceptors),
339
+ $converters: _try(SeparatedPropsMode.converters),
340
+ $input: _try(SeparatedPropsMode.input),
341
+ $output: _try(SeparatedPropsMode.output),
342
+ $autoFocus: _try(SeparatedPropsMode.autoFocus),
343
+ $ref: _try(SeparatedPropsMode.refs),
344
+ $nullable: _try(SeparatedPropsMode.nullable),
345
+ $autoComplete: _try(SeparatedPropsMode.autoComplete),
346
+ };
347
+
348
+ const field = this.state.form.makeField(
349
+ {
350
+ key,
351
+ path,
352
+ struct,
353
+ data,
354
+ props,
355
+ update,
356
+ state: this.state,
357
+ },
358
+
359
+ (data && data[FieldPropsEnum.class]) || _try(SeparatedPropsMode.classes),
360
+ );
361
+
362
+ this.fields.merge({ [key]: field });
363
+
364
+ return field;
365
+ }
366
+
367
+ /******************************************************************
368
+ Actions
369
+ */
370
+
371
+ validate(opt?: ValidateOptions, obj?: ValidateOptions): Promise<any> {
372
+ const $opt = merge({}, opt, { path: this.path });
373
+ return this.state.form.validator.validate($opt, obj);
374
+ }
375
+
376
+ /**
377
+ Submit
378
+ */
379
+ submit(
380
+ hooks: SubmitHooks = {},
381
+ {
382
+ execOnSubmitHook = true,
383
+ execValidationHooks = true,
384
+ validate = true,
385
+ } = {},
386
+ ): Promise<any> {
387
+ const execOnSubmit = () => this.execHook(FieldPropsEnum.onSubmit, hooks);
388
+ const submit = execOnSubmitHook ? execOnSubmit() : undefined;
389
+ this.$submitting = true;
390
+ this.$submitted += 1;
391
+
392
+ if (
393
+ !validate ||
394
+ !this.state.options.get(OptionsEnum.validateOnSubmit, this)
395
+ ) {
396
+ return Promise.resolve(submit)
397
+ .then(action(() => (this.$submitting = false)))
398
+ .catch(
399
+ action((err: any) => {
400
+ this.$submitting = false;
401
+ throw err;
402
+ }),
403
+ )
404
+ .then(() => this);
405
+ }
406
+
407
+ const exec = (isValid: boolean) =>
408
+ isValid
409
+ ? this.execHook(ValidationHooks.onSuccess, hooks)
410
+ : this.execHook(ValidationHooks.onError, hooks);
411
+
412
+ return this.validate({
413
+ showErrors: this.state.options.get(OptionsEnum.showErrorsOnSubmit, this),
414
+ })
415
+ .then(({ isValid }: any) => {
416
+ const handler = execValidationHooks ? exec(isValid) : undefined;
417
+ if (isValid) return Promise.all([submit, handler]);
418
+ const $err = this.state.options.get(
419
+ OptionsEnum.defaultGenericError,
420
+ this,
421
+ );
422
+ const $throw = this.state.options.get(
423
+ OptionsEnum.submitThrowsError,
424
+ this,
425
+ );
426
+ if ($throw && $err) (this as any).invalidate();
427
+ return Promise.all([submit, handler]);
428
+ })
429
+ .then(action(() => (this.$submitting = false)))
430
+ .catch(
431
+ action((err: any) => {
432
+ this.$submitting = false;
433
+ throw err;
434
+ }),
435
+ )
436
+ .then(() => this);
437
+ }
438
+
439
+ /**
440
+ Check Field Computed Values
441
+ */
442
+ check(prop: string, deep: boolean = false): boolean {
443
+ allowedProps(AllowedFieldPropsTypes.computed, [prop]);
444
+
445
+ return deep
446
+ ? checkPropOccurrence({
447
+ type: props.occurrences[prop],
448
+ data: this.deepCheck(props.occurrences[prop], prop, this.fields),
449
+ })
450
+ : (this as any)[prop];
451
+ }
452
+
453
+ deepCheck(type: string, prop: string, fields: any): any {
454
+ const $fields = getObservableMapValues(fields);
455
+ return transform(
456
+ $fields,
457
+ (check: any, field: any) => {
458
+ if (!field.fields.size || !Array.isArray(field.initial)) {
459
+ check.push(field[prop]);
460
+ }
461
+
462
+ check.push(
463
+ checkPropOccurrence({
464
+ data: this.deepCheck(type, prop, field.fields),
465
+ type,
466
+ }),
467
+ );
468
+
469
+ return check;
470
+ },
471
+ [],
472
+ );
473
+ }
474
+
475
+ firstError(): string | null {
476
+ if (!this.state.options.get(OptionsEnum.bubbleUpErrorMessages, this as any))
477
+ return null;
478
+ for (const field of getObservableMapValues(this.fields)) {
479
+ if (field.error) return field.error;
480
+ if (field.fields.size) {
481
+ const nested = field.firstError();
482
+ if (nested) return nested;
483
+ }
484
+ }
485
+ return null;
486
+ }
487
+
488
+ /**
489
+ Update Field Values recurisvely
490
+ OR Create Field if 'undefined'
491
+ */
492
+ update(fields: any): void {
493
+ if (!isPlainObject(fields)) {
494
+ throw new Error("The update() method accepts only plain objects.");
495
+ }
496
+
497
+ this.deepUpdate(
498
+ prepareFieldsData({ fields }, this.state.strict),
499
+ undefined,
500
+ undefined,
501
+ fields,
502
+ );
503
+ }
504
+
505
+ deepUpdate(
506
+ fields: any,
507
+ path: string = "",
508
+ recursion: boolean = true,
509
+ raw?: any,
510
+ ): void {
511
+ each(fields, (field, key) => {
512
+ const $key = has(field, FieldPropsEnum.name) ? field.name : key;
513
+ const $path = `${path}.${$key}`.replace(/^\.+/, "");
514
+
515
+ const strictUpdate = this.state.options.get(
516
+ OptionsEnum.strictUpdate,
517
+ this,
518
+ );
519
+ const $field = this.select($path, null, strictUpdate);
520
+ const $container =
521
+ this.select(path, null, false) ||
522
+ this.state.form.select(this.path ?? "", null, false);
523
+ const applyInputConverterOnUpdate = this.state.options.get(
524
+ OptionsEnum.applyInputConverterOnUpdate,
525
+ this,
526
+ );
527
+
528
+ if ($field != null && field !== void 0) {
529
+ if (Array.isArray($field.values())) {
530
+ const n: number = Math.max(
531
+ -1,
532
+ ...Object.keys(field.fields || {}).map(Number),
533
+ );
534
+ getObservableMapValues($field.fields).forEach(($f) => {
535
+ if (Number($f.name) > n) {
536
+ $field.$changed++;
537
+ $field.state.form.$changed++;
538
+ $field.fields.delete($f.name);
539
+ }
540
+ });
541
+ }
542
+ if (field?.fields) {
543
+ const fallback = this.state.options.get(OptionsEnum.fallback);
544
+ const x = this.state
545
+ .struct()
546
+ .findIndex((s) =>
547
+ s.startsWith($field.path.replace(/\.\d+\./, "[].") + "[]"),
548
+ );
549
+ if (!fallback && $field.fields.size === 0 && x < 0) {
550
+ $field.value = parseInput(
551
+ applyInputConverterOnUpdate ? $field.$input : (val) => val,
552
+ {
553
+ fallbackValueOption: this.state.options.get(
554
+ OptionsEnum.fallbackValue,
555
+ this,
556
+ ),
557
+ separated: get(raw, $path),
558
+ },
559
+ );
560
+ return;
561
+ }
562
+ }
563
+ if (field === null || field.fields == null) {
564
+ $field.value = parseInput(
565
+ applyInputConverterOnUpdate ? $field.$input : (val) => val,
566
+ {
567
+ fallbackValueOption: this.state.options.get(
568
+ OptionsEnum.fallbackValue,
569
+ this,
570
+ ),
571
+ separated: field,
572
+ },
573
+ );
574
+ return;
575
+ }
576
+ }
577
+
578
+ if ($container != null && $field == null) {
579
+ // get full path when using update() with select() - FIX: #179
580
+ const $newFieldPath = [this.path, $path].join(".").replace(/^\.+/, "");
581
+ // init field into the container field
582
+ $container.$changed++;
583
+ $container.state.form.$changed++;
584
+ $container.initField($key, $newFieldPath, field, true);
585
+ } else if (recursion) {
586
+ if (has(field, FieldPropsEnum.fields) && field.fields != null) {
587
+ // handle nested fields if defined
588
+ this.deepUpdate(field.fields, $path);
589
+ } else {
590
+ // handle nested fields if undefined or null
591
+ const $fields = pathToFieldsTree(this.state.struct(), $path);
592
+ this.deepUpdate($fields, $path, false);
593
+ }
594
+ }
595
+ });
596
+ }
597
+
598
+ /**
599
+ Get Fields Props
600
+ */
601
+ get(prop: any = null, strict: boolean = true): any {
602
+ if (prop == null) {
603
+ return this.deepGet(
604
+ [...props.computed, ...props.editable, ...props.validation],
605
+ this.fields,
606
+ strict,
607
+ );
608
+ }
609
+
610
+ allowedProps(
611
+ AllowedFieldPropsTypes.all,
612
+ Array.isArray(prop) ? prop : [prop],
613
+ );
614
+
615
+ if (typeof prop === "string") {
616
+ if (
617
+ ([FieldPropsEnum.hooks, FieldPropsEnum.handlers] as string[]).includes(
618
+ prop,
619
+ )
620
+ ) {
621
+ return (this as any)[`$${prop}`];
622
+ }
623
+
624
+ if (strict && this.fields.size === 0) {
625
+ const retrieveNullifiedEmptyStrings = this.state.options.get(
626
+ OptionsEnum.retrieveNullifiedEmptyStrings,
627
+ this,
628
+ );
629
+ return parseCheckOutput(
630
+ this,
631
+ prop,
632
+ strict ? retrieveNullifiedEmptyStrings : false,
633
+ );
634
+ }
635
+
636
+ const value = this.deepGet(prop, this.fields, strict);
637
+ const removeNullishValuesInArrays = this.state.options.get(
638
+ OptionsEnum.removeNullishValuesInArrays,
639
+ this,
640
+ );
641
+
642
+ return parseCheckArray(
643
+ this,
644
+ value,
645
+ prop,
646
+ strict ? removeNullishValuesInArrays : false,
647
+ );
648
+ }
649
+
650
+ return this.deepGet(prop, this.fields, strict);
651
+ }
652
+
653
+ /**
654
+ Get Fields Props Recursively
655
+ */
656
+ deepGet(prop: any, fields: any, strict = true): any {
657
+ const _fieldsArr = getObservableMapValues(fields);
658
+ const _result = transform(
659
+ _fieldsArr,
660
+ (obj: any, field: any) => {
661
+ const $nested = ($fields: any) =>
662
+ $fields.size !== 0 ? this.deepGet(prop, $fields, strict) : undefined;
663
+
664
+ Object.assign(obj, {
665
+ [field.key]: { fields: $nested(field.fields) },
666
+ });
667
+
668
+ if (typeof prop === "string") {
669
+ const opt = this.state.options;
670
+ const removeProp =
671
+ (opt.get(OptionsEnum.retrieveOnlyDirtyFieldsValues, this) &&
672
+ prop === FieldPropsEnum.value &&
673
+ field.isPristine) ||
674
+ (opt.get(OptionsEnum.retrieveOnlyEnabledFieldsValues, this) &&
675
+ prop === FieldPropsEnum.value &&
676
+ field.disabled) ||
677
+ (opt.get(OptionsEnum.retrieveOnlyEnabledFieldsErrors, this) &&
678
+ prop === FieldPropsEnum.error &&
679
+ field.disabled &&
680
+ field.isValid &&
681
+ (!field.error || !field.hasError)) ||
682
+ (opt.get(OptionsEnum.softDelete, this) &&
683
+ prop === FieldPropsEnum.value &&
684
+ field.deleted);
685
+
686
+ if (field.fields.size === 0) {
687
+ delete obj[field.key];
688
+ if (removeProp) return obj;
689
+ const retrieveNullifiedEmptyStrings = this.state.options.get(
690
+ OptionsEnum.retrieveNullifiedEmptyStrings,
691
+ this,
692
+ );
693
+ return Object.assign(obj, {
694
+ [field.key]: parseCheckOutput(
695
+ field,
696
+ prop,
697
+ strict ? retrieveNullifiedEmptyStrings : false,
698
+ ),
699
+ });
700
+ }
701
+
702
+ let value = this.deepGet(prop, field.fields, strict);
703
+ if (prop === FieldPropsEnum.value) value = field.$output(value);
704
+
705
+ delete obj[field.key];
706
+ if (removeProp) return obj;
707
+ const removeNullishValuesInArrays = this.state.options.get(
708
+ OptionsEnum.removeNullishValuesInArrays,
709
+ this,
710
+ );
711
+
712
+ return Object.assign(obj, {
713
+ [field.key]: parseCheckArray(
714
+ field,
715
+ value,
716
+ prop,
717
+ strict ? removeNullishValuesInArrays : false,
718
+ ),
719
+ });
720
+ }
721
+
722
+ each(prop, ($prop) =>
723
+ Object.assign(obj[field.key], {
724
+ [$prop]: field[$prop],
725
+ }),
726
+ );
727
+
728
+ return obj;
729
+ },
730
+ {} as Record<string, any>,
731
+ );
732
+
733
+ // Array fields with integer keys must preserve _entries order
734
+ // (JavaScript Object.assign sorts integer-like keys regardless of insertion order)
735
+ if (
736
+ typeof prop === "string" &&
737
+ _fieldsArr.length > 0 &&
738
+ hasIntKeys(fields)
739
+ ) {
740
+ const keysInResult = new Set(Object.keys(_result));
741
+ return _fieldsArr
742
+ .filter((f) => keysInResult.has(String(f.key)))
743
+ .map((f) => _result[String(f.key)]);
744
+ }
745
+
746
+ return _result;
747
+ }
748
+
749
+ /**
750
+ Set Fields Props
751
+ */
752
+ set(prop: any, data?: any): void {
753
+ // UPDATE CUSTOM PROP
754
+ if (typeof prop === "string" && data !== void 0) {
755
+ allowedProps(AllowedFieldPropsTypes.editable, [prop]);
756
+
757
+ const isPlain = (
758
+ [FieldPropsEnum.hooks, FieldPropsEnum.handlers] as string[]
759
+ ).includes(prop);
760
+
761
+ const deep: boolean =
762
+ (data !== null &&
763
+ typeof data === "object" &&
764
+ prop === FieldPropsEnum.value) ||
765
+ (isPlainObject(data) && !isPlain);
766
+ if (deep && this.hasNestedFields)
767
+ return this.deepSet(prop, data, "", true);
768
+
769
+ if (prop === FieldPropsEnum.value) {
770
+ const applyInputConverterOnSet = this.state.options.get(
771
+ OptionsEnum.applyInputConverterOnSet,
772
+ this,
773
+ );
774
+ (this as any).value = parseInput(
775
+ applyInputConverterOnSet ? (this as any).$input : (val) => val,
776
+ {
777
+ fallbackValueOption: this.state.options.get(
778
+ OptionsEnum.fallbackValue,
779
+ this,
780
+ ),
781
+ separated: data,
782
+ },
783
+ );
784
+ } else if (isPlain) {
785
+ Object.assign((this as any)[`$${prop}`], data);
786
+ } else {
787
+ set(this, `$${prop}`, data);
788
+ }
789
+
790
+ return;
791
+ }
792
+
793
+ // NO PROP NAME PROVIDED ("prop" is value)
794
+ if (data == null) {
795
+ if (this.hasNestedFields)
796
+ this.deepSet(FieldPropsEnum.value, prop, "", true);
797
+ else this.set(FieldPropsEnum.value, prop);
798
+ }
799
+ }
800
+
801
+ /**
802
+ Set Fields Props Recursively
803
+ */
804
+ deepSet(
805
+ prop: any,
806
+ data: any,
807
+ path: string = "",
808
+ recursion: boolean = false,
809
+ ): void {
810
+ const err = "You are updating a not existent field:";
811
+ const isStrict = this.state.options.get(OptionsEnum.strictSet, this);
812
+
813
+ if (data == null) {
814
+ this.each(
815
+ (field: any) =>
816
+ (field.$value = defaultValue({
817
+ fallbackValueOption: this.state.options.get(
818
+ OptionsEnum.fallbackValue,
819
+ this,
820
+ ),
821
+ value: field.$value,
822
+ nullable: field.$nullable,
823
+ type: field.type,
824
+ })),
825
+ );
826
+ return;
827
+ }
828
+
829
+ each(data, ($val, $key) => {
830
+ const $path = `${path}.${$key}`.replace(/^\.+/, "");
831
+ // get the field by path joining keys recursively
832
+ const field = this.select($path, null, isStrict);
833
+ // if no field found when is strict update, throw error
834
+ if (isStrict) throwError($path, field, err);
835
+ // update the field/fields if defined
836
+ if (field !== void 0) {
837
+ // update field values or others props
838
+ if ($val !== void 0) {
839
+ field.set(prop, $val, recursion);
840
+ }
841
+ // update values recursively only if field has nested
842
+ if (field.fields.size && $val !== null && typeof $val === "object") {
843
+ this.deepSet(prop, $val, $path, recursion);
844
+ }
845
+ }
846
+ });
847
+ }
848
+
849
+ /**
850
+ Add Field
851
+ */
852
+ add(obj?: any, execEvent: boolean = true): any {
853
+ if (isArrayOfObjects(obj)) {
854
+ each(obj, (values) =>
855
+ this.update({
856
+ [maxKey(this.fields)]: values,
857
+ }),
858
+ );
859
+
860
+ this.$changed++;
861
+ this.state.form.$changed++;
862
+ execEvent && this.execHook(FieldPropsEnum.onAdd);
863
+ return this;
864
+ }
865
+
866
+ let key;
867
+ if (has(obj, FieldPropsEnum.key)) key = obj.key;
868
+ if (has(obj, FieldPropsEnum.name)) key = obj.name;
869
+ if (!key) key = maxKey(this.fields);
870
+
871
+ const $path = ($key: string) =>
872
+ [this.path, $key].join(".").replace(/^\.+/, "");
873
+ const tree = pathToFieldsTree(
874
+ this.state.struct(),
875
+ this.path ?? "",
876
+ 0,
877
+ true,
878
+ );
879
+ const field = this.initField(key, $path(key), merge(tree[0], obj));
880
+ const hasValues =
881
+ has(obj, FieldPropsEnum.value) || has(obj, FieldPropsEnum.fields);
882
+
883
+ if (!hasValues) {
884
+ // When the struct defines nested fields and obj is a plain object
885
+ // without field-definition props (key, name), treat obj properties
886
+ // directly as nested field values (e.g. add({ firstname: 'John' }))
887
+ if (
888
+ tree[0]?.fields &&
889
+ isPlainObject(obj) &&
890
+ !hasSome(obj, [FieldPropsEnum.key, FieldPropsEnum.name])
891
+ ) {
892
+ each(obj, (val, fieldName) => {
893
+ const nestedField = field.select(fieldName as string);
894
+ if (nestedField && !nestedField.hasNestedFields) {
895
+ nestedField.set(FieldPropsEnum.value, val);
896
+ }
897
+ });
898
+ } else if (
899
+ !this.state.options.get(OptionsEnum.preserveDeletedFieldsValues, this)
900
+ ) {
901
+ const fallbackValueOption = this.state.options.get(
902
+ OptionsEnum.fallbackValue,
903
+ this,
904
+ );
905
+ field.$value = defaultValue({
906
+ fallbackValueOption,
907
+ value: field.$value,
908
+ nullable: field.$nullable,
909
+ type: field.type,
910
+ });
911
+ field.each(
912
+ (f: any) =>
913
+ (f.$value = defaultValue({
914
+ fallbackValueOption,
915
+ value: f.$value,
916
+ nullable: f.$nullable,
917
+ type: f.type,
918
+ })),
919
+ );
920
+ }
921
+ }
922
+
923
+ this.$changed++;
924
+ this.state.form.$changed++;
925
+ execEvent && this.execHook(FieldPropsEnum.onAdd);
926
+ return field;
927
+ }
928
+
929
+ /**
930
+ Del Field
931
+ */
932
+ del($path: string | null = null, execEvent: boolean = true) {
933
+ const isStrict = this.state.options.get(OptionsEnum.strictDelete, this);
934
+ const path = parsePath($path ?? this.path ?? "");
935
+ const fullpath = [this.path ?? "", path ?? ""]
936
+ .join(".")
937
+ .replace(/^\.+|\.+$/g, "");
938
+ const container = this.container($path);
939
+ const keys = path.split(".");
940
+ const lastKey = keys[keys.length - 1];
941
+
942
+ if (isStrict && !container.fields.has(lastKey)) {
943
+ const msg = `Key "${lastKey}" not found when trying to delete field`;
944
+ throwError(fullpath, null, msg);
945
+ }
946
+
947
+ container.$changed++;
948
+ container.state.form.$changed++;
949
+
950
+ if (this.state.options.get(OptionsEnum.softDelete, this)) {
951
+ return this.select(fullpath).set(FieldPropsEnum.deleted, true);
952
+ }
953
+
954
+ container.each((field: any) => field.debouncedValidation.cancel());
955
+ execEvent && this.execHook(FieldPropsEnum.onDel);
956
+ return container.fields.delete(lastKey);
957
+ }
958
+
959
+ /******************************************************************
960
+ Events
961
+ */
962
+
963
+ /**
964
+ MobX Event (observe/intercept)
965
+ */
966
+ MOBXEvent({
967
+ prop = FieldPropsEnum.value,
968
+ key = null,
969
+ path = null,
970
+ call,
971
+ type,
972
+ }: any): void {
973
+ let $prop = key || prop;
974
+ allowedProps(AllowedFieldPropsTypes.observable, [$prop]);
975
+ const $instance = this.select(path || this.path, null, false) || this;
976
+
977
+ const $call = (change: any) =>
978
+ call.apply(null, [
979
+ {
980
+ change,
981
+ form: this.state.form,
982
+ path: $instance.path || null,
983
+ field: $instance.path ? $instance : null,
984
+ },
985
+ ]);
986
+
987
+ let fn;
988
+ let ffn;
989
+
990
+ if (type === "observer") {
991
+ fn = observe;
992
+ ffn = (cb: any) => observe($instance.fields.toArray(), cb); // fields
993
+ }
994
+
995
+ if (type === "interceptor") {
996
+ $prop = `$${prop}`;
997
+ fn = intercept;
998
+ ffn = $instance.fields.intercept; // fields
999
+ }
1000
+ const $dkey = $instance.path ? `${$prop}@${$instance.path}` : $prop;
1001
+
1002
+ merge((this.state.disposers as any)[type], {
1003
+ [$dkey]:
1004
+ $prop === FieldPropsEnum.fields
1005
+ ? ffn.apply((change: any) => $call(change))
1006
+ : (fn as any)($instance, $prop, (change: any) => $call(change)),
1007
+ });
1008
+ }
1009
+
1010
+ /**
1011
+ Dispose MOBX Events
1012
+ */
1013
+ dispose(opt: any = null): void {
1014
+ if (this.path && opt) return this.disposeSingle(opt);
1015
+ return this.disposeAll();
1016
+ }
1017
+
1018
+ /**
1019
+ Dispose All Events (observe/intercept)
1020
+ */
1021
+ disposeAll(): void {
1022
+ const dispose = (disposer: any) => disposer.apply();
1023
+ each(this.state.disposers.interceptor, dispose);
1024
+ each(this.state.disposers.observer, dispose);
1025
+ this.state.disposers = { interceptor: {}, observer: {} };
1026
+ return;
1027
+ }
1028
+
1029
+ /**
1030
+ Dispose Single Event (observe/intercept)
1031
+ */
1032
+ disposeSingle({ type, key = FieldPropsEnum.value, path = null }: any) {
1033
+ const $path = parsePath(path ?? this.path ?? "");
1034
+ // eslint-disable-next-line
1035
+ if (type === "interceptor") key = `$${key}`; // target observables
1036
+ const disposersType = (this.state.disposers as any)[type];
1037
+ disposersType[`${key}@${$path}`].apply();
1038
+ delete disposersType[`${key}@${$path}`];
1039
+ }
1040
+
1041
+ /******************************************************************
1042
+ Utils
1043
+ */
1044
+
1045
+ /**
1046
+ Fields Selector
1047
+ */
1048
+ select(path: string | number, fields: any = null, isStrict: boolean = true) {
1049
+ const $path = parsePath(String(path));
1050
+ const keys = $path.split(".");
1051
+ const headKey = keys[0];
1052
+
1053
+ keys.shift();
1054
+
1055
+ let $fields =
1056
+ fields == null ? this.fields.get(headKey) : fields.get(headKey);
1057
+
1058
+ let stop = false;
1059
+ each(keys, ($key) => {
1060
+ if (stop) return;
1061
+ if ($fields == null) {
1062
+ $fields = undefined;
1063
+ stop = true;
1064
+ } else {
1065
+ $fields = $fields.fields.get($key);
1066
+ }
1067
+ });
1068
+
1069
+ if (isStrict && this.state.options.get(OptionsEnum.strictSelect, this)) {
1070
+ throwError(String(path), $fields);
1071
+ }
1072
+
1073
+ return $fields;
1074
+ }
1075
+
1076
+ /**
1077
+ Get Container
1078
+ */
1079
+ container($path?: string | null) {
1080
+ const path = parsePath($path ?? this.path ?? "");
1081
+ const cpath = path.replace(/[^./]+$/, "").replace(/^\.+|\.+$/g, "");
1082
+
1083
+ if (!!this.path && $path == null) {
1084
+ return cpath !== ""
1085
+ ? this.state.form.select(cpath, null, false)
1086
+ : this.state.form;
1087
+ }
1088
+
1089
+ return cpath !== "" ? this.select(cpath, null, false) : this;
1090
+ }
1091
+
1092
+ /**
1093
+ Has Field
1094
+ */
1095
+ has(path: string): boolean {
1096
+ return this.fields.has(path);
1097
+ }
1098
+
1099
+ /**
1100
+ Map Fields
1101
+ */
1102
+ map(cb: any): ReadonlyArray<FieldInterface> {
1103
+ return getObservableMapValues(this.fields).map(cb);
1104
+ }
1105
+
1106
+ /**
1107
+ * Iterates deeply over fields and invokes `iteratee` for each element.
1108
+ * The iteratee is invoked with three arguments: (value, index|key, depth).
1109
+ *
1110
+ * @param {Function} iteratee The function invoked per iteration.
1111
+ * @param {Array|Object} [fields=form.fields] fields to iterate over.
1112
+ * @param {number} [depth=1] The recursion depth for internal use.
1113
+ * @returns {Array} Returns [fields.values()] of input [fields] parameter.
1114
+ * @example
1115
+ *
1116
+ * JSON.stringify(form)
1117
+ * // => {
1118
+ * "fields": {
1119
+ * "state": {
1120
+ * "fields": {
1121
+ * "city": {
1122
+ * "fields": { "places": {
1123
+ * "fields": {},
1124
+ * "key": "places", "path": "state.city.places", "$value": "NY Places"
1125
+ * }
1126
+ * },
1127
+ * "key": "city", "path": "state.city", "$value": "New York"
1128
+ * }
1129
+ * },
1130
+ * "key": "state", "path": "state", "$value": "USA"
1131
+ * }
1132
+ * }
1133
+ * }
1134
+ *
1135
+ * const data = {};
1136
+ * form.each(field => data[field.path] = field.value);
1137
+ * // => {
1138
+ * "state": "USA",
1139
+ * "state.city": "New York",
1140
+ * "state.city.places": "NY Places"
1141
+ * }
1142
+ *
1143
+ */
1144
+ each(iteratee: any, fields: any = null, depth: number = 0) {
1145
+ const $fields = fields || this.fields;
1146
+ getObservableMapValues($fields).forEach((field: FieldInterface, index) => {
1147
+ iteratee(field, index, depth);
1148
+
1149
+ if (field.fields.size !== 0) {
1150
+ this.each(iteratee, field.fields, depth + 1);
1151
+ }
1152
+ });
1153
+ }
1154
+
1155
+ reduce(iteratee: any, acc: any): any {
1156
+ return getObservableMapValues(this.fields).reduce(iteratee, acc);
1157
+ }
1158
+
1159
+ /******************************************************************
1160
+ Array Operations
1161
+ */
1162
+
1163
+ /**
1164
+ Move a field from one index to another (for sortable lists).
1165
+ */
1166
+ move(fromIndex: number, toIndex: number): void {
1167
+ this.fields.move(fromIndex, toIndex);
1168
+ }
1169
+
1170
+ /******************************************************************
1171
+ Helpers
1172
+ */
1173
+
1174
+ /**
1175
+ Fields Selector (alias of select)
1176
+ */
1177
+ $(key: string) {
1178
+ return this.select(key);
1179
+ }
1180
+
1181
+ /**
1182
+ Fields Values (recursive with Nested Fields)
1183
+ */
1184
+ values() {
1185
+ return this.get(FieldPropsEnum.value);
1186
+ }
1187
+
1188
+ /**
1189
+ Fields Errors (recursive with Nested Fields)
1190
+ */
1191
+ errors() {
1192
+ return this.get(FieldPropsEnum.error);
1193
+ }
1194
+
1195
+ /**
1196
+ Fields Labels (recursive with Nested Fields)
1197
+ */
1198
+ labels() {
1199
+ return this.get(FieldPropsEnum.label);
1200
+ }
1201
+
1202
+ /**
1203
+ Fields Placeholders (recursive with Nested Fields)
1204
+ */
1205
+ placeholders() {
1206
+ return this.get(FieldPropsEnum.placeholder);
1207
+ }
1208
+
1209
+ /**
1210
+ Fields Default Values (recursive with Nested Fields)
1211
+ */
1212
+ defaults() {
1213
+ return this.get(FieldPropsEnum.default);
1214
+ }
1215
+
1216
+ /**
1217
+ Fields Initial Values (recursive with Nested Fields)
1218
+ */
1219
+ initials() {
1220
+ return this.get(FieldPropsEnum.initial);
1221
+ }
1222
+
1223
+ /**
1224
+ Fields Types (recursive with Nested Fields)
1225
+ */
1226
+ types() {
1227
+ return this.get(FieldPropsEnum.type);
1228
+ }
1229
+ }