@flowerforce/flower-core 3.1.2-beta.3 → 3.1.2-beta.5

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/index.cjs.js CHANGED
@@ -433,18 +433,22 @@ const FlowerStateUtils = {
433
433
  },
434
434
  makeSelectNodeErrors: (name, currentNodeId) => (state) => {
435
435
  const form = FlowerStateUtils.selectFlowerFormNode(name, currentNodeId)(state);
436
- return {
437
- touched: form?.touched || false,
438
- errors: form?.errors,
439
- isValidating: form?.isValidating,
440
- isValid: form && form.errors
441
- ? Object.values(form.errors).flat().length === 0
442
- : true
443
- };
436
+ return createFormData(form);
444
437
  }
445
438
  };
439
+ const createFormData = (form) => {
440
+ const validationErrors = form && form.errors;
441
+ const allErrors = Object.values(validationErrors || {});
442
+ return {
443
+ touched: form?.touched || false,
444
+ errors: form?.errors,
445
+ customErrors: form?.customErrors,
446
+ isValidating: form?.isValidating,
447
+ isValid: allErrors.flat().length === 0
448
+ };
449
+ };
446
450
 
447
- const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule } = CoreUtils;
451
+ const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule, getPath } = CoreUtils;
448
452
  /**
449
453
  * These functions are Redux reducers used in a Flux architecture for managing state transitions and updates in a Flower application.
450
454
  */
@@ -601,6 +605,9 @@ const FlowerCoreReducers = {
601
605
  }
602
606
  }
603
607
  },
608
+ formAddCustomErrors: (state, { payload }) => {
609
+ _set(state, [payload.name, 'form', payload.currentNode, 'customErrors', payload.id], payload.errors);
610
+ },
604
611
  formAddErrors: (state, { payload }) => {
605
612
  _set(state, [payload.name, 'form', payload.currentNode, 'errors', payload.id], payload.errors);
606
613
  },
@@ -612,15 +619,33 @@ const FlowerCoreReducers = {
612
619
  'errors',
613
620
  payload.id
614
621
  ]);
622
+ _unset(state, [
623
+ payload.name,
624
+ 'form',
625
+ payload.currentNode,
626
+ 'customErrors',
627
+ payload.id
628
+ ]);
615
629
  _unset(state, [payload.name, 'form', payload.currentNode, 'isValidating']);
616
630
  },
631
+ formFieldTouch: (state, { payload }) => {
632
+ _set(state, [payload.name, 'form', payload.currentNode, 'touches', payload.id], payload.touched);
633
+ },
634
+ formFieldDirty: (state, { payload }) => {
635
+ _set(state, [payload.name, 'form', payload.currentNode, 'dirty', payload.id], payload.dirty);
636
+ },
617
637
  addData: (state, { payload }) => {
618
638
  const prevData = _get(state, [payload.flowName, 'data']);
619
639
  _set(state, [payload.flowName, 'data'], { ...prevData, ...payload.value });
620
640
  },
621
641
  addDataByPath: (state, { payload }) => {
642
+ const { path: newpath } = getPath(payload.id);
643
+ const currentNode = FlowerStateUtils.makeSelectCurrentNodeId(payload.flowName)(state);
622
644
  if (payload.id && payload.id.length) {
623
- _set(state, [payload.flowName, 'data', ...payload.id], payload.value);
645
+ _set(state, [payload.flowName, 'data', ...newpath], payload.value);
646
+ if (payload?.dirty) {
647
+ _set(state, [payload.flowName, 'form', currentNode, 'dirty', payload.id], payload.dirty);
648
+ }
624
649
  }
625
650
  },
626
651
  // TODO usato al momento solo il devtool
