native-document 1.0.70 → 1.0.72

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 (117) hide show
  1. package/components.js +2 -0
  2. package/dist/native-document.components.min.js +5636 -0
  3. package/dist/native-document.dev.js +380 -321
  4. package/dist/native-document.dev.js.map +1 -1
  5. package/dist/native-document.devtools.min.js +1 -1
  6. package/dist/native-document.min.js +1 -1
  7. package/elements.js +3 -3
  8. package/index.js +17 -17
  9. package/package.json +1 -1
  10. package/rollup.config.js +17 -1
  11. package/src/components/fom-control/FormControl.js +247 -0
  12. package/src/components/fom-control/default/DefaultLayout.js +8 -0
  13. package/src/components/fom-control/default/collection/DefaultCollectionLayout.js +12 -0
  14. package/src/components/fom-control/default/collection/DefaultCollectionTemplate.js +6 -0
  15. package/src/components/fom-control/field/DefaultRender.js +91 -0
  16. package/src/components/fom-control/field/Field.js +396 -0
  17. package/src/components/fom-control/field/FieldCollection.js +260 -0
  18. package/src/components/fom-control/field/FieldFactory.js +107 -0
  19. package/src/components/fom-control/field/types/AutocompleteField.js +46 -0
  20. package/src/components/fom-control/field/types/CheckboxField.js +17 -0
  21. package/src/components/fom-control/field/types/CheckboxGroupField.js +78 -0
  22. package/src/components/fom-control/field/types/ColorField.js +39 -0
  23. package/src/components/fom-control/field/types/DateField.js +62 -0
  24. package/src/components/fom-control/field/types/EmailField.js +44 -0
  25. package/src/components/fom-control/field/types/FileField.js +66 -0
  26. package/src/components/fom-control/field/types/HiddenField.js +8 -0
  27. package/src/components/fom-control/field/types/ImageField.js +49 -0
  28. package/src/components/fom-control/field/types/NumberField.js +74 -0
  29. package/src/components/fom-control/field/types/PasswordField.js +72 -0
  30. package/src/components/fom-control/field/types/RadioField.js +44 -0
  31. package/src/components/fom-control/field/types/RangeField.js +17 -0
  32. package/src/components/fom-control/field/types/SearchField.js +17 -0
  33. package/src/components/fom-control/field/types/SelectField.js +41 -0
  34. package/src/components/fom-control/field/types/StringField.js +49 -0
  35. package/src/components/fom-control/field/types/TelField.js +38 -0
  36. package/src/components/fom-control/field/types/TextAreaField.js +56 -0
  37. package/src/components/fom-control/field/types/TimeField.js +45 -0
  38. package/src/components/fom-control/field/types/UrlField.js +53 -0
  39. package/src/components/fom-control/index.js +8 -0
  40. package/src/components/fom-control/merge +0 -0
  41. package/src/components/fom-control/utils.js +17 -0
  42. package/src/components/fom-control/validation/Validation.js +556 -0
  43. package/src/components/table/Column.js +106 -0
  44. package/src/components/table/ColumnGroup.js +54 -0
  45. package/src/components/table/DataTable.js +195 -0
  46. package/src/components/table/SimpleTable.js +184 -0
  47. package/src/components/table/index.js +9 -0
  48. package/src/{data → core/data}/ObservableArray.js +1 -0
  49. package/src/{data → core/data}/ObservableItem.js +49 -3
  50. package/src/{data → core/data}/observable-helpers/computed.js +2 -1
  51. package/src/{elements → core/elements}/anchor.js +32 -32
  52. package/src/{elements → core/elements}/control/for-each-array.js +4 -2
  53. package/src/core/utils/EventEmitter.js +46 -0
  54. package/src/{utils → core/utils}/helpers.js +12 -0
  55. package/src/{utils → core/utils}/validator.js +7 -0
  56. package/src/{wrappers → core/wrappers}/ElementCreator.js +10 -33
  57. package/src/{wrappers → core/wrappers}/NDElement.js +0 -127
  58. package/src/core/wrappers/NdPrototype.js +147 -0
  59. package/src/core/wrappers/TemplateBinding.js +7 -0
  60. package/src/{wrappers → core/wrappers}/TemplateCloner.js +5 -6
  61. package/src/core/wrappers/prototype-extensions.js +56 -0
  62. package/src/devtools/hrm/ComponentRegistry.js +1 -1
  63. package/src/router/Route.js +1 -1
  64. package/src/router/RouteGroupHelper.js +1 -1
  65. package/src/router/Router.js +4 -4
  66. package/src/router/RouterComponent.js +13 -2
  67. package/src/router/link.js +2 -2
  68. package/src/router/modes/HistoryRouter.js +2 -2
  69. package/types/forms.d.ts +2 -1
  70. package/types/validator.ts +2 -1
  71. package/utils.js +3 -3
  72. package/src/wrappers/NdPrototype.js +0 -71
  73. /package/src/{data → core/data}/MemoryManager.js +0 -0
  74. /package/src/{data → core/data}/Observable.js +0 -0
  75. /package/src/{data → core/data}/ObservableChecker.js +0 -0
  76. /package/src/{data → core/data}/ObservableWhen.js +0 -0
  77. /package/src/{data → core/data}/Store.js +0 -0
  78. /package/src/{data → core/data}/observable-helpers/array.js +0 -0
  79. /package/src/{data → core/data}/observable-helpers/batch.js +0 -0
  80. /package/src/{data → core/data}/observable-helpers/object.js +0 -0
  81. /package/src/{elements → core/elements}/content-formatter.js +0 -0
  82. /package/src/{elements → core/elements}/control/for-each.js +0 -0
  83. /package/src/{elements → core/elements}/control/show-if.js +0 -0
  84. /package/src/{elements → core/elements}/control/show-when.js +0 -0
  85. /package/src/{elements → core/elements}/control/switch.js +0 -0
  86. /package/src/{elements → core/elements}/description-list.js +0 -0
  87. /package/src/{elements → core/elements}/form.js +0 -0
  88. /package/src/{elements → core/elements}/html5-semantics.js +0 -0
  89. /package/src/{elements → core/elements}/img.js +0 -0
  90. /package/src/{elements → core/elements}/index.js +0 -0
  91. /package/src/{elements → core/elements}/interactive.js +0 -0
  92. /package/src/{elements → core/elements}/list.js +0 -0
  93. /package/src/{elements → core/elements}/medias.js +0 -0
  94. /package/src/{elements → core/elements}/meta-data.js +0 -0
  95. /package/src/{elements → core/elements}/table.js +0 -0
  96. /package/src/{errors → core/errors}/ArgTypesError.js +0 -0
  97. /package/src/{errors → core/errors}/NativeDocumentError.js +0 -0
  98. /package/src/{errors → core/errors}/RouterError.js +0 -0
  99. /package/src/{utils → core/utils}/args-types.js +0 -0
  100. /package/src/{utils → core/utils}/debug-manager.js +0 -0
  101. /package/src/{utils → core/utils}/events.js +0 -0
  102. /package/src/{utils → core/utils}/filters/date.js +0 -0
  103. /package/src/{utils → core/utils}/filters/index.js +0 -0
  104. /package/src/{utils → core/utils}/filters/standard.js +0 -0
  105. /package/src/{utils → core/utils}/filters/strings.js +0 -0
  106. /package/src/{utils → core/utils}/filters/utils.js +0 -0
  107. /package/src/{utils → core/utils}/memoize.js +0 -0
  108. /package/src/{utils → core/utils}/plugins-manager.js +0 -0
  109. /package/src/{utils → core/utils}/property-accumulator.js +0 -0
  110. /package/src/{utils → core/utils}/prototypes.js +0 -0
  111. /package/src/{utils → core/utils}/service.js +0 -0
  112. /package/src/{wrappers → core/wrappers}/AttributesWrapper.js +0 -0
  113. /package/src/{wrappers → core/wrappers}/DocumentObserver.js +0 -0
  114. /package/src/{wrappers → core/wrappers}/HtmlElementWrapper.js +0 -0
  115. /package/src/{wrappers → core/wrappers}/SingletonView.js +0 -0
  116. /package/src/{wrappers → core/wrappers}/constants.js +0 -0
  117. /package/src/{utils/fetch → fetch}/NativeFetch.js +0 -0
