@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