@rolster/react-forms 18.14.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) {
@@ -110,10 +109,10 @@ class ReactRolsterArrayControl extends RolsterArrayControl {
110
109
  }
111
110
  }
112
111
  function rolsterArrayControl(options, validators) {
113
- const _options = createFormControlOptions(options, validators);
112
+ const formControl = createFormControlOptions(options, validators);
114
113
  return new ReactRolsterArrayControl({
115
- ..._options,
116
- initialValue: _options.value,
114
+ ...formControl,
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
  }
@@ -351,33 +358,35 @@ function refactorForControls(action, state, groups) {
351
358
  }
352
359
  }
353
360
  function useFormArray(options, validators) {
354
- const _options = createFormArrayOptions(options, validators);
355
- const groups = _options.groups || [];
356
- const _value = useRef(groups);
357
- const mapGroups = useRef(new Map());
358
- const [state, setState] = useState({
359
- ...refactorForValid$1(groups, _options.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: _options.validators
361
+ const formArray = createFormArrayOptions(options, validators);
362
+ const groups = formArray.groups || [];
363
+ const value = useRef(groups);
364
+ const formGroups = useRef(new Map());
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
- mapGroups.current.clear();
380
+ formGroups.current.clear();
372
381
  state.groups.forEach((group) => {
373
- mapGroups.current.set(group.uuid, group);
382
+ formGroups.current.set(group.uuid, group);
374
383
  group.subscribe(subscriber);
375
384
  });
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,
@@ -402,7 +411,7 @@ function useFormArray(options, validators) {
402
411
  ...state,
403
412
  ...refactorForGroups(groups, state.validators)
404
413
  }));
405
- _value.current = groups;
414
+ value.current = groups;
406
415
  }, []);
407
416
  const push = useCallback((group) => {
408
417
  setState((state) => ({
@@ -423,7 +432,7 @@ function useFormArray(options, validators) {
423
432
  }));
424
433
  }, []);
425
434
  const findByUuid = useCallback((uuid) => {
426
- return mapGroups.current.get(uuid);
435
+ return formGroups.current.get(uuid);
427
436
  }, [state.groups]);
428
437
  const setValidators = useCallback((validators) => {
429
438
  setState((state) => ({
@@ -432,12 +441,16 @@ 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,
440
- ...refactorForGroups(_value.current, state.validators)
453
+ ...refactorForGroups(value.current, state.validators)
441
454
  }));
442
455
  }, []);
443
456
  return {
@@ -469,16 +482,18 @@ function errorsInControl(value, validators) {
469
482
  return validators ? controlIsValid({ value, validators }) : [];
470
483
  }
471
484
  function useControl(options, validators) {
472
- const _options = createFormControlOptions(options, validators);
473
- const initialValue = useRef(_options.value);
474
- const [state, setState] = useState({
475
- dirty: false,
476
- disabled: false,
477
- errors: errorsInControl(_options.value, _options.validators),
478
- focused: false,
479
- touched: !!_options.touched,
480
- value: _options.value,
481
- validators: _options.validators
485
+ const formControl = createFormControlOptions(options, 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,78 +599,101 @@ 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
- const _options = createFormGroupOptions(options, validators);
578
- const { controls } = _options;
579
- const firstEffects = useRef({
580
- dirty: true,
581
- disabledFocused: true,
582
- touched: true,
583
- value: true
609
+ const formGroup = createFormGroupOptions(options, validators);
610
+ const formInitialized = useRef({
611
+ dirty: false,
612
+ touched: false,
613
+ value: false,
614
+ visual: false
584
615
  });
585
- const [state, setState] = useState({
586
- ...refactorForValid(controls, _options.validators),
587
- controls,
588
- dirties: controlsAllChecked(controls, 'dirty'),
589
- dirty: controlsPartialChecked(controls, 'dirty'),
590
- touched: controlsPartialChecked(controls, 'touched'),
591
- toucheds: controlsAllChecked(controls, 'touched'),
592
- value: controlsToValue(controls),
593
- validators: _options.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
+ };
594
646
  });
595
647
  useEffect(() => {
596
- if (!firstEffects.current.value) {
648
+ if (formInitialized.current.value) {
597
649
  setState((state) => ({
598
650
  ...state,
599
- ...refactorForValid(controls, state.validators),
600
- controls,
601
- value: controlsToValue(controls)
651
+ ...refactorForValid(formGroup.controls, state.validators),
652
+ controls: formGroup.controls,
653
+ value: controlsToValue(formGroup.controls)
602
654
  }));
603
655
  }
604
656
  else {
605
- firstEffects.current.value = false;
657
+ formInitialized.current.value = true;
606
658
  }
607
- }, reduceControlsToArray(controls, 'value'));
659
+ }, formGroupStatus.value);
608
660
  useEffect(() => {
609
- if (!firstEffects.current.disabledFocused) {
661
+ if (formInitialized.current.dirty) {
610
662
  setState((state) => ({
611
663
  ...state,
612
- controls
664
+ controls: formGroup.controls,
665
+ dirty: checkPartialSuccess(formGroupStatus.dirty),
666
+ dirties: checkAllSuccess(formGroupStatus.dirty)
613
667
  }));
614
668
  }
615
669
  else {
616
- firstEffects.current.disabledFocused = false;
670
+ formInitialized.current.dirty = true;
617
671
  }
618
- }, [
619
- ...reduceControlsToArray(controls, 'disabled'),
620
- ...reduceControlsToArray(controls, 'focused')
621
- ]);
672
+ }, formGroupStatus.dirty);
622
673
  useEffect(() => {
623
- if (!firstEffects.current.dirty) {
674
+ if (formInitialized.current.touched) {
624
675
  setState((state) => ({
625
676
  ...state,
626
- controls,
627
- dirty: controlsPartialChecked(controls, 'dirty'),
628
- dirties: controlsAllChecked(controls, 'dirty')
677
+ controls: formGroup.controls,
678
+ touched: checkPartialSuccess(formGroupStatus.touched),
679
+ toucheds: checkAllSuccess(formGroupStatus.touched)
629
680
  }));
630
681
  }
631
682
  else {
632
- firstEffects.current.dirty = false;
683
+ formInitialized.current.touched = true;
633
684
  }
634
- }, reduceControlsToArray(controls, 'dirty'));
685
+ }, formGroupStatus.touched);
635
686
  useEffect(() => {
636
- if (!firstEffects.current.touched) {
687
+ if (formInitialized.current.visual) {
637
688
  setState((state) => ({
638
689
  ...state,
639
- controls,
640
- touched: controlsPartialChecked(controls, 'touched'),
641
- toucheds: controlsAllChecked(controls, 'touched')
690
+ controls: formGroup.controls
642
691
  }));
643
692
  }
644
693
  else {
645
- firstEffects.current.touched = false;
694
+ formInitialized.current.visual = true;
646
695
  }
647
- }, reduceControlsToArray(controls, 'touched'));
696
+ }, formGroupStatus.visual);
648
697
  const setValidators = useCallback((validators) => {
649
698
  setState((state) => ({
650
699
  ...state,
@@ -652,7 +701,7 @@ function useFormGroup(options, validators) {
652
701
  }));
653
702
  }, []);
654
703
  const reset = useCallback(() => {
655
- Object.values(controls).forEach((control) => {
704
+ Object.values(formGroup.controls).forEach((control) => {
656
705
  control.reset();
657
706
  });
658
707
  }, []);