@@ -0,0 +1,396 @@
1
+ import {Validation} from "../validation/Validation";
2
+ import DefaultRender from "./DefaultRender";
3
+ import {Validator} from "../../../../index";
4
+ import {ShowIf} from "../../../../elements";
5
+ import {resolveParams} from "../utils";
6
+
7
+ export default function Field(name, type, defaultConfig) {
8
+
9
+ this.$description = {
10
+ name: name,
11
+ type: type,
12
+ key: name,
13
+ label: null,
14
+ placeholder: null,
15
+ help: null,
16
+ defaultValue: null,
17
+ disabled: false,
18
+ readonly: false,
19
+ rules: [],
20
+ clearErrorOn: 'focus',
21
+ validateOn: 'blur',
22
+ showIf: null,
23
+ requiredIf: null,
24
+ value: null,
25
+ errors: null,
26
+ showErrors: true,
27
+ id: null,
28
+ suffix: 'field',
29
+ classes: {
30
+ wrapper: null,
31
+ label: null,
32
+ input: null,
33
+ error: null,
34
+ hint: null
35
+ },
36
+ events: {},
37
+ ...defaultConfig
38
+ };
39
+
40
+ this.$element = null;
41
+ this.$input = null;
42
+
43
+ }
44
+
45
+ Field.renderers = {};
46
+
47
+ Field.defaultRenderer = DefaultRender;
48
+
49
+
50
+
51
+ // ---------------------------------------------
52
+ // COMMON METHODS
53
+ // ---------------------------------------------
54
+ Object.defineProperty( Field.prototype, 'nd', {
55
+ get: function() {
56
+ return this.field().nd;
57
+ }
58
+ });
59
+
60
+ Field.prototype.id = function(value) {
61
+ this.$description.id = value;
62
+ return this;
63
+ };
64
+
65
+ Field.prototype.suffix = function(value) {
66
+ this.$description.suffix = value;
67
+ return this;
68
+ };
69
+
70
+ Field.prototype.field = function() {
71
+ if(!this.$element) {
72
+ this.$element = this.toNdElement();
73
+ }
74
+ return this.$element;
75
+ };
76
+
77
+ Field.prototype.input = function(callback) {
78
+ if(!this.$input) {
79
+ this.field();
80
+ }
81
+ callback && callback(this.$input);
82
+ return this;
83
+ };
84
+
85
+ Field.prototype.render = function(customRenderer) {
86
+ if (typeof customRenderer !== 'function') {
87
+ throw new Error('Custom renderer must be a function');
88
+ }
89
+
90
+ this.$description.customRenderer = customRenderer;
91
+ return this;
92
+ };
93
+
94
+ Field.registerRenderer = function(type, renderer) {
95
+ if (typeof renderer !== 'function') {
96
+ throw new Error(`Renderer for type "${type}" must be a function`);
97
+ }
98
+
99
+ Field.renderers[type] = renderer;
100
+ };
101
+
102
+ Field.prototype.getRenderer = function() {
103
+ if (this.$description.customRenderer) {
104
+ return this.$description.customRenderer;
105
+ }
106
+
107
+ const typeRenderer = Field.renderers[this.$description.type];
108
+ if (typeRenderer) {
109
+ return typeRenderer;
110
+ }
111
+
112
+ return Field.defaultRenderer;
113
+ };
114
+
115
+ Field.prototype.showErrors = function(show = true) {
116
+ this.$description.showErrors = show;
117
+ return this;
118
+ };
119
+
120
+ Field.prototype.hideErrors = function() {
121
+ this.$description.showErrors = false;
122
+ return this;
123
+ };
124
+
125
+ Field.prototype.value = function(value) {
126
+ this.$description.value = value;
127
+ return this;
128
+ };
129
+
130
+ Field.prototype.errors = function(errors) {
131
+ if(!Validator.isObservable(errors)) {
132
+ throw new Error('Errors must be an observable');
133
+ }
134
+ this.$description.errors = errors;
135
+ return this;
136
+ };
137
+
138
+ Field.prototype.setError = function(error) {
139
+ this.$description.errors?.set?.(error);
140
+ return this;
141
+ };
142
+
143
+ Field.prototype.type = function(type) {
144
+ this.$description.type = type;
145
+ return this;
146
+ };
147
+
148
+ Field.prototype.key = function(keyInData) {
149
+ this.$description.key = keyInData;
150
+ return this;
151
+ };
152
+
153
+ Field.prototype.default = function(value) {
154
+ this.$description.defaultValue = value;
155
+ return this;
156
+ };
157
+
158
+ Field.prototype.label = function(text) {
159
+ this.$description.label = text;
160
+ return this;
161
+ };
162
+
163
+ Field.prototype.help = function(text) {
164
+ this.$description.help = text;
165
+ return this;
166
+ };
167
+
168
+ Field.prototype.hint = function(text) {
169
+ this.$description.help = text;
170
+ return this;
171
+ };
172
+
173
+ Field.prototype.placeholder = function(text) {
174
+ this.$description.placeholder = text;
175
+ return this;
176
+ };
177
+
178
+ Field.prototype.disabled = function(value) {
179
+ this.$description.disabled = value;
180
+ return this;
181
+ };
182
+
183
+ Field.prototype.readonly = function(value) {
184
+ this.$description.readonly = value;
185
+ return this;
186
+ };
187
+
188
+ Field.prototype.required = function(message) {
189
+ this.$description.rules.push({
190
+ fn: Validation.required,
191
+ message: message || `${this.$description.label || this.$description.name} is required`
192
+ });
193
+ return this;
194
+ };
195
+
196
+ Field.prototype.custom = function(validatorFn, message) {
197
+ this.$description.rules.push({
198
+ validate: validatorFn,
199
+ message: message || 'Validation failed'
200
+ });
201
+ return this;
202
+ };
203
+
204
+ Field.prototype.clearErrorOn = function(event) {
205
+ this.$description.clearErrorOn = event;
206
+ return this;
207
+ };
208
+
209
+ Field.prototype.validateOn = function(event) {
210
+ this.$description.validateOn = event;
211
+ return this;
212
+ };
213
+
214
+ Field.prototype.showIf = function(condition) {
215
+ this.$description.showIf = condition;
216
+ return this;
217
+ };
218
+
219
+ Field.prototype.requiredIf = function(condition, message) {
220
+ this.addRule(Validation.requiredIf, [condition], message);
221
+ return this;
222
+ };
223
+
224
+ Field.prototype.addRule = function(validationFn, params, message) {
225
+ this.$description.rules.push({
226
+ fn: validationFn,
227
+ params: params || [],
228
+ message
229
+ });
230
+ return this;
231
+ };
232
+
233
+ Field.prototype.getValue = function() {
234
+ const value = this.$description.value || this.$description.checked;
235
+ return Validator.isObservable(value) ? value.val() : value;
236
+ };
237
+
238
+ Field.prototype.validate = function(allValues = {}) {
239
+ if (!this.$description.rules || this.$description.rules.length === 0) {
240
+ this.$description.errors?.set(null);
241
+ return [];
242
+ }
243
+
244
+ const errors = [];
245
+ const value = this.getValue();
246
+
247
+ for (const rule of this.$description.rules) {
248
+ const paramsResolved = resolveParams(rule, allValues);
249
+ const result = rule.fn(value, ...paramsResolved, allValues);
250
+
251
+ if (!result.valid) {
252
+ errors.push(rule.message || result.message);
253
+ }
254
+ }
255
+
256
+ this.$description.errors?.set(errors.length ? errors : null);
257
+ return errors;
258
+ };
259
+
260
+ Field.prototype.toJSON = function() {
261
+ return {
262
+ ...this.$description,
263
+ rules: this.$description.rules?.map(r => ({
264
+ type: r.fn.name,
265
+ params: r.params,
266
+ message: r.message
267
+ })),
268
+ };
269
+ };
270
+
271
+ Field.prototype.classes = function(classesObject) {
272
+ Object.assign(this.$description.classes, classesObject);
273
+ return this;
274
+ };
275
+
276
+ Field.prototype.wrapperClass = function(wrapperClass) {
277
+ this.$description.classes.wrapper = wrapperClass;
278
+ return this;
279
+ };
280
+
281
+ Field.prototype.inputClass = function(inputClass) {
282
+ this.$description.classes.input = inputClass;
283
+ return this;
284
+ };
285
+
286
+ Field.prototype.labelClass = function(labelClass) {
287
+ this.$description.classes.label = labelClass;
288
+ return this;
289
+ };
290
+
291
+ Field.prototype.errorClass = function(errorClass) {
292
+ this.$description.classes.error = errorClass;
293
+ return this;
294
+ };
295
+
296
+ Field.prototype.hintClass = function(hintClass) {
297
+ this.$description.classes.error = hintClass;
298
+ return this;
299
+ };
300
+
301
+ Field.prototype.toNdElement = function() {
302
+ if(this.$element) {
303
+ return this.$element;
304
+ }
305
+ const renderer = this.getRenderer();
306
+ this.$element = renderer(this);
307
+
308
+ if(this.$description.showIf) {
309
+ ShowIf(this.$description.showIf, this.$element);
310
+ }
311
+
312
+ return this.$element;
313
+ };
314
+
315
+ // ---------------------------------------------
316
+ // Events METHODS
317
+ // ---------------------------------------------
318
+ Field.prototype.onChange = function(callback) {
319
+ this.$description.events['change'] = callback;
320
+ return this;
321
+ };
322
+
323
+ Field.prototype.onInput = function(callback) {
324
+ this.$description.events['input'] = callback;
325
+ return this;
326
+ };
327
+
328
+ Field.prototype.onFocus = function(callback) {
329
+ this.$description.events['focus'] = callback;
330
+ return this;
331
+ };
332
+
333
+ Field.prototype.onBlur = function(callback) {
334
+ this.$description.events['blur'] = callback;
335
+ return this;
336
+ };
337
+
338
+
339
+ Field.prototype.onKeydown = function(callback) {
340
+ this.$description.events['keydown'] = callback;
341
+ return this;
342
+ };
343
+
344
+ Field.prototype.onKeyup = function(callback) {
345
+ this.$description.events['keyup'] = callback;
346
+ return this;
347
+ };
348
+
349
+ Field.prototype.onKeypress = function(callback) {
350
+ this.$description.events['keypress'] = callback;
351
+ return this;
352
+ };
353
+
354
+
355
+ Field.prototype.onPaste = function(callback) {
356
+ this.$description.events['paste'] = callback;
357
+ return this;
358
+ };
359
+
360
+ Field.prototype.onCut = function(callback) {
361
+ this.$description.events['cut'] = callback;
362
+ return this;
363
+ };
364
+
365
+ Field.prototype.onCopy = function(callback) {
366
+ this.$description.events['copy'] = callback;
367
+ return this;
368
+ };
369
+
370
+
371
+ Field.prototype.onFileSelect = function(callback) {
372
+ this.$description.events['fileselect'] = callback;
373
+ return this;
374
+ };
375
+
376
+ Field.prototype.onDrop = function(callback) {
377
+ this.$description.events['drop'] = callback;
378
+ return this;
379
+ };
380
+
381
+ Field.prototype.onDragover = function(callback) {
382
+ this.$description.events['dragover'] = callback;
383
+ return this;
384
+ };
385
+
386
+
387
+ // Autocomplete
388
+ Field.prototype.onSearch = function(callback) {
389
+ this.$description.events['search'] = callback;
390
+ return this;
391
+ };
392
+
393
+ Field.prototype.onSelect = function(callback) {
394
+ this.$description.events['select'] = callback;
395
+ return this;
396
+ };
@@ -0,0 +1,260 @@
1
+ import { Observable as $, Validator } from "../../../../index";
2
+ import { Button } from "../../../../elements";
3
+ import NativeDocumentError from "../../../core/errors/NativeDocumentError";
4
+ import {Validation} from "../validation/Validation";
5
+ import DefaultCollectionLayout from "../default/collection/DefaultCollectionLayout";
6
+ import DefaultCollectionTemplate from "../default/collection/DefaultCollectionTemplate";
7
+ import {resolveParams} from "../utils";
8
+
9
+ export default function FieldCollection(name, config) {
10
+ this.$description = {
11
+ name: name,
12
+ defaultItem: null,
13
+ value: (config?.data && Validator.isObservable(config.data))
14
+ ? config.data
15
+ : $.array(config?.data || []),
16
+ rules: null,
17
+ layout: DefaultCollectionLayout,
18
+ template: DefaultCollectionTemplate,
19
+ ...config
20
+ };
21
+
22
+ this.$items = null;
23
+ this.$currentRefId = 0;
24
+ }
25
+
26
+
27
+ const setFieldValue = (field, name, proxyData) => {
28
+ const value = field.$description.value || field.$description.checked;
29
+
30
+ if(value != null) {
31
+ return;
32
+ }
33
+ if(typeof field.checked === 'function') {
34
+ field.checked(proxyData[name]);
35
+ return;
36
+ }
37
+ field.value(proxyData[name]);
38
+ };
39
+
40
+ Object.defineProperty(FieldCollection.prototype, 'items', {
41
+ get() { return this.$items; }
42
+ });
43
+
44
+ FieldCollection.prototype.data = function(data) {
45
+ this.$description.defaultItem = data;
46
+ return this;
47
+ };
48
+
49
+ FieldCollection.prototype.isEmpty = function() {
50
+ return this.$description.value.val().length === 0;
51
+ };
52
+
53
+ FieldCollection.prototype.count = function() {
54
+ return this.$description.value.val().length;
55
+ };
56
+
57
+ FieldCollection.prototype.addRule = function(validationFn, params, message) {
58
+ this.$description.rules = this.$description.rules || [];
59
+ this.$description.rules.push({
60
+ fn: validationFn,
61
+ params: params || [],
62
+ message
63
+ });
64
+ return this;
65
+ };
66
+
67
+ FieldCollection.prototype.fields = function(fieldBuilder) {
68
+ if(typeof fieldBuilder !== "function") {
69
+ throw new NativeDocumentError('Field builder must be a function');
70
+ }
71
+ this.$fieldBuilder = fieldBuilder;
72
+ return this;
73
+ };
74
+
75
+ FieldCollection.prototype.template = function(template) {
76
+ if(typeof template !== "function") {
77
+ throw new NativeDocumentError('Template must be a function');
78
+ }
79
+ this.$description.template = function(item, index) {
80
+ const fields = this.items.get(item).fields;
81
+ return template.call(this, item, index, { collection: this, fields });
82
+ };
83
+ return this;
84
+ };
85
+
86
+ FieldCollection.prototype.add = function(...args) {
87
+ if (!this.$fieldBuilder) {
88
+ throw new NativeDocumentError('Field builder not defined');
89
+ }
90
+
91
+ const defaultItem = this.$description.defaultItem;
92
+ let defaultItemData = (typeof defaultItem === 'function' ? defaultItem(...args) : defaultItem) || '';
93
+ defaultItemData = Validator.isObservable(defaultItemData)
94
+ ? defaultItemData
95
+ : Validator.isObject(defaultItemData)
96
+ ? $.init(defaultItemData)
97
+ : $(defaultItemData);
98
+
99
+ this.$items = this.$items || new WeakMap();
100
+
101
+ const refId = this.$currentRefId++;
102
+ const createdFields = this.$fieldBuilder(refId, defaultItemData);
103
+ let fields = {};
104
+ if(Array.isArray(createdFields)) {
105
+ createdFields.forEach(field => {
106
+ const name = field.$description.name.split('.').pop();
107
+ setFieldValue(field, name, defaultItemData);
108
+ fields[name] = field;
109
+ });
110
+ } else {
111
+ Object.entries(createdFields).forEach(([name, field]) => {
112
+ setFieldValue(field, name, defaultItemData);
113
+ fields[name] = field;
114
+ })
115
+ }
116
+
117
+ this.$items.set(defaultItemData, {
118
+ refId,
119
+ fields
120
+ });
121
+
122
+ this.$description.value.push(defaultItemData);
123
+ return this;
124
+
125
+ };
126
+
127
+ FieldCollection.prototype.remove = function(item) {
128
+ this.$description.value.removeItem(item);
129
+ this.$items?.delete(item);
130
+ return this;
131
+ };
132
+
133
+ FieldCollection.prototype.clear = function() {
134
+ this.$description.value.forEach((item) => {
135
+ this.$items.delete(item);
136
+ })
137
+ this.$description.value.clear();
138
+ };
139
+
140
+ FieldCollection.prototype.value = function(value) {
141
+ if(Validator.isObservable(value)) {
142
+ this.$description.value?.cleanup?.();
143
+ this.$description.value = value;
144
+ return this;
145
+ }
146
+ this.$description.value.set(value);
147
+ return this;
148
+ };
149
+
150
+ FieldCollection.prototype.getValue = function() {
151
+ return this.$description.value.map((item) => {
152
+ return typeof item?.val === 'function' ? item.val() : item;
153
+ });
154
+ };
155
+
156
+ FieldCollection.prototype.validate = function(allValues) {
157
+ const errors = [];
158
+ const rowsValues = [];
159
+
160
+ if(this.$items) {
161
+ this.$description.value.forEach((dataItem) => {
162
+ const row = this.$items.get(dataItem);
163
+ const fields = Object.entries(row.fields);
164
+ const itemValue = dataItem.val();
165
+ rowsValues.push(itemValue);
166
+
167
+ for(const [_, field] of fields) {
168
+ const fieldErrors = field.validate({ ...itemValue, $parent: allValues });
169
+ if(fieldErrors && fieldErrors.length) {
170
+ errors.push(fieldErrors);
171
+ }
172
+ }
173
+ });
174
+ }
175
+
176
+ if(this.$description.rules) {
177
+ for(const rule of this.$description.rules) {
178
+ const paramsResolved = resolveParams(rule, allValues);
179
+ console.log({ rule, paramsResolved });
180
+ const result = rule.fn(rowsValues, ...paramsResolved, allValues);
181
+
182
+ if (!result.valid) {
183
+ errors.push(rule.message || result.message);
184
+ }
185
+ }
186
+ }
187
+
188
+ return errors;
189
+ };
190
+
191
+ FieldCollection.prototype.min = function(minCount, message) {
192
+ if (typeof minCount !== 'number' || minCount < 0) {
193
+ throw new NativeDocumentError('min() expects a positive number');
194
+ }
195
+
196
+ this.addRule(
197
+ (values) => {
198
+ const isValid = values.length >= minCount;
199
+ return {
200
+ valid: isValid,
201
+ message: `Minimum ${minCount} item(s) required`
202
+ };
203
+ },
204
+ [],
205
+ message || `${this.$description.name} must have at least ${minCount} item(s)`
206
+ );
207
+
208
+ return this;
209
+ };
210
+
211
+ FieldCollection.prototype.max = function(maxCount, message) {
212
+ if (typeof maxCount !== 'number' || maxCount < 0) {
213
+ throw new NativeDocumentError('max() expects a positive number');
214
+ }
215
+
216
+ this.addRule(
217
+ (values) => {
218
+ const isValid = values.length <= maxCount;
219
+ return {
220
+ valid: isValid,
221
+ message: `Maximum ${maxCount} item(s) allowed`
222
+ };
223
+ },
224
+ [],
225
+ message || `${this.$description.name} must have at most ${maxCount} item(s)`
226
+ );
227
+
228
+ return this;
229
+ };
230
+
231
+ FieldCollection.prototype.required = function(message = '') {
232
+ this.addRule(Validation.required, [], message || this.name+' is required');
233
+ return this;
234
+ };
235
+
236
+ FieldCollection.prototype.reset = function() {
237
+ this.clear();
238
+ return this;
239
+ };
240
+
241
+ FieldCollection.prototype.layout = function(layout) {
242
+ if(typeof layout !== 'function') {
243
+ throw new NativeDocumentError(this.name+' FieldCollection Layout must be a function');
244
+ }
245
+ this.$description.layout = layout;
246
+ return this;
247
+ };
248
+
249
+
250
+ FieldCollection.prototype.toNdElement = function() {
251
+ if (!this.$description.layout) {
252
+ throw new NativeDocumentError(`Layout not defined for collection "${this.$description.name}"`);
253
+ }
254
+
255
+ return this.$description.layout({
256
+ collection: this,
257
+ data: this.$description.value,
258
+ Template: this.$description.template ? this.$description.template.bind(this) : null
259
+ });
260
+ };