@rolster/react-forms 19.0.0 → 19.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { createFormControlOptions, createFormGroupOptions, createFormArrayOptions } from '@rolster/forms/arguments';
2
- import { controlIsValid, hasError, someErrors, groupIsValid, controlsToValue, controlsAllChecked, controlsPartialChecked, arrayIsValid, groupAllChecked, reduceControlsToArray } from '@rolster/forms/helpers';
2
+ import { controlIsValid, hasError, someErrors, groupIsValid, controlsAllChecked, controlsPartialChecked, controlsToValue, arrayIsValid, groupAllChecked, reduceControlsToArray } from '@rolster/forms/helpers';
3
3
  import { v4 } from 'uuid';
4
4
  import { useRef, useState, useEffect, useCallback, useMemo } from 'react';
5
5
 
6
6
  class RolsterArrayControl {
7
7
  constructor(options) {
8
8
  this.uuid = options.uuid;
9
+ this.defaultValue = options.defaultValue;
9
10
  this.value = options.value;
10
- this.initialValue = options.initialValue;
11
11
  this.focused = !!options.focused;
12
12
  this.unfocused = !this.focused;
13
13
  this.touched = !!options.touched;
@@ -38,17 +38,20 @@ class RolsterArrayControl {
38
38
  touch() {
39
39
  this.untouched && this.refresh('touched', { touched: true });
40
40
  }
41
- setInitialValue(value) {
42
- if (value !== this.initialValue) {
41
+ setDefaultValue(value) {
42
+ if (value !== this.defaultValue) {
43
43
  const errors = this.validators
44
44
  ? controlIsValid({ value, validators: this.validators })
45
45
  : [];
46
- this.refresh('value', {
47
- dirty: false,
48
- errors,
49
- initialValue: value,
50
- value
51
- });
46
+ this.refresh('value', { errors, defaultValue: value, value });
47
+ }
48
+ }
49
+ setStartValue(value) {
50
+ if (value !== this.value) {
51
+ const errors = this.validators
52
+ ? controlIsValid({ value, validators: this.validators })
53
+ : [];
54
+ this.refresh('value', { errors, value });
52
55
  }
53
56
  }
54
57
  setValue(value) {
@@ -56,11 +59,7 @@ class RolsterArrayControl {
56
59
  const errors = this.validators
57
60
  ? controlIsValid({ value, validators: this.validators })
58
61
  : [];
59
- this.refresh('value', {
60
- dirty: true,
61
- errors,
62
- value
63
- });
62
+ this.refresh('value', { dirty: true, errors, value });
64
63
  }
65
64
  }
66
65
  setValidators(validators) {
@@ -81,7 +80,7 @@ class RolsterArrayControl {
81
80
  reset() {
82
81
  const errors = this.validators
83
82
  ? controlIsValid({
84
- value: this.initialValue,
83
+ value: this.defaultValue,
85
84
  validators: this.validators
86
85
  })
87
86
  : [];
@@ -89,7 +88,7 @@ class RolsterArrayControl {
89
88
  dirty: false,
90
89
  errors,
91
90
  touched: false,
92
- value: this.initialValue
91
+ value: this.defaultValue
93
92
  });
94
93
  }
95
94
  isValid(errors) {
@@ -113,7 +112,7 @@ function rolsterArrayControl(options, validators) {
113
112
  const formControl = createFormControlOptions(options, validators);
114
113
  return new ReactRolsterArrayControl({
115
114
  ...formControl,
116
- initialValue: formControl.value,
115
+ defaultValue: formControl.value,
117
116
  uuid: v4()
118
117
  });
119
118
  }
@@ -229,12 +228,12 @@ class ReactRolsterArrayGroup extends RolsterArrayGroup {
229
228
  super({
230
229
  ...options,
231
230
  errors,
232
- value: controlsToValue(controls),
233
231
  dirties: controlsAllChecked(controls, 'dirty'),
234
232
  dirty: controlsPartialChecked(controls, 'dirty'),
235
233
  touched: controlsPartialChecked(controls, 'touched'),
236
234
  toucheds: controlsAllChecked(controls, 'touched'),
237
- valid: errors.length === 0 && controlsAllChecked(controls, 'valid')
235
+ valid: errors.length === 0 && controlsAllChecked(controls, 'valid'),
236
+ value: controlsToValue(controls)
238
237
  });
239
238
  }
240
239
  }
@@ -252,7 +251,7 @@ function formArrayGroup(options, validators) {
252
251
  class RolsterArrayList extends RolsterArrayControl {
253
252
  constructor(options) {
254
253
  const { controls, valueToControls, validators } = options;
255
- const value = controls.map((controls) => controlsToValue(controls));
254
+ const value = controls.map(controlsToValue);
256
255
  const errors = validators ? controlIsValid({ value, validators }) : [];
257
256
  super({ ...options, errors, value });
258
257
  this.valueToControls = valueToControls;
@@ -266,20 +265,28 @@ class RolsterArrayList extends RolsterArrayControl {
266
265
  this._subscribe(reactControls);
267
266
  });
268
267
  }
269
- setInitialValue(value) {
268
+ setDefaultValue(value) {
269
+ this.refresh('list', {
270
+ controls: value.map(this.valueToControls),
271
+ defaultValue: value
272
+ });
273
+ }
274
+ setStartValue(value) {
270
275
  this.refresh('list', {
271
- controls: value.map((value) => this.valueToControls(value)),
272
- initialValue: value
276
+ controls: value.map(this.valueToControls)
273
277
  });
274
278
  }
275
279
  setValue(value) {
276
280
  this.refresh('list', {
277
- controls: value.map((value) => this.valueToControls(value))
281
+ controls: value.map(this.valueToControls),
282
+ dirty: true
278
283
  });
279
284
  }
280
285
  reset() {
281
286
  this.refresh('list', {
282
- controls: this.initialValue.map((value) => this.valueToControls(value))
287
+ controls: this.defaultValue.map(this.valueToControls),
288
+ dirty: false,
289
+ touched: false
283
290
  });
284
291
  }
285
292
  push(controls) {
@@ -318,7 +325,7 @@ function formArrayList(options) {
318
325
  return new RolsterArrayList({
319
326
  ...options,
320
327
  controls: value.map((value) => options.valueToControls(value)),
321
- initialValue: value,
328
+ defaultValue: value,
322
329
  uuid: v4()
323
330
  });
324
331
  }
@@ -352,20 +359,21 @@ function refactorForControls(action, state, groups) {
352
359
  }
353
360
  function useFormArray(options, validators) {
354
361
  const formArray = createFormArrayOptions(options, validators);
355
- const groups = formArray.groups || [];
356
- const value = useRef(groups);
362
+ const defaultValue = useRef(formArray.groups || []);
357
363
  const formGroups = useRef(new Map());
358
- const [state, setState] = useState({
359
- ...refactorForValid$1(groups, formArray.validators),
360
- controls: groups.map(({ controls }) => controls),
361
- dirty: false,
362
- dirties: false,
363
- disabled: false,
364
- groups,
365
- touched: false,
366
- toucheds: false,
367
- value: groups.map(({ controls }) => controlsToValue(controls)),
368
- validators: formArray.validators
364
+ const [state, setState] = useState(() => {
365
+ return {
366
+ ...refactorForValid$1(defaultValue.current, formArray.validators),
367
+ controls: defaultValue.current.map(({ controls }) => controls),
368
+ dirty: false,
369
+ dirties: false,
370
+ disabled: false,
371
+ groups: defaultValue.current,
372
+ touched: false,
373
+ toucheds: false,
374
+ value: defaultValue.current.map(({ controls }) => controlsToValue(controls)),
375
+ validators: formArray.validators
376
+ };
369
377
  });
370
378
  useEffect(() => {
371
379
  formGroups.current.clear();
@@ -376,8 +384,8 @@ function useFormArray(options, validators) {
376
384
  }, [state.groups]);
377
385
  const subscriber = useCallback((action, group) => {
378
386
  setState((state) => {
379
- const groups = state.groups.map((_group) => {
380
- return _group.uuid === group.uuid ? group : _group;
387
+ const groups = state.groups.map((currentGroup) => {
388
+ return currentGroup.uuid === group.uuid ? group : currentGroup;
381
389
  });
382
390
  return {
383
391
  ...state,
@@ -397,12 +405,12 @@ function useFormArray(options, validators) {
397
405
  ...refactorForGroups(groups, state.validators)
398
406
  }));
399
407
  }, []);
400
- const setInitialValue = useCallback((groups) => {
408
+ const setDefaultValue = useCallback((groups) => {
401
409
  setState((state) => ({
402
410
  ...state,
403
411
  ...refactorForGroups(groups, state.validators)
404
412
  }));
405
- value.current = groups;
413
+ defaultValue.current = groups;
406
414
  }, []);
407
415
  const push = useCallback((group) => {
408
416
  setState((state) => ({
@@ -432,12 +440,16 @@ function useFormArray(options, validators) {
432
440
  validators
433
441
  }));
434
442
  }, []);
435
- const hasError$1 = useCallback((key) => hasError(state.errors, key), [state.errors]);
436
- const someErrors$1 = useCallback((keys) => someErrors(state.errors, keys), [state.errors]);
443
+ const hasError$1 = useCallback((key) => {
444
+ return hasError(state.errors, key);
445
+ }, [state.errors]);
446
+ const someErrors$1 = useCallback((keys) => {
447
+ return someErrors(state.errors, keys);
448
+ }, [state.errors]);
437
449
  const reset = useCallback(() => {
438
450
  setState((state) => ({
439
451
  ...state,
440
- ...refactorForGroups(value.current, state.validators)
452
+ ...refactorForGroups(defaultValue.current, state.validators)
441
453
  }));
442
454
  }, []);
443
455
  return {
@@ -455,7 +467,7 @@ function useFormArray(options, validators) {
455
467
  push,
456
468
  remove,
457
469
  reset,
458
- setInitialValue,
470
+ setDefaultValue,
459
471
  setValidators,
460
472
  setValue,
461
473
  someErrors: someErrors$1,
@@ -470,15 +482,17 @@ function errorsInControl(value, validators) {
470
482
  }
471
483
  function useControl(options, validators) {
472
484
  const formControl = createFormControlOptions(options, validators);
473
- const initialValue = useRef(formControl.value);
474
- const [state, setState] = useState({
475
- dirty: false,
476
- disabled: false,
477
- errors: errorsInControl(formControl.value, formControl.validators),
478
- focused: false,
479
- touched: !!formControl.touched,
480
- value: formControl.value,
481
- validators: formControl.validators
485
+ const defaultValue = useRef(formControl.value);
486
+ const [state, setState] = useState(() => {
487
+ return {
488
+ dirty: false,
489
+ disabled: false,
490
+ errors: errorsInControl(formControl.value, formControl.validators),
491
+ focused: false,
492
+ touched: !!formControl.touched,
493
+ value: formControl.value,
494
+ validators: formControl.validators
495
+ };
482
496
  });
483
497
  const elementRef = useRef(null);
484
498
  const focus = useCallback(() => {
@@ -496,11 +510,17 @@ function useControl(options, validators) {
496
510
  const touch = useCallback(() => {
497
511
  setState((state) => ({ ...state, touched: true }));
498
512
  }, []);
499
- const setInitialValue = useCallback((value) => {
500
- initialValue.current = value;
513
+ const setDefaultValue = useCallback((value) => {
514
+ defaultValue.current = value;
515
+ setState((state) => ({
516
+ ...state,
517
+ errors: errorsInControl(value, state.validators),
518
+ value
519
+ }));
520
+ }, []);
521
+ const setStartValue = useCallback((value) => {
501
522
  setState((state) => ({
502
523
  ...state,
503
- dirty: true,
504
524
  errors: errorsInControl(value, state.validators),
505
525
  value
506
526
  }));
@@ -524,13 +544,17 @@ function useControl(options, validators) {
524
544
  setState((state) => ({
525
545
  ...state,
526
546
  dirty: false,
527
- errors: errorsInControl(initialValue.current, state.validators),
528
- value: initialValue.current,
547
+ errors: errorsInControl(defaultValue.current, state.validators),
548
+ value: defaultValue.current,
529
549
  touched: false
530
550
  }));
531
551
  }, []);
532
- const hasError$1 = useCallback((key) => hasError(state.errors, key), [state.errors]);
533
- const someErrors$1 = useCallback((keys) => someErrors(state.errors, keys), [state.errors]);
552
+ const hasError$1 = useCallback((key) => {
553
+ return hasError(state.errors, key);
554
+ }, [state.errors]);
555
+ const someErrors$1 = useCallback((keys) => {
556
+ return someErrors(state.errors, keys);
557
+ }, [state.errors]);
534
558
  const valid = state.errors.length === 0;
535
559
  return {
536
560
  ...state,
@@ -545,7 +569,8 @@ function useControl(options, validators) {
545
569
  invalid: !valid,
546
570
  pristine: !state.dirty,
547
571
  reset,
548
- setInitialValue,
572
+ setDefaultValue,
573
+ setStartValue,
549
574
  setValidators,
550
575
  setValue,
551
576
  someErrors: someErrors$1,
@@ -573,26 +598,53 @@ function refactorForValid(controls, validators) {
573
598
  valid: errors.length === 0 && controlsAllChecked(controls, 'valid')
574
599
  };
575
600
  }
601
+ function checkAllSuccess(status) {
602
+ return status.reduce((success, status) => success && status, true);
603
+ }
604
+ function checkPartialSuccess(status) {
605
+ return status.reduce((success, status) => success || status, false);
606
+ }
576
607
  function useFormGroup(options, validators) {
577
608
  const formGroup = createFormGroupOptions(options, validators);
578
- const firstEffects = useRef({
579
- dirty: true,
580
- disabledFocused: true,
581
- touched: true,
582
- value: true
609
+ const formInitialized = useRef({
610
+ dirty: false,
611
+ touched: false,
612
+ value: false,
613
+ visual: false
583
614
  });
584
- const [state, setState] = useState({
585
- ...refactorForValid(formGroup.controls, formGroup.validators),
586
- controls: formGroup.controls,
587
- dirties: controlsAllChecked(formGroup.controls, 'dirty'),
588
- dirty: controlsPartialChecked(formGroup.controls, 'dirty'),
589
- touched: controlsPartialChecked(formGroup.controls, 'touched'),
590
- toucheds: controlsAllChecked(formGroup.controls, 'touched'),
591
- value: controlsToValue(formGroup.controls),
592
- validators: formGroup.validators
615
+ const formGroupStatus = useMemo(() => {
616
+ const dirty = [];
617
+ const touched = [];
618
+ const value = [];
619
+ const visual = [];
620
+ Object.values(formGroup.controls).forEach((control) => {
621
+ dirty.push(control.dirty);
622
+ touched.push(control.touched);
623
+ value.push(control.value);
624
+ visual.push(control.disabled);
625
+ visual.push(control.focused);
626
+ });
627
+ return {
628
+ dirty,
629
+ touched,
630
+ value,
631
+ visual
632
+ };
633
+ }, [formGroup.controls]);
634
+ const [state, setState] = useState(() => {
635
+ return {
636
+ ...refactorForValid(formGroup.controls, formGroup.validators),
637
+ controls: formGroup.controls,
638
+ dirties: checkAllSuccess(formGroupStatus.dirty),
639
+ dirty: checkPartialSuccess(formGroupStatus.dirty),
640
+ touched: checkPartialSuccess(formGroupStatus.touched),
641
+ toucheds: checkAllSuccess(formGroupStatus.touched),
642
+ validators: formGroup.validators,
643
+ value: controlsToValue(formGroup.controls)
644
+ };
593
645
  });
594
646
  useEffect(() => {
595
- if (!firstEffects.current.value) {
647
+ if (formInitialized.current.value) {
596
648
  setState((state) => ({
597
649
  ...state,
598
650
  ...refactorForValid(formGroup.controls, state.validators),
@@ -601,49 +653,46 @@ function useFormGroup(options, validators) {
601
653
  }));
602
654
  }
603
655
  else {
604
- firstEffects.current.value = false;
656
+ formInitialized.current.value = true;
605
657
  }
606
- }, reduceControlsToArray(formGroup.controls, 'value'));
658
+ }, formGroupStatus.value);
607
659
  useEffect(() => {
608
- if (!firstEffects.current.disabledFocused) {
660
+ if (formInitialized.current.dirty) {
609
661
  setState((state) => ({
610
662
  ...state,
611
- controls: formGroup.controls
663
+ controls: formGroup.controls,
664
+ dirty: checkPartialSuccess(formGroupStatus.dirty),
665
+ dirties: checkAllSuccess(formGroupStatus.dirty)
612
666
  }));
613
667
  }
614
668
  else {
615
- firstEffects.current.disabledFocused = false;
669
+ formInitialized.current.dirty = true;
616
670
  }
617
- }, [
618
- ...reduceControlsToArray(formGroup.controls, 'disabled'),
619
- ...reduceControlsToArray(formGroup.controls, 'focused')
620
- ]);
671
+ }, formGroupStatus.dirty);
621
672
  useEffect(() => {
622
- if (!firstEffects.current.dirty) {
673
+ if (formInitialized.current.touched) {
623
674
  setState((state) => ({
624
675
  ...state,
625
676
  controls: formGroup.controls,
626
- dirty: controlsPartialChecked(formGroup.controls, 'dirty'),
627
- dirties: controlsAllChecked(formGroup.controls, 'dirty')
677
+ touched: checkPartialSuccess(formGroupStatus.touched),
678
+ toucheds: checkAllSuccess(formGroupStatus.touched)
628
679
  }));
629
680
  }
630
681
  else {
631
- firstEffects.current.dirty = false;
682
+ formInitialized.current.touched = true;
632
683
  }
633
- }, reduceControlsToArray(formGroup.controls, 'dirty'));
684
+ }, formGroupStatus.touched);
634
685
  useEffect(() => {
635
- if (!firstEffects.current.touched) {
686
+ if (formInitialized.current.visual) {
636
687
  setState((state) => ({
637
688
  ...state,
638
- controls: formGroup.controls,
639
- touched: controlsPartialChecked(formGroup.controls, 'touched'),
640
- toucheds: controlsAllChecked(formGroup.controls, 'touched')
689
+ controls: formGroup.controls
641
690
  }));
642
691
  }
643
692
  else {
644
- firstEffects.current.touched = false;
693
+ formInitialized.current.visual = true;
645
694
  }
646
- }, reduceControlsToArray(formGroup.controls, 'touched'));
695
+ }, formGroupStatus.visual);
647
696
  const setValidators = useCallback((validators) => {
648
697
  setState((state) => ({
649
698
  ...state,