@@ -634,6 +659,16 @@ const FlowerCoreReducers = {
634
659
  setFormIsValidating: (state, { payload }) => {
635
660
  _set(state, [payload.name, 'form', payload.currentNode, 'isValidating'], payload.isValidating);
636
661
  },
662
+ resetForm: (state, { payload }) => {
663
+ const touchedFields = _get(state, [payload.flowName, 'form', payload.id, 'errors'], {});
664
+ Object.keys(touchedFields).forEach((key) => {
665
+ const { flowNameFromPath = payload.flowName, path } = getPath(key);
666
+ _unset(state, [flowNameFromPath, 'data', ...path]);
667
+ });
668
+ _unset(state, [payload.flowName, 'form', payload.id, 'touches']);
669
+ _unset(state, [payload.flowName, 'form', payload.id, 'dirty']);
670
+ _unset(state, [payload.flowName, 'form', payload.id, 'touched']);
671
+ },
637
672
  node: (state, { payload }) => {
638
673
  const { name, history } = payload;
639
674
  const node = payload.nodeId || payload.node || '';
@@ -743,6 +778,8 @@ const FlowerCoreStateSelectors = {
743
778
  getDataByFlow: (flower) => _get(flower, ['data']) ?? {},
744
779
  getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
745
780
  makeSelectNodeFormTouched: (form) => form && form.touched,
781
+ makeSelectNodeFormFieldTouched: (id) => (form) => form && form.touches && form.touches[id],
782
+ makeSelectNodeFormFieldDirty: (id) => (form) => form && form.dirty && form.dirty[id],
746
783
  makeSelectCurrentNodeId: (flower, startNodeId) => _get(flower, ['current']) || startNodeId,
747
784
  makeSelectCurrentNodeDisabled: (nodes, current) => !!_get(nodes, [current, 'disabled']),
748
785
  makeSelectPrevNodeRetain: (nodes, history, current) => {
@@ -760,19 +797,16 @@ const FlowerCoreStateSelectors = {
760
797
  if (nodes[prevFlowerNode] && nodes[prevFlowerNode].disabled)
761
798
  return;
762
799
  // eslint-disable-next-line consistent-return
763
- return (nodes[prevFlowerNode] && nodes[prevFlowerNode].retain && prevFlowerNode);
764
- },
765
- makeSelectNodeErrors: (form) => {
766
- return {
767
- touched: form?.touched || false,
768
- errors: form?.errors,
769
- isValidating: form?.isValidating,
770
- isValid: form && form.errors
771
- ? Object.values(form.errors).flat().length === 0
772
- : true
773
- };
774
- },
775
- makeSelectFieldError: (name, id, validate) => (data) => {
800
+ return nodes[prevFlowerNode] && nodes[prevFlowerNode].retain
801
+ ? prevFlowerNode
802
+ : undefined;
803
+ },
804
+ makeSelectNodeErrors: createFormData,
805
+ makeSelectFieldError: (name, id, validate) => (data, form) => {
806
+ const customErrors = Object.entries((form && form.customErrors) || {})
807
+ .filter(([k]) => k === id)
808
+ .map(([, v]) => v)
809
+ .flat();
776
810
  if (!validate || !data)
777
811
  return [];
778
812
  const errors = validate.filter((rule) => {
@@ -787,7 +821,7 @@ const FlowerCoreStateSelectors = {
787
821
  return hasError;
788
822
  });
789
823
  const result = errors.map((r) => (r && r.message) || 'error');
790
- return result.length === 0 ? [] : result;
824
+ return [...customErrors, ...(result.length === 0 ? [] : result)];
791
825
  },
792
826
  selectorRulesDisabled: (id, rules, keys, flowName, value) => (data, form) => {
793
827
  const newState = { ...data, ...value, $form: form };
package/dist/index.esm.js CHANGED
@@ -431,18 +431,22 @@ const FlowerStateUtils = {
431
431
  },
432
432
  makeSelectNodeErrors: (name, currentNodeId) => (state) => {
433
433
  const form = FlowerStateUtils.selectFlowerFormNode(name, currentNodeId)(state);
434
- return {
435
- touched: form?.touched || false,
436
- errors: form?.errors,
437
- isValidating: form?.isValidating,
438
- isValid: form && form.errors
439
- ? Object.values(form.errors).flat().length === 0
440
- : true
441
- };
434
+ return createFormData(form);
442
435
  }
443
436
  };
437
+ const createFormData = (form) => {
438
+ const validationErrors = form && form.errors;
439
+ const allErrors = Object.values(validationErrors || {});
440
+ return {
441
+ touched: form?.touched || false,
442
+ errors: form?.errors,
443
+ customErrors: form?.customErrors,
444
+ isValidating: form?.isValidating,
445
+ isValid: allErrors.flat().length === 0
446
+ };
447
+ };
444
448
 
445
- const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule } = CoreUtils;
449
+ const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule, getPath } = CoreUtils;
446
450
  /**
447
451
  * These functions are Redux reducers used in a Flux architecture for managing state transitions and updates in a Flower application.
448
452
  */
@@ -599,6 +603,9 @@ const FlowerCoreReducers = {
599
603
  }
600
604
  }
601
605
  },
606
+ formAddCustomErrors: (state, { payload }) => {
607
+ _set(state, [payload.name, 'form', payload.currentNode, 'customErrors', payload.id], payload.errors);
608
+ },
602
609
  formAddErrors: (state, { payload }) => {
603
610
  _set(state, [payload.name, 'form', payload.currentNode, 'errors', payload.id], payload.errors);
604
611
  },
@@ -610,15 +617,33 @@ const FlowerCoreReducers = {
610
617
  'errors',
611
618
  payload.id
612
619
  ]);
