@rolster/react-forms 19.4.11 → 19.4.13
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.
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
import { createFormControlOptions, formControlIsValid, hasError, someErrors, createFormGroupOptions, formGroupIsValid, controlsToValue, verifyAllTrueInControls, verifyAnyTrueInControls, createFormArrayOptions, formArrayIsValid, verifyAllTrueInGroups, reduceControlsToArray } from '@rolster/forms/helpers';
|
|
2
|
+
import { v4 } from 'uuid';
|
|
3
|
+
import { useRef, useState, useCallback, useEffect, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
class RolsterArrayControl {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.uuid = options.uuid;
|
|
8
|
+
this.defaultValue = options.defaultValue;
|
|
9
|
+
this.value = options.value;
|
|
10
|
+
this.focused = !!options.focused;
|
|
11
|
+
this.unfocused = !this.focused;
|
|
12
|
+
this.touched = !!options.touched;
|
|
13
|
+
this.untouched = !this.touched;
|
|
14
|
+
this.dirty = !!options.dirty;
|
|
15
|
+
this.pristine = !this.dirty;
|
|
16
|
+
this.disabled = !!options.disabled;
|
|
17
|
+
this.enabled = !this.disabled;
|
|
18
|
+
this.valid = this.isValid(options.errors);
|
|
19
|
+
this.invalid = !this.valid;
|
|
20
|
+
this.wrong = this.touched && this.invalid;
|
|
21
|
+
this.errors = options.errors;
|
|
22
|
+
this.error = this.errors[0];
|
|
23
|
+
this.validators = options.validators;
|
|
24
|
+
}
|
|
25
|
+
focus() {
|
|
26
|
+
this.unfocused && this.refresh('focused', { focused: true });
|
|
27
|
+
}
|
|
28
|
+
blur() {
|
|
29
|
+
this.focused && this.refresh('focused', { focused: false, touched: true });
|
|
30
|
+
}
|
|
31
|
+
disable() {
|
|
32
|
+
this.enabled && this.refresh('disabled', { disabled: true });
|
|
33
|
+
}
|
|
34
|
+
enable() {
|
|
35
|
+
this.disabled && this.refresh('disabled', { disabled: false });
|
|
36
|
+
}
|
|
37
|
+
touch() {
|
|
38
|
+
this.untouched && this.refresh('touched', { touched: true });
|
|
39
|
+
}
|
|
40
|
+
setDefaultValue(value) {
|
|
41
|
+
if (value !== this.defaultValue) {
|
|
42
|
+
const errors = this.validators
|
|
43
|
+
? formControlIsValid({ value, validators: this.validators })
|
|
44
|
+
: [];
|
|
45
|
+
this.refresh('value', { errors, defaultValue: value, value });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
setStartValue(value) {
|
|
49
|
+
if (value !== this.value) {
|
|
50
|
+
const errors = this.validators
|
|
51
|
+
? formControlIsValid({ value, validators: this.validators })
|
|
52
|
+
: [];
|
|
53
|
+
this.refresh('value', { errors, value });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
setValue(value) {
|
|
57
|
+
if (value !== this.value) {
|
|
58
|
+
const errors = this.validators
|
|
59
|
+
? formControlIsValid({ value, validators: this.validators })
|
|
60
|
+
: [];
|
|
61
|
+
this.refresh('value', { dirty: true, errors, value });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
setValidators(validators) {
|
|
65
|
+
const errors = validators
|
|
66
|
+
? formControlIsValid({ value: this.value, validators })
|
|
67
|
+
: [];
|
|
68
|
+
this.refresh('validators', { errors, validators });
|
|
69
|
+
}
|
|
70
|
+
subscribe(subscriber) {
|
|
71
|
+
this.subscriber = subscriber;
|
|
72
|
+
}
|
|
73
|
+
hasError(key) {
|
|
74
|
+
return hasError(this.errors, key);
|
|
75
|
+
}
|
|
76
|
+
someErrors(keys) {
|
|
77
|
+
return someErrors(this.errors, keys);
|
|
78
|
+
}
|
|
79
|
+
reset() {
|
|
80
|
+
const errors = this.validators
|
|
81
|
+
? formControlIsValid({
|
|
82
|
+
value: this.defaultValue,
|
|
83
|
+
validators: this.validators
|
|
84
|
+
})
|
|
85
|
+
: [];
|
|
86
|
+
this.refresh('reset', {
|
|
87
|
+
dirty: false,
|
|
88
|
+
errors,
|
|
89
|
+
touched: false,
|
|
90
|
+
value: this.defaultValue
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
isValid(errors) {
|
|
94
|
+
return errors.length === 0;
|
|
95
|
+
}
|
|
96
|
+
builder(options) {
|
|
97
|
+
return new RolsterArrayControl({ ...this, ...options });
|
|
98
|
+
}
|
|
99
|
+
refresh(action, options) {
|
|
100
|
+
this.subscriber?.(action, this.builder(options));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
class ReactRolsterArrayControl extends RolsterArrayControl {
|
|
104
|
+
constructor(options) {
|
|
105
|
+
const { value, validators } = options;
|
|
106
|
+
const errors = validators ? formControlIsValid({ value, validators }) : [];
|
|
107
|
+
super({ ...options, errors });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function rolsterArrayControl(options, validators) {
|
|
111
|
+
const formControl = createFormControlOptions(options, validators);
|
|
112
|
+
return new ReactRolsterArrayControl({
|
|
113
|
+
...formControl,
|
|
114
|
+
defaultValue: formControl.value,
|
|
115
|
+
uuid: v4()
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function reactArrayControl(options, validators) {
|
|
119
|
+
return rolsterArrayControl(options, validators);
|
|
120
|
+
}
|
|
121
|
+
function formArrayControl(options, validators) {
|
|
122
|
+
return rolsterArrayControl(options, validators);
|
|
123
|
+
}
|
|
124
|
+
function inputArrayControl(options, validators) {
|
|
125
|
+
return rolsterArrayControl(options, validators);
|
|
126
|
+
}
|
|
127
|
+
function areaArrayControl(options, validators) {
|
|
128
|
+
return rolsterArrayControl(options, validators);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function replaceControl(controls, control) {
|
|
132
|
+
return Object.entries(controls).reduce((controls, [key, _control]) => {
|
|
133
|
+
if (_control.uuid === control.uuid) {
|
|
134
|
+
controls[key] = control;
|
|
135
|
+
}
|
|
136
|
+
return controls;
|
|
137
|
+
}, { ...controls });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function refactorForValid$2(controls, validators) {
|
|
141
|
+
const errors = validators ? formGroupIsValid({ controls, validators }) : [];
|
|
142
|
+
return {
|
|
143
|
+
errors,
|
|
144
|
+
valid: errors.length === 0 && verifyAllTrueInControls(controls, 'valid')
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function refactorForControls$1(action, group, controls) {
|
|
148
|
+
switch (action) {
|
|
149
|
+
case 'focused':
|
|
150
|
+
case 'touched':
|
|
151
|
+
return {
|
|
152
|
+
touched: verifyAnyTrueInControls(controls, 'touched'),
|
|
153
|
+
toucheds: verifyAllTrueInControls(controls, 'touched')
|
|
154
|
+
};
|
|
155
|
+
case 'validators':
|
|
156
|
+
return refactorForValid$2(controls, group.validators);
|
|
157
|
+
case 'reset':
|
|
158
|
+
return {
|
|
159
|
+
...refactorForValid$2(controls, group.validators),
|
|
160
|
+
dirty: verifyAnyTrueInControls(controls, 'dirty'),
|
|
161
|
+
dirties: verifyAllTrueInControls(controls, 'dirty'),
|
|
162
|
+
touched: verifyAnyTrueInControls(controls, 'touched'),
|
|
163
|
+
toucheds: verifyAllTrueInControls(controls, 'touched'),
|
|
164
|
+
value: controlsToValue(controls)
|
|
165
|
+
};
|
|
166
|
+
case 'list':
|
|
167
|
+
case 'value':
|
|
168
|
+
return {
|
|
169
|
+
...refactorForValid$2(controls, group.validators),
|
|
170
|
+
dirty: verifyAnyTrueInControls(controls, 'dirty'),
|
|
171
|
+
dirties: verifyAllTrueInControls(controls, 'dirty'),
|
|
172
|
+
value: controlsToValue(controls)
|
|
173
|
+
};
|
|
174
|
+
default:
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
class RolsterArrayGroup {
|
|
179
|
+
constructor(options) {
|
|
180
|
+
this.uuid = options.uuid;
|
|
181
|
+
this._controls = options.controls;
|
|
182
|
+
this.value = options.value;
|
|
183
|
+
this.resource = options.resource;
|
|
184
|
+
this.dirty = !!options.dirty;
|
|
185
|
+
this.dirties = !!options.dirties;
|
|
186
|
+
this.pristine = !this.dirty;
|
|
187
|
+
this.pristines = !this.dirties;
|
|
188
|
+
this.touched = !!options.touched;
|
|
189
|
+
this.toucheds = !!options.toucheds;
|
|
190
|
+
this.untouched = !this.touched;
|
|
191
|
+
this.untoucheds = !this.toucheds;
|
|
192
|
+
this.valid = !!options.valid;
|
|
193
|
+
this.invalid = !this.valid;
|
|
194
|
+
this.wrong = this.touched && this.invalid;
|
|
195
|
+
this.errors = options.errors;
|
|
196
|
+
this.error = this.errors[0];
|
|
197
|
+
this.validators = options.validators;
|
|
198
|
+
this.subscriberControl = (action, control) => {
|
|
199
|
+
const controls = replaceControl(this._controls, control);
|
|
200
|
+
this._controls = controls;
|
|
201
|
+
this.refresh(action, {
|
|
202
|
+
...refactorForControls$1(action, this, controls),
|
|
203
|
+
controls
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
get controls() {
|
|
208
|
+
return this._controls;
|
|
209
|
+
}
|
|
210
|
+
subscribe(subscriber) {
|
|
211
|
+
this.subscriber = subscriber;
|
|
212
|
+
Object.values(this._controls).forEach((control) => {
|
|
213
|
+
control.subscribe(this.subscriberControl);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
setValidators(validators) {
|
|
217
|
+
this.refresh('validators', {
|
|
218
|
+
...refactorForValid$2(this._controls, validators),
|
|
219
|
+
validators
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
setResource(resource) {
|
|
223
|
+
this.refresh('resource', { resource });
|
|
224
|
+
}
|
|
225
|
+
reset() {
|
|
226
|
+
Object.values(this._controls).forEach((control) => {
|
|
227
|
+
control.reset();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
refresh(action, options) {
|
|
231
|
+
this.subscriber &&
|
|
232
|
+
this.subscriber(action, new RolsterArrayGroup({
|
|
233
|
+
...this,
|
|
234
|
+
...options,
|
|
235
|
+
controls: this._controls
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
class ReactRolsterArrayGroup extends RolsterArrayGroup {
|
|
240
|
+
constructor(options) {
|
|
241
|
+
const { controls, validators } = options;
|
|
242
|
+
const errors = validators ? formGroupIsValid({ controls, validators }) : [];
|
|
243
|
+
super({
|
|
244
|
+
...options,
|
|
245
|
+
errors,
|
|
246
|
+
dirties: verifyAllTrueInControls(controls, 'dirty'),
|
|
247
|
+
dirty: verifyAnyTrueInControls(controls, 'dirty'),
|
|
248
|
+
touched: verifyAnyTrueInControls(controls, 'touched'),
|
|
249
|
+
toucheds: verifyAllTrueInControls(controls, 'touched'),
|
|
250
|
+
valid: errors.length === 0 && verifyAllTrueInControls(controls, 'valid'),
|
|
251
|
+
value: controlsToValue(controls)
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function valueIsGroupOptions(options) {
|
|
256
|
+
return typeof options === 'object' && 'controls' in options;
|
|
257
|
+
}
|
|
258
|
+
function formArrayGroup(options, validators) {
|
|
259
|
+
const _uuid = valueIsGroupOptions(options) ? options.uuid || v4() : v4();
|
|
260
|
+
return new ReactRolsterArrayGroup({
|
|
261
|
+
...createFormGroupOptions(options, validators),
|
|
262
|
+
uuid: _uuid
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
class RolsterArrayList extends RolsterArrayControl {
|
|
267
|
+
constructor(options) {
|
|
268
|
+
const { controls, controlsUuid, valueToControls, valueToUuid, validators } = options;
|
|
269
|
+
const value = controls.map(controlsToValue);
|
|
270
|
+
const errors = validators ? formControlIsValid({ value, validators }) : [];
|
|
271
|
+
super({ ...options, errors, value });
|
|
272
|
+
this.valueToControls = valueToControls;
|
|
273
|
+
this.valueToUuid = valueToUuid;
|
|
274
|
+
this._controls = controls;
|
|
275
|
+
this.controlsUuid = controlsUuid ?? controls.map(() => v4());
|
|
276
|
+
this.valid =
|
|
277
|
+
errors.length === 0 &&
|
|
278
|
+
controls.reduce((valid, controls) => valid && verifyAllTrueInControls(controls, 'valid'), true);
|
|
279
|
+
this.invalid = !this.valid;
|
|
280
|
+
this.wrong = this.touched && this.invalid;
|
|
281
|
+
controls.forEach((reactControls) => {
|
|
282
|
+
this._subscribe(reactControls);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
get controls() {
|
|
286
|
+
return this._controls;
|
|
287
|
+
}
|
|
288
|
+
setDefaultValue(value) {
|
|
289
|
+
this.refresh('list', {
|
|
290
|
+
controls: value.map(this.valueToControls),
|
|
291
|
+
controlsUuid: this.generateControlsUuid(value),
|
|
292
|
+
defaultValue: value
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
setStartValue(value) {
|
|
296
|
+
this.refresh('list', {
|
|
297
|
+
controls: value.map(this.valueToControls),
|
|
298
|
+
controlsUuid: this.generateControlsUuid(value)
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
setValue(value) {
|
|
302
|
+
this.refresh('list', {
|
|
303
|
+
controls: value.map(this.valueToControls),
|
|
304
|
+
controlsUuid: this.generateControlsUuid(value),
|
|
305
|
+
dirty: true
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
reset() {
|
|
309
|
+
this.refresh('list', {
|
|
310
|
+
controls: this.defaultValue.map(this.valueToControls),
|
|
311
|
+
controlsUuid: this.generateControlsUuid(this.defaultValue),
|
|
312
|
+
dirty: false,
|
|
313
|
+
touched: false
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
push(controls) {
|
|
317
|
+
const _uuid = this.valueToUuid?.(controlsToValue(controls)) ?? v4();
|
|
318
|
+
this.refresh('list', {
|
|
319
|
+
controls: [...this._controls, controls],
|
|
320
|
+
controlsUuid: [...this.controlsUuid, _uuid]
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
remove(controls) {
|
|
324
|
+
const _controls = [];
|
|
325
|
+
const _controlsUuid = [];
|
|
326
|
+
this._controls.forEach((currentControls, index) => {
|
|
327
|
+
if (currentControls !== controls) {
|
|
328
|
+
_controls.push(currentControls);
|
|
329
|
+
_controlsUuid.push(this.controlsUuid[index]);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
this.refresh('list', {
|
|
333
|
+
controls: _controls,
|
|
334
|
+
controlsUuid: _controlsUuid
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
findControlsByUuid(uuid) {
|
|
338
|
+
const index = this.controlsUuid.indexOf(uuid);
|
|
339
|
+
return index >= 0 ? this._controls[index] : undefined;
|
|
340
|
+
}
|
|
341
|
+
builder(options) {
|
|
342
|
+
return new RolsterArrayList({
|
|
343
|
+
...this,
|
|
344
|
+
...options,
|
|
345
|
+
valueToControls: this.valueToControls,
|
|
346
|
+
valueToUuid: this.valueToUuid
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
refresh(action, options) {
|
|
350
|
+
super.refresh(action, options);
|
|
351
|
+
}
|
|
352
|
+
generateControlsUuid(values) {
|
|
353
|
+
return values.map((value) => this.valueToUuid?.(value) ?? v4());
|
|
354
|
+
}
|
|
355
|
+
_subscribe(controls) {
|
|
356
|
+
Object.values(controls).forEach((control) => {
|
|
357
|
+
control.subscribe((action, _control) => {
|
|
358
|
+
const _controls = this._controls.map((_controls) => {
|
|
359
|
+
const currentControl = Object.values(_controls).some((currentControl) => currentControl.uuid === _control.uuid);
|
|
360
|
+
return currentControl
|
|
361
|
+
? replaceControl(_controls, _control)
|
|
362
|
+
: _controls;
|
|
363
|
+
});
|
|
364
|
+
this._controls = _controls;
|
|
365
|
+
this.refresh(action, { controls: _controls });
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function formArrayList(options) {
|
|
371
|
+
const { valueToControls, valueToUuid } = options;
|
|
372
|
+
const value = options?.value || [];
|
|
373
|
+
return new RolsterArrayList({
|
|
374
|
+
...options,
|
|
375
|
+
controls: value.map(valueToControls),
|
|
376
|
+
controlsUuid: value.map((v) => valueToUuid?.(v) ?? v4()),
|
|
377
|
+
defaultValue: value,
|
|
378
|
+
uuid: v4()
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function refactorForValid$1(groups, validators) {
|
|
383
|
+
const errors = validators ? formArrayIsValid({ groups, validators }) : [];
|
|
384
|
+
return {
|
|
385
|
+
errors,
|
|
386
|
+
valid: errors.length === 0 && verifyAllTrueInGroups(groups, 'valid')
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function refactorForGroups(groups, validators) {
|
|
390
|
+
return {
|
|
391
|
+
...refactorForValid$1(groups, validators),
|
|
392
|
+
groups,
|
|
393
|
+
controls: groups.map(({ controls }) => controls),
|
|
394
|
+
value: groups.map(({ controls }) => controlsToValue(controls))
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
function refactorForControls(action, state, groups) {
|
|
398
|
+
switch (action) {
|
|
399
|
+
case 'validators':
|
|
400
|
+
return refactorForValid$1(groups, state.validators);
|
|
401
|
+
case 'reset':
|
|
402
|
+
case 'list':
|
|
403
|
+
case 'value':
|
|
404
|
+
return refactorForGroups(groups, state.validators);
|
|
405
|
+
default:
|
|
406
|
+
return { groups };
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function useFormArray(options, validators) {
|
|
410
|
+
const formArray = createFormArrayOptions(options, validators);
|
|
411
|
+
const refArrayValue = useRef(formArray.groups || []);
|
|
412
|
+
const refArrayGroups = useRef(new Map());
|
|
413
|
+
const [state, setState] = useState(() => {
|
|
414
|
+
return {
|
|
415
|
+
...refactorForValid$1(refArrayValue.current, formArray.validators),
|
|
416
|
+
controls: refArrayValue.current.map(({ controls }) => controls),
|
|
417
|
+
dirty: false,
|
|
418
|
+
dirties: false,
|
|
419
|
+
disabled: false,
|
|
420
|
+
groups: refArrayValue.current,
|
|
421
|
+
touched: false,
|
|
422
|
+
toucheds: false,
|
|
423
|
+
value: refArrayValue.current.map(({ controls }) => controlsToValue(controls)),
|
|
424
|
+
validators: formArray.validators
|
|
425
|
+
};
|
|
426
|
+
});
|
|
427
|
+
const subscriber = useCallback((action, group) => {
|
|
428
|
+
setState((state) => {
|
|
429
|
+
const groups = state.groups.map((currentGroup) => {
|
|
430
|
+
return currentGroup.uuid === group.uuid ? group : currentGroup;
|
|
431
|
+
});
|
|
432
|
+
return {
|
|
433
|
+
...state,
|
|
434
|
+
...refactorForControls(action, state, groups)
|
|
435
|
+
};
|
|
436
|
+
});
|
|
437
|
+
}, []);
|
|
438
|
+
useEffect(() => {
|
|
439
|
+
const previousGroups = refArrayGroups.current;
|
|
440
|
+
const currentGroups = new Map();
|
|
441
|
+
state.groups.forEach((group) => {
|
|
442
|
+
currentGroups.set(group.uuid, group);
|
|
443
|
+
if (previousGroups.get(group.uuid) !== group) {
|
|
444
|
+
group.subscribe(subscriber);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
refArrayGroups.current = currentGroups;
|
|
448
|
+
}, [state.groups]);
|
|
449
|
+
const disable = useCallback(() => {
|
|
450
|
+
setState((state) => ({ ...state, disabled: true }));
|
|
451
|
+
}, []);
|
|
452
|
+
const enable = useCallback(() => {
|
|
453
|
+
setState((state) => ({ ...state, disabled: false }));
|
|
454
|
+
}, []);
|
|
455
|
+
const setValue = useCallback((groups) => {
|
|
456
|
+
setState((state) => ({
|
|
457
|
+
...state,
|
|
458
|
+
...refactorForGroups(groups, state.validators)
|
|
459
|
+
}));
|
|
460
|
+
}, []);
|
|
461
|
+
const setStartValue = useCallback((groups) => {
|
|
462
|
+
setState((state) => ({
|
|
463
|
+
...state,
|
|
464
|
+
...refactorForGroups(groups, state.validators)
|
|
465
|
+
}));
|
|
466
|
+
}, []);
|
|
467
|
+
const setDefaultValue = useCallback((groups) => {
|
|
468
|
+
setState((state) => ({
|
|
469
|
+
...state,
|
|
470
|
+
...refactorForGroups(groups, state.validators)
|
|
471
|
+
}));
|
|
472
|
+
refArrayValue.current = groups;
|
|
473
|
+
}, []);
|
|
474
|
+
const push = useCallback((group) => {
|
|
475
|
+
refArrayGroups.current.set(group.uuid, group);
|
|
476
|
+
group.subscribe(subscriber);
|
|
477
|
+
setState((state) => ({
|
|
478
|
+
...state,
|
|
479
|
+
...refactorForGroups([...state.groups, group], state.validators)
|
|
480
|
+
}));
|
|
481
|
+
}, []);
|
|
482
|
+
const merge = useCallback((groups) => {
|
|
483
|
+
groups.forEach((group) => {
|
|
484
|
+
group.subscribe(subscriber);
|
|
485
|
+
refArrayGroups.current.set(group.uuid, group);
|
|
486
|
+
});
|
|
487
|
+
setState((state) => ({
|
|
488
|
+
...state,
|
|
489
|
+
...refactorForGroups([...state.groups, ...groups], state.validators)
|
|
490
|
+
}));
|
|
491
|
+
}, []);
|
|
492
|
+
const remove = useCallback(({ uuid }) => {
|
|
493
|
+
refArrayGroups.current.delete(uuid);
|
|
494
|
+
setState((state) => ({
|
|
495
|
+
...state,
|
|
496
|
+
...refactorForGroups(state.groups.filter((group) => group.uuid !== uuid), state.validators)
|
|
497
|
+
}));
|
|
498
|
+
}, []);
|
|
499
|
+
const findByUuid = useCallback((uuid) => {
|
|
500
|
+
return refArrayGroups.current.get(uuid);
|
|
501
|
+
}, []);
|
|
502
|
+
const setValidators = useCallback((validators) => {
|
|
503
|
+
setState((state) => ({
|
|
504
|
+
...state,
|
|
505
|
+
...refactorForValid$1(state.groups, validators),
|
|
506
|
+
validators
|
|
507
|
+
}));
|
|
508
|
+
}, []);
|
|
509
|
+
const formArrayHasError = useCallback((key) => {
|
|
510
|
+
return hasError(state.errors, key);
|
|
511
|
+
}, [state.errors]);
|
|
512
|
+
const formArraySomeErrors = useCallback((keys) => {
|
|
513
|
+
return someErrors(state.errors, keys);
|
|
514
|
+
}, [state.errors]);
|
|
515
|
+
const reset = useCallback(() => {
|
|
516
|
+
refArrayValue.current.forEach((group) => group.reset());
|
|
517
|
+
refArrayGroups.current = new Map();
|
|
518
|
+
setState((state) => ({
|
|
519
|
+
...state,
|
|
520
|
+
...refactorForGroups(refArrayValue.current, state.validators)
|
|
521
|
+
}));
|
|
522
|
+
}, []);
|
|
523
|
+
return {
|
|
524
|
+
...state,
|
|
525
|
+
disable,
|
|
526
|
+
enable,
|
|
527
|
+
enabled: !state.disabled,
|
|
528
|
+
error: state.errors[0],
|
|
529
|
+
findByUuid,
|
|
530
|
+
hasError: formArrayHasError,
|
|
531
|
+
invalid: !state.valid,
|
|
532
|
+
merge,
|
|
533
|
+
pristine: !state.dirty,
|
|
534
|
+
pristines: !state.dirties,
|
|
535
|
+
push,
|
|
536
|
+
remove,
|
|
537
|
+
reset,
|
|
538
|
+
setDefaultValue,
|
|
539
|
+
setStartValue,
|
|
540
|
+
setValidators,
|
|
541
|
+
setValue,
|
|
542
|
+
someErrors: formArraySomeErrors,
|
|
543
|
+
untouched: !state.touched,
|
|
544
|
+
untoucheds: !state.toucheds,
|
|
545
|
+
wrong: state.touched && !state.valid
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function errorsInControl(value, validators) {
|
|
550
|
+
return validators ? formControlIsValid({ value, validators }) : [];
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function useControl(options, validators) {
|
|
554
|
+
const formControl = createFormControlOptions(options, validators);
|
|
555
|
+
const defaultValue = useRef(formControl.value);
|
|
556
|
+
const [state, setState] = useState(() => {
|
|
557
|
+
return {
|
|
558
|
+
dirty: false,
|
|
559
|
+
disabled: false,
|
|
560
|
+
errors: errorsInControl(formControl.value, formControl.validators),
|
|
561
|
+
focused: false,
|
|
562
|
+
touched: !!formControl.touched,
|
|
563
|
+
value: formControl.value,
|
|
564
|
+
validators: formControl.validators
|
|
565
|
+
};
|
|
566
|
+
});
|
|
567
|
+
const elementRef = useRef(null);
|
|
568
|
+
const focus = useCallback(() => {
|
|
569
|
+
setState((state) => ({ ...state, focused: true }));
|
|
570
|
+
}, []);
|
|
571
|
+
const blur = useCallback(() => {
|
|
572
|
+
setState((state) => ({ ...state, focused: false, touched: true }));
|
|
573
|
+
}, []);
|
|
574
|
+
const disable = useCallback(() => {
|
|
575
|
+
setState((state) => ({ ...state, disabled: true }));
|
|
576
|
+
}, []);
|
|
577
|
+
const enable = useCallback(() => {
|
|
578
|
+
setState((state) => ({ ...state, disabled: false }));
|
|
579
|
+
}, []);
|
|
580
|
+
const touch = useCallback(() => {
|
|
581
|
+
setState((state) => ({ ...state, touched: true }));
|
|
582
|
+
}, []);
|
|
583
|
+
const setDefaultValue = useCallback((value) => {
|
|
584
|
+
defaultValue.current = value;
|
|
585
|
+
setState((state) => ({
|
|
586
|
+
...state,
|
|
587
|
+
errors: errorsInControl(value, state.validators),
|
|
588
|
+
value
|
|
589
|
+
}));
|
|
590
|
+
}, []);
|
|
591
|
+
const setStartValue = useCallback((value) => {
|
|
592
|
+
setState((state) => ({
|
|
593
|
+
...state,
|
|
594
|
+
errors: errorsInControl(value, state.validators),
|
|
595
|
+
value
|
|
596
|
+
}));
|
|
597
|
+
}, []);
|
|
598
|
+
const setValue = useCallback((value) => {
|
|
599
|
+
setState((state) => ({
|
|
600
|
+
...state,
|
|
601
|
+
dirty: true,
|
|
602
|
+
errors: errorsInControl(value, state.validators),
|
|
603
|
+
value
|
|
604
|
+
}));
|
|
605
|
+
}, []);
|
|
606
|
+
const setValidators = useCallback((validators) => {
|
|
607
|
+
setState((state) => ({
|
|
608
|
+
...state,
|
|
609
|
+
errors: errorsInControl(state.value, validators),
|
|
610
|
+
validators
|
|
611
|
+
}));
|
|
612
|
+
}, []);
|
|
613
|
+
const reset = useCallback(() => {
|
|
614
|
+
setState((state) => ({
|
|
615
|
+
...state,
|
|
616
|
+
dirty: false,
|
|
617
|
+
errors: errorsInControl(defaultValue.current, state.validators),
|
|
618
|
+
value: defaultValue.current,
|
|
619
|
+
touched: false
|
|
620
|
+
}));
|
|
621
|
+
}, []);
|
|
622
|
+
const formControlHasError = useCallback((key) => {
|
|
623
|
+
return hasError(state.errors, key);
|
|
624
|
+
}, [state.errors]);
|
|
625
|
+
const formControlSomeErrors = useCallback((keys) => {
|
|
626
|
+
return someErrors(state.errors, keys);
|
|
627
|
+
}, [state.errors]);
|
|
628
|
+
const valid = state.errors.length === 0;
|
|
629
|
+
return {
|
|
630
|
+
...state,
|
|
631
|
+
blur,
|
|
632
|
+
disable,
|
|
633
|
+
elementRef,
|
|
634
|
+
enable,
|
|
635
|
+
enabled: !state.disabled,
|
|
636
|
+
error: state.errors[0],
|
|
637
|
+
focus,
|
|
638
|
+
hasError: formControlHasError,
|
|
639
|
+
invalid: !valid,
|
|
640
|
+
pristine: !state.dirty,
|
|
641
|
+
reset,
|
|
642
|
+
setDefaultValue,
|
|
643
|
+
setStartValue,
|
|
644
|
+
setValidators,
|
|
645
|
+
setValue,
|
|
646
|
+
someErrors: formControlSomeErrors,
|
|
647
|
+
touch,
|
|
648
|
+
unfocused: !state.focused,
|
|
649
|
+
untouched: !state.touched,
|
|
650
|
+
valid,
|
|
651
|
+
wrong: state.touched && !valid
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function useReactControl(options, validators) {
|
|
655
|
+
return useControl(options, validators);
|
|
656
|
+
}
|
|
657
|
+
function useFormControl(options, validators) {
|
|
658
|
+
return useControl(options, validators);
|
|
659
|
+
}
|
|
660
|
+
function useInputControl(options, validators) {
|
|
661
|
+
return useControl(options, validators);
|
|
662
|
+
}
|
|
663
|
+
function useAreaControl(options, validators) {
|
|
664
|
+
return useControl(options, validators);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function refactorForValid(controls, validators) {
|
|
668
|
+
const errors = validators ? formGroupIsValid({ controls, validators }) : [];
|
|
669
|
+
return {
|
|
670
|
+
errors,
|
|
671
|
+
valid: errors.length === 0 && verifyAllTrueInControls(controls, 'valid')
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function checkAllSuccess(status) {
|
|
675
|
+
return status.every((value) => value);
|
|
676
|
+
}
|
|
677
|
+
function checkPartialSuccess(status) {
|
|
678
|
+
return status.some((value) => value);
|
|
679
|
+
}
|
|
680
|
+
function arraysShallowEqual(a, b) {
|
|
681
|
+
if (a === b) {
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
if (a.length !== b.length) {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
for (let i = 0; i < a.length; i++) {
|
|
688
|
+
if (a[i] !== b[i]) {
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
function useFormGroup(options, validators) {
|
|
695
|
+
const formGroup = createFormGroupOptions(options, validators);
|
|
696
|
+
const refControls = useRef(formGroup.controls);
|
|
697
|
+
refControls.current = formGroup.controls;
|
|
698
|
+
const formGroupStatus = useMemo(() => {
|
|
699
|
+
const dirty = [];
|
|
700
|
+
const disabled = [];
|
|
701
|
+
const focused = [];
|
|
702
|
+
const touched = [];
|
|
703
|
+
const value = [];
|
|
704
|
+
Object.values(formGroup.controls).forEach((control) => {
|
|
705
|
+
dirty.push(control.dirty);
|
|
706
|
+
disabled.push(control.disabled);
|
|
707
|
+
focused.push(control.focused);
|
|
708
|
+
touched.push(control.touched);
|
|
709
|
+
value.push(control.value);
|
|
710
|
+
});
|
|
711
|
+
return {
|
|
712
|
+
dirty,
|
|
713
|
+
disabled,
|
|
714
|
+
focused,
|
|
715
|
+
touched,
|
|
716
|
+
value
|
|
717
|
+
};
|
|
718
|
+
}, [formGroup.controls]);
|
|
719
|
+
const [state, setState] = useState(() => {
|
|
720
|
+
return {
|
|
721
|
+
...refactorForValid(formGroup.controls, formGroup.validators),
|
|
722
|
+
dirties: checkAllSuccess(formGroupStatus.dirty),
|
|
723
|
+
dirty: checkPartialSuccess(formGroupStatus.dirty),
|
|
724
|
+
touched: checkPartialSuccess(formGroupStatus.touched),
|
|
725
|
+
toucheds: checkAllSuccess(formGroupStatus.touched),
|
|
726
|
+
validators: formGroup.validators,
|
|
727
|
+
value: controlsToValue(formGroup.controls)
|
|
728
|
+
};
|
|
729
|
+
});
|
|
730
|
+
const refPrevFormGroupStatus = useRef(null);
|
|
731
|
+
useEffect(() => {
|
|
732
|
+
const formGroupPrev = refPrevFormGroupStatus.current;
|
|
733
|
+
refPrevFormGroupStatus.current = formGroupStatus;
|
|
734
|
+
if (!formGroupPrev) {
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const valueChanged = !arraysShallowEqual(formGroupPrev.value, formGroupStatus.value);
|
|
738
|
+
const dirtyChanged = !arraysShallowEqual(formGroupPrev.dirty, formGroupStatus.dirty);
|
|
739
|
+
const touchedChanged = !arraysShallowEqual(formGroupPrev.touched, formGroupStatus.touched);
|
|
740
|
+
const disabledChanged = !arraysShallowEqual(formGroupPrev.disabled, formGroupStatus.disabled);
|
|
741
|
+
const focusedChanged = !arraysShallowEqual(formGroupPrev.focused, formGroupStatus.focused);
|
|
742
|
+
if (!valueChanged &&
|
|
743
|
+
!dirtyChanged &&
|
|
744
|
+
!touchedChanged &&
|
|
745
|
+
!disabledChanged &&
|
|
746
|
+
!focusedChanged) {
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
setState((state) => {
|
|
750
|
+
const next = { ...state };
|
|
751
|
+
if (valueChanged) {
|
|
752
|
+
const validResult = refactorForValid(refControls.current, state.validators);
|
|
753
|
+
next.errors = validResult.errors;
|
|
754
|
+
next.valid = validResult.valid;
|
|
755
|
+
next.value = controlsToValue(refControls.current);
|
|
756
|
+
}
|
|
757
|
+
if (dirtyChanged) {
|
|
758
|
+
next.dirty = checkPartialSuccess(formGroupStatus.dirty);
|
|
759
|
+
next.dirties = checkAllSuccess(formGroupStatus.dirty);
|
|
760
|
+
}
|
|
761
|
+
if (touchedChanged) {
|
|
762
|
+
next.touched = checkPartialSuccess(formGroupStatus.touched);
|
|
763
|
+
next.toucheds = checkAllSuccess(formGroupStatus.touched);
|
|
764
|
+
}
|
|
765
|
+
return next;
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
const setValidators = useCallback((validators) => {
|
|
769
|
+
setState((state) => ({
|
|
770
|
+
...state,
|
|
771
|
+
...refactorForValid(refControls.current, validators),
|
|
772
|
+
validators
|
|
773
|
+
}));
|
|
774
|
+
}, []);
|
|
775
|
+
const setValue = useCallback((value) => {
|
|
776
|
+
Object.entries(value).forEach(([key, valueControl]) => {
|
|
777
|
+
const formControl = refControls.current[key];
|
|
778
|
+
formControl?.setValue(valueControl);
|
|
779
|
+
});
|
|
780
|
+
}, []);
|
|
781
|
+
const reset = useCallback(() => {
|
|
782
|
+
Object.values(refControls.current).forEach((control) => {
|
|
783
|
+
control.reset();
|
|
784
|
+
});
|
|
785
|
+
}, []);
|
|
786
|
+
return {
|
|
787
|
+
...state,
|
|
788
|
+
controls: formGroup.controls,
|
|
789
|
+
error: state.errors[0],
|
|
790
|
+
invalid: !state.valid,
|
|
791
|
+
pristine: !state.dirty,
|
|
792
|
+
pristines: !state.dirties,
|
|
793
|
+
reset,
|
|
794
|
+
setValidators,
|
|
795
|
+
setValue,
|
|
796
|
+
untouched: !state.touched,
|
|
797
|
+
untoucheds: !state.toucheds,
|
|
798
|
+
wrong: state.touched && !state.valid
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function useInputRefControl(options) {
|
|
803
|
+
const formRef = useInputControl(options);
|
|
804
|
+
const setValueRef = useRef(options.setValue);
|
|
805
|
+
setValueRef.current = options.setValue;
|
|
806
|
+
useEffect(() => {
|
|
807
|
+
const element = formRef.elementRef?.current;
|
|
808
|
+
if (!element) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const handleFocus = () => {
|
|
812
|
+
formRef.focus();
|
|
813
|
+
};
|
|
814
|
+
const handleBlur = () => {
|
|
815
|
+
formRef.blur();
|
|
816
|
+
};
|
|
817
|
+
const handleChange = (event) => {
|
|
818
|
+
const target = event.target;
|
|
819
|
+
setValueRef.current(formRef, target.value);
|
|
820
|
+
};
|
|
821
|
+
element.addEventListener('focus', handleFocus);
|
|
822
|
+
element.addEventListener('blur', handleBlur);
|
|
823
|
+
element.addEventListener('change', handleChange);
|
|
824
|
+
return () => {
|
|
825
|
+
element.removeEventListener('focus', handleFocus);
|
|
826
|
+
element.removeEventListener('blur', handleBlur);
|
|
827
|
+
element.removeEventListener('change', handleChange);
|
|
828
|
+
};
|
|
829
|
+
}, []);
|
|
830
|
+
return formRef;
|
|
831
|
+
}
|
|
832
|
+
function useTextRefControl(options, validators) {
|
|
833
|
+
return useInputRefControl({
|
|
834
|
+
...createFormControlOptions(options, validators),
|
|
835
|
+
setValue: (control, value) => {
|
|
836
|
+
control.setValue(value);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
function useNumberRefControl(options, validators) {
|
|
841
|
+
return useInputRefControl({
|
|
842
|
+
...createFormControlOptions(options, validators),
|
|
843
|
+
setValue: (control, value) => {
|
|
844
|
+
control.setValue(+value);
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function reduceControlsToValues(controls) {
|
|
850
|
+
return reduceControlsToArray(controls, 'value');
|
|
851
|
+
}
|
|
852
|
+
function reduceGroupToValues(group) {
|
|
853
|
+
return reduceControlsToValues(group.controls);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function useFormArrayGroupSelect({ formArray }) {
|
|
857
|
+
const [formSelect, setFormGroup] = useState();
|
|
858
|
+
const formGroup = useMemo(() => {
|
|
859
|
+
return (formSelect &&
|
|
860
|
+
formArray.groups.find(({ uuid }) => formSelect.uuid === uuid));
|
|
861
|
+
}, [formArray.value, formSelect]);
|
|
862
|
+
return { formGroup, setFormGroup };
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
export { areaArrayControl, formArrayControl, formArrayGroup, formArrayList, inputArrayControl, reactArrayControl, reduceControlsToValues, reduceGroupToValues, useAreaControl, useFormArray, useFormArrayGroupSelect, useFormControl, useFormGroup, useInputControl, useNumberRefControl, useReactControl, useTextRefControl };
|
|
866
|
+
//# sourceMappingURL=index.mjs.map
|