@rolster/react-forms 19.0.0 → 19.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }
@@ -355,17 +362,19 @@ function useFormArray(options, validators) {
355
362
  const groups = formArray.groups || [];
356
363
  const value = useRef(groups);
357
364
  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
365
+ const [state, setState] = useState(() => {
366
+ return {
367
+ ...refactorForValid$1(groups, formArray.validators),
368
+ controls: groups.map(({ controls }) => controls),
369
+ dirty: false,
370
+ dirties: false,
371
+ disabled: false,
372
+ groups,
373
+ touched: false,
374
+ toucheds: false,
375
+ value: groups.map(({ controls }) => controlsToValue(controls)),
376
+ validators: formArray.validators
377
+ };
369
378
  });
370
379
  useEffect(() => {
371
380
  formGroups.current.clear();
@@ -376,8 +385,8 @@ function useFormArray(options, validators) {
376
385
  }, [state.groups]);
377
386
  const subscriber = useCallback((action, group) => {
378
387
  setState((state) => {
379
- const groups = state.groups.map((_group) => {
380
- return _group.uuid === group.uuid ? group : _group;
388
+ const groups = state.groups.map((currentGroup) => {
389
+ return currentGroup.uuid === group.uuid ? group : currentGroup;
381
390
  });
382
391
  return {
383
392
  ...state,
@@ -432,8 +441,12 @@ function useFormArray(options, validators) {
432
441
  validators
433
442
  }));
434
443
  }, []);
435
- const hasError$1 = useCallback((key) => hasError(state.errors, key), [state.errors]);
436
- const someErrors$1 = useCallback((keys) => someErrors(state.errors, keys), [state.errors]);
444
+ const hasError$1 = useCallback((key) => {
445
+ return hasError(state.errors, key);
446
+ }, [state.errors]);
447
+ const someErrors$1 = useCallback((keys) => {
448
+ return someErrors(state.errors, keys);
449
+ }, [state.errors]);
437
450
  const reset = useCallback(() => {
438
451
  setState((state) => ({
439
452
  ...state,
@@ -470,15 +483,17 @@ function errorsInControl(value, validators) {
470
483
  }
471
484
  function useControl(options, validators) {
472
485
  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
486
+ const defaultValue = useRef(formControl.value);
487
+ const [state, setState] = useState(() => {
488
+ return {
489
+ dirty: false,
490
+ disabled: false,
491
+ errors: errorsInControl(formControl.value, formControl.validators),
492
+ focused: false,
493
+ touched: !!formControl.touched,
494
+ value: formControl.value,
495
+ validators: formControl.validators
496
+ };
482
497
  });
483
498
  const elementRef = useRef(null);
484
499
  const focus = useCallback(() => {
@@ -496,11 +511,17 @@ function useControl(options, validators) {
496
511
  const touch = useCallback(() => {
497
512
  setState((state) => ({ ...state, touched: true }));
498
513
  }, []);
499
- const setInitialValue = useCallback((value) => {
500
- initialValue.current = value;
514
+ const setDefaultValue = useCallback((value) => {
515
+ defaultValue.current = value;
516
+ setState((state) => ({
517
+ ...state,
518
+ errors: errorsInControl(value, state.validators),
519
+ value
520
+ }));
521
+ }, []);
522
+ const setStartValue = useCallback((value) => {
501
523
  setState((state) => ({
502
524
  ...state,
503
- dirty: true,
504
525
  errors: errorsInControl(value, state.validators),
505
526
  value
506
527
  }));
@@ -524,13 +545,17 @@ function useControl(options, validators) {
524
545
  setState((state) => ({
525
546
  ...state,
526
547
  dirty: false,
527
- errors: errorsInControl(initialValue.current, state.validators),
528
- value: initialValue.current,
548
+ errors: errorsInControl(defaultValue.current, state.validators),
549
+ value: defaultValue.current,
529
550
  touched: false
530
551
  }));
531
552
  }, []);
532
- const hasError$1 = useCallback((key) => hasError(state.errors, key), [state.errors]);
533
- const someErrors$1 = useCallback((keys) => someErrors(state.errors, keys), [state.errors]);
553
+ const hasError$1 = useCallback((key) => {
554
+ return hasError(state.errors, key);
555
+ }, [state.errors]);
556
+ const someErrors$1 = useCallback((keys) => {
557
+ return someErrors(state.errors, keys);
558
+ }, [state.errors]);
534
559
  const valid = state.errors.length === 0;
535
560
  return {
536
561
  ...state,
@@ -545,7 +570,8 @@ function useControl(options, validators) {
545
570
  invalid: !valid,
546
571
  pristine: !state.dirty,
547
572
  reset,
548
- setInitialValue,
573
+ setDefaultValue,
574
+ setStartValue,
549
575
  setValidators,
550
576
  setValue,
551
577
  someErrors: someErrors$1,
@@ -573,26 +599,53 @@ function refactorForValid(controls, validators) {
573
599
  valid: errors.length === 0 && controlsAllChecked(controls, 'valid')
574
600
  };
575
601
  }
602
+ function checkAllSuccess(status) {
603
+ return status.reduce((success, status) => success && status, true);
604
+ }
605
+ function checkPartialSuccess(status) {
606
+ return status.reduce((success, status) => success || status, false);
607
+ }
576
608
  function useFormGroup(options, validators) {
577
609
  const formGroup = createFormGroupOptions(options, validators);
578
- const firstEffects = useRef({
579
- dirty: true,
580
- disabledFocused: true,
581
- touched: true,
582
- value: true
610
+ const formInitialized = useRef({
611
+ dirty: false,
612
+ touched: false,
613
+ value: false,
614
+ visual: false
583
615
  });
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
616
+ const formGroupStatus = useMemo(() => {
617
+ const dirty = [];
618
+ const touched = [];
619
+ const value = [];
620
+ const visual = [];
621
+ Object.values(formGroup.controls).forEach((control) => {
622
+ dirty.push(control.dirty);
623
+ touched.push(control.touched);
624
+ value.push(control.value);
625
+ visual.push(control.disabled);
626
+ visual.push(control.focused);
627
+ });
628
+ return {
629
+ dirty,
630
+ touched,
631
+ value,
632
+ visual
633
+ };
634
+ }, [formGroup.controls]);
635
+ const [state, setState] = useState(() => {
636
+ return {
637
+ ...refactorForValid(formGroup.controls, formGroup.validators),
638
+ controls: formGroup.controls,
639
+ dirties: checkAllSuccess(formGroupStatus.dirty),
640
+ dirty: checkPartialSuccess(formGroupStatus.dirty),
641
+ touched: checkPartialSuccess(formGroupStatus.touched),
642
+ toucheds: checkAllSuccess(formGroupStatus.touched),
643
+ validators: formGroup.validators,
644
+ value: controlsToValue(formGroup.controls)
645
+ };
593
646
  });
594
647
  useEffect(() => {
595
- if (!firstEffects.current.value) {
648
+ if (formInitialized.current.value) {
596
649
  setState((state) => ({
597
650
  ...state,
598
651
  ...refactorForValid(formGroup.controls, state.validators),
@@ -601,49 +654,46 @@ function useFormGroup(options, validators) {
601
654
  }));
602
655
  }
603
656
  else {
604
- firstEffects.current.value = false;
657
+ formInitialized.current.value = true;
605
658
  }
606
- }, reduceControlsToArray(formGroup.controls, 'value'));
659
+ }, formGroupStatus.value);
607
660
  useEffect(() => {
608
- if (!firstEffects.current.disabledFocused) {
661
+ if (formInitialized.current.dirty) {
609
662
  setState((state) => ({
610
663
  ...state,
611
- controls: formGroup.controls
664
+ controls: formGroup.controls,
665
+ dirty: checkPartialSuccess(formGroupStatus.dirty),
666
+ dirties: checkAllSuccess(formGroupStatus.dirty)
612
667
  }));
613
668
  }
614
669
  else {
615
- firstEffects.current.disabledFocused = false;
670
+ formInitialized.current.dirty = true;
616
671
  }
617
- }, [
618
- ...reduceControlsToArray(formGroup.controls, 'disabled'),
619
- ...reduceControlsToArray(formGroup.controls, 'focused')
620
- ]);
672
+ }, formGroupStatus.dirty);
621
673
  useEffect(() => {
622
- if (!firstEffects.current.dirty) {
674
+ if (formInitialized.current.touched) {
623
675
  setState((state) => ({
624
676
  ...state,
625
677
  controls: formGroup.controls,
626
- dirty: controlsPartialChecked(formGroup.controls, 'dirty'),
627
- dirties: controlsAllChecked(formGroup.controls, 'dirty')
678
+ touched: checkPartialSuccess(formGroupStatus.touched),
679
+ toucheds: checkAllSuccess(formGroupStatus.touched)
628
680
  }));
629
681
  }
630
682
  else {
631
- firstEffects.current.dirty = false;
683
+ formInitialized.current.touched = true;
632
684
  }
633
- }, reduceControlsToArray(formGroup.controls, 'dirty'));
685
+ }, formGroupStatus.touched);
634
686
  useEffect(() => {
635
- if (!firstEffects.current.touched) {
687
+ if (formInitialized.current.visual) {
636
688
  setState((state) => ({
637
689
  ...state,
638
- controls: formGroup.controls,
639
- touched: controlsPartialChecked(formGroup.controls, 'touched'),
640
- toucheds: controlsAllChecked(formGroup.controls, 'touched')
690
+ controls: formGroup.controls
641
691
  }));
642
692
  }
643
693
  else {
644
- firstEffects.current.touched = false;
694
+ formInitialized.current.visual = true;
645
695
  }
646
- }, reduceControlsToArray(formGroup.controls, 'touched'));
696
+ }, formGroupStatus.visual);
647
697
  const setValidators = useCallback((validators) => {
648
698
  setState((state) => ({
649
699
  ...state,