620
+ _unset(state, [
621
+ payload.name,
622
+ 'form',
623
+ payload.currentNode,
624
+ 'customErrors',
625
+ payload.id
626
+ ]);
613
627
  _unset(state, [payload.name, 'form', payload.currentNode, 'isValidating']);
614
628
  },
629
+ formFieldTouch: (state, { payload }) => {
630
+ _set(state, [payload.name, 'form', payload.currentNode, 'touches', payload.id], payload.touched);
631
+ },
632
+ formFieldDirty: (state, { payload }) => {
633
+ _set(state, [payload.name, 'form', payload.currentNode, 'dirty', payload.id], payload.dirty);
634
+ },
615
635
  addData: (state, { payload }) => {
616
636
  const prevData = _get(state, [payload.flowName, 'data']);
617
637
  _set(state, [payload.flowName, 'data'], { ...prevData, ...payload.value });
618
638
  },
619
639
  addDataByPath: (state, { payload }) => {
640
+ const { path: newpath } = getPath(payload.id);
641
+ const currentNode = FlowerStateUtils.makeSelectCurrentNodeId(payload.flowName)(state);
620
642
  if (payload.id && payload.id.length) {
621
- _set(state, [payload.flowName, 'data', ...payload.id], payload.value);
643
+ _set(state, [payload.flowName, 'data', ...newpath], payload.value);
644
+ if (payload?.dirty) {
645
+ _set(state, [payload.flowName, 'form', currentNode, 'dirty', payload.id], payload.dirty);
646
+ }
622
647
  }
623
648
  },
624
649
  // TODO usato al momento solo il devtool
@@ -632,6 +657,16 @@ const FlowerCoreReducers = {
632
657
  setFormIsValidating: (state, { payload }) => {
633
658
  _set(state, [payload.name, 'form', payload.currentNode, 'isValidating'], payload.isValidating);
634
659
  },
660
+ resetForm: (state, { payload }) => {
661
+ const touchedFields = _get(state, [payload.flowName, 'form', payload.id, 'errors'], {});
662
+ Object.keys(touchedFields).forEach((key) => {
663
+ const { flowNameFromPath = payload.flowName, path } = getPath(key);
664
+ _unset(state, [flowNameFromPath, 'data', ...path]);
665
+ });
666
+ _unset(state, [payload.flowName, 'form', payload.id, 'touches']);
667
+ _unset(state, [payload.flowName, 'form', payload.id, 'dirty']);
668
+ _unset(state, [payload.flowName, 'form', payload.id, 'touched']);
669
+ },
635
670
  node: (state, { payload }) => {
636
671
  const { name, history } = payload;
637
672
  const node = payload.nodeId || payload.node || '';
@@ -741,6 +776,8 @@ const FlowerCoreStateSelectors = {
741
776
  getDataByFlow: (flower) => _get(flower, ['data']) ?? {},
742
777
  getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
743
778
  makeSelectNodeFormTouched: (form) => form && form.touched,
779
+ makeSelectNodeFormFieldTouched: (id) => (form) => form && form.touches && form.touches[id],
780
+ makeSelectNodeFormFieldDirty: (id) => (form) => form && form.dirty && form.dirty[id],
744
781
  makeSelectCurrentNodeId: (flower, startNodeId) => _get(flower, ['current']) || startNodeId,
745
782
  makeSelectCurrentNodeDisabled: (nodes, current) => !!_get(nodes, [current, 'disabled']),
746
783
  makeSelectPrevNodeRetain: (nodes, history, current) => {
@@ -758,19 +795,16 @@ const FlowerCoreStateSelectors = {
758
795
  if (nodes[prevFlowerNode] && nodes[prevFlowerNode].disabled)
759
796
  return;
760
797
  // eslint-disable-next-line consistent-return
761
- return (nodes[prevFlowerNode] && nodes[prevFlowerNode].retain && prevFlowerNode);
762
- },
763
- makeSelectNodeErrors: (form) => {
764
- return {
765
- touched: form?.touched || false,
766
- errors: form?.errors,
767
- isValidating: form?.isValidating,
768
- isValid: form && form.errors
769
- ? Object.values(form.errors).flat().length === 0
770
- : true
771
- };
772
- },
773
- makeSelectFieldError: (name, id, validate) => (data) => {
798
+ return nodes[prevFlowerNode] && nodes[prevFlowerNode].retain
799
+ ? prevFlowerNode
800
+ : undefined;
801
+ },
802
+ makeSelectNodeErrors: createFormData,
803
+ makeSelectFieldError: (name, id, validate) => (data, form) => {
804
+ const customErrors = Object.entries((form && form.customErrors) || {})
805
+ .filter(([k]) => k === id)
806
+ .map(([, v]) => v)
807
+ .flat();
774
808
  if (!validate || !data)
775
809
  return [];
776
810
  const errors = validate.filter((rule) => {
@@ -785,7 +819,7 @@ const FlowerCoreStateSelectors = {
785
819
  return hasError;
786
820
  });
787
821
  const result = errors.map((r) => (r && r.message) || 'error');
788
- return result.length === 0 ? [] : result;
822
+ return [...customErrors, ...(result.length === 0 ? [] : result)];
789
823
  },
790
824
  selectorRulesDisabled: (id, rules, keys, flowName, value) => (data, form) => {
791
825
  const newState = { ...data, ...value, $form: form };
@@ -1,2 +1,9 @@
1
1
  import { CoreStateUtils } from './interfaces/UtilsInterface';
2
2
  export declare const FlowerStateUtils: CoreStateUtils;
3
+ export declare const createFormData: (form: Record<string, any>) => {
4
+ touched: any;
5
+ errors: any;
6
+ customErrors: any;
7
+ isValidating: any;
8
+ isValid: boolean;
9
+ };
@@ -5,7 +5,7 @@ export type ActionWithPayload<T> = {
5
5
  payload: T;
6
6
  };
7
7
  type ReducerFunctionSign<T extends object, R> = (state: Record<string, Flower<T>>, action: ActionWithPayload<R>) => Record<string, Flower<T>> | void;
8
- export type ActionsTypes = 'historyAdd' | 'historyPrevToNode' | 'setFormTouched' | 'forceAddHistory' | 'historyPop' | 'restoreHistory' | 'replaceNode' | 'initializeFromNode' | 'forceResetHistory' | 'destroy' | 'initNodes' | 'setCurrentNode' | 'formAddErrors' | 'formRemoveErrors' | 'addData' | 'addDataByPath' | 'replaceData' | 'unsetData' | 'setFormIsValidating' | 'node' | 'prevToNode' | 'next' | 'prev' | 'reset';
8
+ export type ActionsTypes = 'historyAdd' | 'historyPrevToNode' | 'setFormTouched' | 'forceAddHistory' | 'historyPop' | 'restoreHistory' | 'replaceNode' | 'initializeFromNode' | 'forceResetHistory' | 'destroy' | 'initNodes' | 'setCurrentNode' | 'formAddErrors' | 'formRemoveErrors' | 'addData' | 'addDataByPath' | 'replaceData' | 'unsetData' | 'setFormIsValidating' | 'resetForm' | 'formFieldTouch' | 'formFieldDirty' | 'node' | 'prevToNode' | 'next' | 'prev' | 'reset';
9
9
  /**
10
10
  * These functions are Redux reducers used in a Flux architecture for managing state transitions and updates in a Flower application.
11
11
  */
@@ -162,6 +162,20 @@ export type ReducersFunctions<T extends Record<string, any> = Record<string, Flo
162
162
  name: string;
163
163
  node: string;
164
164
  }>;
165
+ /**
166
+ * @param state
167
+ * @param action
168
+ *
169
+ * Adds errors to a form node in a flow.
170
+ *
171
+ * @returns state
172
+ */
173
+ formAddCustomErrors: ReducerFunctionSign<T, {
174
+ name: string;
175
+ currentNode: string;
176
+ id: string;
177
+ errors: string[];
178
+ }>;
165
179
  /**
166
180
  * @param state
167
181
  * @param action
@@ -178,6 +192,34 @@ export type ReducersFunctions<T extends Record<string, any> = Record<string, Flo
178
192
  [x: string]: string[];
179
193
  } | string[];
180
194
  }>;
195
+ /**
196
+ * @param state
197
+ * @param action
198
+ *
199
+ * Set touch form single field
200
+ *
201
+ * @returns state
202
+ */
203
+ formFieldDirty: ReducerFunctionSign<T, {
204
+ name: string;
205
+ currentNode: string;
206
+ id: string;
207
+ dirty?: boolean;
208
+ }>;
209
+ /**
210
+ * @param state
211
+ * @param action
212
+ *
213
+ * Set touch form single field
214
+ *
215
+ * @returns state
216
+ */
217
+ formFieldTouch: ReducerFunctionSign<T, {
218
+ name: string;
219
+ currentNode: string;
220
+ id: string;
221
+ touched?: boolean;
222
+ }>;
181
223
  /**
182
224
  * @param state
183
225
  * @param action
@@ -212,9 +254,10 @@ export type ReducersFunctions<T extends Record<string, any> = Record<string, Flo
212
254
  * @returns state
213
255
  */
214
256
  addDataByPath: ReducerFunctionSign<T, {
215
- id: string[];
257
+ id: string;
216
258
  flowName: string;
217
259
  value: T | string;
260
+ dirty?: boolean;
218
261
  }>;
219
262
  /**
220
263
  * @param state
@@ -331,6 +374,19 @@ export type ReducersFunctions<T extends Record<string, any> = Record<string, Flo
331
374
  name?: string;
332
375
  flowName?: string;
333
376
  initialData?: Record<string, any>;
377
+ }
378
+ /**
379
+ * @param state
380
+ * @param action
381
+ *
382
+ * Reset form.
383
+ *
384
+ * @returns state
385
+ */
386
+ >;
387
+ resetForm: ReducerFunctionSign<T, {
388
+ id: string;
389
+ flowName: string;
334
390
  }>;
335
391
  };
336
392
  export {};
@@ -51,7 +51,7 @@ export interface ISelectors {
51
51
  * @param current
52
52
  * @returns
53
53
  */
54
- makeSelectPrevNodeRetain<T extends Record<string, any>>(nodes: Flower<T>['nodes'], history: Flower<T>['history'], current: Flower<T>['current']): boolean | string | undefined;
54
+ makeSelectPrevNodeRetain<T extends Record<string, any>>(nodes: Flower<T>['nodes'], history: Flower<T>['history'], current: Flower<T>['current']): string | undefined;
55
55
  /**
56
56
  * @param nodes
57
57
  * @param current
@@ -67,9 +67,20 @@ export interface ISelectors {
67
67
  makeSelectNodeErrors<T extends Record<string, any>>(form: Form<T> | undefined): {
68
68
  touched: boolean;
69
69
  errors: any;
70
+ customErrors: any;
70
71
  isValid: boolean;
71
72
  isValidating?: boolean;
72
73
  };
74
+ /**
75
+ * @param form
76
+ * @returns
77
+ */
78
+ makeSelectNodeFormFieldTouched<T extends Record<string, any>>(id: string): (form: Form<T> | undefined) => boolean | undefined;
79
+ /**
80
+ * @param form
81
+ * @returns
82
+ */
83
+ makeSelectNodeFormFieldDirty<T extends Record<string, any>>(id: string): (form: Form<T> | undefined) => boolean | undefined;
73
84
  /**
74
85
  * @param flower
75
86
  * @returns
@@ -94,7 +105,7 @@ export interface ISelectors {
94
105
  makeSelectFieldError<T extends Record<string, any>>(name: string, id: string, validate: {
95
106
  rules?: RulesObject<any>;
96
107
  message?: string;
97
- }[] | null): (data?: T) => Array<string>;
108
+ }[] | null): (data: T | undefined, form: Form<T>) => Array<string>;
98
109
  /**
99
110
  * @param id
100
111
  * @param rules
@@ -103,10 +114,5 @@ export interface ISelectors {
103
114
  * @param value
104
115
  * @returns
105
116
  */
106
- selectorRulesDisabled<T extends Record<string, any>>(id: string, rules: any, keys: string[] | null, flowName: string, value: any): (data: T | undefined, form: {
107
- touched: boolean;
108
- errors: any;
109
- isValid: boolean;
110
- isValidating?: boolean;
111
- }) => boolean;
117
+ selectorRulesDisabled<T extends Record<string, any>>(id: string, rules: any, keys: string[] | null, flowName: string, value: any): (data: T | undefined, form: Form<T>) => boolean;
112
118
  }
@@ -49,4 +49,13 @@ export type Form<T> = {
49
49
  errors?: {
50
50
  [K in keyof T]: Array<string>;
51
51
  };
52
+ customErrors?: {
53
+ [K in keyof T]: Array<string>;
54
+ };
55
+ dirty?: {
56
+ [K in keyof T]: boolean;
57
+ };
58
+ touches?: {
59
+ [K in keyof T]: boolean;
60
+ };
52
61
  };
@@ -43,6 +43,7 @@ export interface CoreStateUtils {
43
43
  makeSelectNodeErrors<T extends object>(name: string, currentNodeId: string): (state: T) => {
44
44
  touched: boolean;
45
45
  errors: any;
46
+ customErrors: any;
46
47
  isValid: boolean;
47
48
  isValidating?: boolean;
48
49
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flower-core",
3
- "version": "3.1.2-beta.3",
3
+ "version": "3.1.2-beta.5",
4
4
  "description": "Core functions for flowerJS",
5
5
  "repository": {
6
6
  "type": "git",