gform-react 2.5.0 → 2.5.3

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.
@@ -28,7 +28,7 @@ const _buildFormInitialValues = (rows = []) => {
28
28
  const inputConfigs = _findInputs(row);
29
29
  inputConfigs.forEach(config => {
30
30
  if (fields[config.formKey]) {
31
- console.warn(`[Duplicate Keys] - field with key '${config.formKey}' has already been defined.`);
31
+ console.warn(`DEV ONLY - [Duplicate Keys] - field with key '${config.formKey}' has already been defined.`);
32
32
  }
33
33
  const {
34
34
  required = false,
@@ -89,8 +89,9 @@ const _findInputs = (root, total = []) => {
89
89
  }
90
90
  return _findInputs((_root$props2 = root.props) === null || _root$props2 === void 0 ? void 0 : _root$props2.children, total);
91
91
  };
92
- const _findValidityKey = validity => {
92
+ const _findValidityKey = (validity, exclude = []) => {
93
93
  for (const key in validity) {
94
+ if (exclude.includes(key)) continue;
94
95
  if (key !== 'valid' && validity[key]) {
95
96
  return key;
96
97
  }
@@ -123,6 +124,14 @@ const hasSubmitter = form => {
123
124
  }
124
125
  return false;
125
126
  };
127
+ const _checkIfFormIsValid = fields => {
128
+ for (const f in fields) {
129
+ if (fields[f].error) {
130
+ return false;
131
+ }
132
+ }
133
+ return true;
134
+ };
126
135
  const _toRawData = (fields, options = {}) => {
127
136
  const data = {};
128
137
  const {
@@ -222,7 +231,8 @@ let validityMap;
222
231
  pattern: 'withPatternMismatchMessage',
223
232
  min: 'withRangeUnderflowMessage',
224
233
  max: 'withRangeOverflowMessage',
225
- step: 'withStepMismatchMessage'
234
+ step: 'withStepMismatchMessage',
235
+ type: 'withTypeMismatchMessage'
226
236
  };
227
237
  validityMap = {
228
238
  tooShort: 'minLength',
@@ -231,7 +241,8 @@ let validityMap;
231
241
  patternMismatch: 'pattern',
232
242
  rangeOverflow: 'max',
233
243
  rangeUnderflow: 'min',
234
- stepMismatch: 'step'
244
+ stepMismatch: 'step',
245
+ typeMismatch: 'type'
235
246
  };
236
247
  }
237
248
  class GValidator {
@@ -262,6 +273,10 @@ class GValidator {
262
273
  }
263
274
  }
264
275
  }
276
+ hasConstraint(constraint) {
277
+ var _this$track;
278
+ return ((_this$track = this.track) === null || _this$track === void 0 ? void 0 : _this$track.includes(constraint)) || false;
279
+ }
265
280
  withRequiredMessage(message) {
266
281
  return this.__addConstraintValidationHandler('valueMissing', message);
267
282
  }
@@ -300,14 +315,14 @@ class GValidator {
300
315
  __addConstraintValidationHandler(validityKey, message) {
301
316
  if (this.track) {
302
317
  if (this.track.includes(validityKey)) {
303
- console.warn(`[Duplicate Handlers] - handler for '${validityKey}' has already been defined`);
318
+ console.warn(`DEV ONLY - [Duplicate Handlers] - handler for '${validityKey}' has already been defined`);
304
319
  }
305
320
  this.track.push(validityKey);
306
321
  }
307
322
  this._constraintHandlers.push((input, key) => {
308
323
  {
309
324
  if (validityKey && validityMap[validityKey] && typeof input[validityMap[validityKey]] === 'undefined') {
310
- console.warn(`[Missing Prop] - the input '${input.formKey}' has registered validator for the violation '${validityKey}' but the input hasn't described the constraint '${validityMap[validityKey]}'.\nadd '${validityMap[validityKey]}' to the input props.\nexample:\n<GInput formKey='${input.formKey}' ${validityMap[validityKey]}={...} />\n\nor either remove '.${handlersMap[validityMap[validityKey]]}(...)' validation`);
325
+ console.warn(`DEV ONLY - [Missing Prop] - the input '${input.formKey}' has registered validator for the violation '${validityKey}' but the input hasn't described the constraint '${validityMap[validityKey]}'.\nadd '${validityMap[validityKey]}' to the input props.\nexample:\n<GInput formKey='${input.formKey}' ${validityMap[validityKey]}={...} />\n\nor either remove '.${handlersMap[validityMap[validityKey]]}(...)' validation`);
311
326
  }
312
327
  }
313
328
  if (key === validityKey) {
@@ -324,15 +339,18 @@ const useFormHandlers = (getState, setState, validators = {}, optimized = false)
324
339
  const _viHandler = (input, e) => {
325
340
  if (!input) return;
326
341
  const element = e && e.target;
342
+ const hasInitialValue = !input.dirty && input.value && !input.touched;
343
+ if (!element && !hasInitialValue) return;
327
344
  if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
328
345
  if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
329
- if (!input.dirty && input.value && !input.touched) {
346
+ if (hasInitialValue) {
330
347
  _checkInputManually(input);
331
348
  _dispatchChanges(input, input.formKey);
332
349
  return;
333
350
  }
334
351
  element.setCustomValidity('');
335
- const validityKey = _findValidityKey(element.validity);
352
+ const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
353
+ const validityKey = _findValidityKey(element.validity, exclude);
336
354
  _validateInput(input, validityKey, v => element.setCustomValidity(v));
337
355
  if (!validityKey && input.error) {
338
356
  element.setCustomValidity(input.errorText || 'error');
@@ -345,6 +363,7 @@ const useFormHandlers = (getState, setState, validators = {}, optimized = false)
345
363
  }
346
364
  };
347
365
  const _checkInputManually = input => {
366
+ const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
348
367
  let validityKey = _findValidityKey({
349
368
  valueMissing: input.required && !input.value || false,
350
369
  typeMismatch: _checkTypeMismatch(input),
@@ -353,7 +372,7 @@ const useFormHandlers = (getState, setState, validators = {}, optimized = false)
353
372
  patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
354
373
  rangeUnderflow: input.min && Number(input.value) < Number(input.min) || false,
355
374
  rangeOverflow: input.max && Number(input.value) > Number(input.max) || false
356
- });
375
+ }, exclude);
357
376
  if (!validityKey && input.error) {
358
377
  validityKey = 'customError';
359
378
  }
@@ -366,6 +385,11 @@ const useFormHandlers = (getState, setState, validators = {}, optimized = false)
366
385
  };
367
386
  const _validateInput = (input, validityKey, setValidity) => {
368
387
  const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
388
+ {
389
+ if (validityKey && !(inputValidator !== null && inputValidator !== void 0 && inputValidator.hasConstraint(validityKey))) {
390
+ if (validityKey === 'typeMismatch') console.warn(`DEV ONLY - [Missing Validator] - the input '${input.formKey}' has described the constraint '${validityMap[validityKey]}' however, a correspond validator / custom validation / pattern validator are missing.\nadd '${handlersMap[validityMap[validityKey]]}' or 'withCustomValidation' or '${handlersMap[validityMap.patternMismatch]}' to the input validator.\nexample:\nconst validators: GValidators = {\n\temail: new GValidator().withPatternMismatchMessage('pattern mismatch'),\n\t...\n}\n\nor either remove the constraint '${validityMap[validityKey]}' from the input props`);else console.warn(`DEV ONLY - [Missing Validator] - the input '${input.formKey}' has described the constraint '${validityMap[validityKey]}' however, a correspond validator is missing.\nadd '${handlersMap[validityMap[validityKey]]}' to the input validator.\nexample:\nconst validators: GValidators = {\n\temail: new GValidator().withPatternMismatchMessage('pattern mismatch'),\n\t...\n}\n\nor either remove the constraint '${validityMap[validityKey]}' from the input props`);
391
+ }
392
+ }
369
393
  if (inputValidator) {
370
394
  __validateInput(input, inputValidator, validityKey, setValidity);
371
395
  }
@@ -416,6 +440,10 @@ const useFormHandlers = (getState, setState, validators = {}, optimized = false)
416
440
  });
417
441
  }
418
442
  };
443
+ const hasCustomValidation = input => {
444
+ const validator = validators[input.validatorKey || input.formKey] || validators['*'];
445
+ return validator && (validator.asyncHandlers.length > 0 || validator.handlers.length > 0);
446
+ };
419
447
  return {
420
448
  _updateInputHandler,
421
449
  _viHandler,
@@ -482,20 +510,6 @@ function createSelector(selectors, combiner) {
482
510
  };
483
511
  }
484
512
 
485
- const selectFields = [state => state.fields];
486
- const selectFirstInvalidField = createSelector(selectFields, fields => {
487
- for (const f in fields) {
488
- if (fields[f].error) {
489
- return true;
490
- }
491
- }
492
- return false;
493
- });
494
- const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
495
- const selected = keys.map(key => fields[key]).filter(Boolean);
496
- return selected.length ? selected : null;
497
- });
498
-
499
513
  const _excluded$1 = ["stateRef", "onSubmit", "onChange", "onPaste", "onKeyDown", "onKeyUp", "children", "onInit"],
500
514
  _excluded2 = ["children", "validators", "optimized"];
501
515
  const FormRenderer = forwardRef((_ref, ref) => {
@@ -515,7 +529,7 @@ const FormRenderer = forwardRef((_ref, ref) => {
515
529
  getState,
516
530
  handlers
517
531
  } = useFormStore();
518
- const isFormInvalid = useFormSelector(selectFirstInvalidField);
532
+ const fields = useFormSelector(state => state.fields);
519
533
  const refHandler = useCallback(element => {
520
534
  if (ref) {
521
535
  if (typeof ref === 'function') {
@@ -527,7 +541,7 @@ const FormRenderer = forwardRef((_ref, ref) => {
527
541
  formRef.current = element;
528
542
  }, [ref]);
529
543
  const getFormState = useCallback(() => {
530
- const fields = getState().fields;
544
+ const isFormInvalid = _checkIfFormIsValid(fields);
531
545
  const formState = _objectSpread(_objectSpread({}, fields), {}, {
532
546
  isValid: !isFormInvalid,
533
547
  isInvalid: isFormInvalid,
@@ -545,7 +559,7 @@ const FormRenderer = forwardRef((_ref, ref) => {
545
559
  });
546
560
  if (stateRef) stateRef.current = formState;
547
561
  return formState;
548
- }, [isFormInvalid]);
562
+ }, [fields]);
549
563
  const formComponent = useMemo(() => {
550
564
  const state = getFormState();
551
565
  const formChildren = typeof children === 'function' ? children(state) : children;
@@ -605,7 +619,7 @@ const FormRenderer = forwardRef((_ref, ref) => {
605
619
  useEffect(() => {
606
620
  const state = getFormState();
607
621
  if (!hasSubmitter(formRef.current)) {
608
- console.warn(`[No Submit Button] - you have created a form without a button type=submit, this will prevent the onSubmit event from being fired.\nif you have a button with onClick event that handle the submission of the form then ignore this warning\nbut don't forget to manually invoke the checkValidity() function to check if the form is valid before perfoming any action, for example:\nif (formState.checkValidity()) { \n\t//do somthing\n}\n`);
622
+ console.warn(`DEV ONLY - [No Submit Button] - you have created a form without a button type=submit, this will prevent the onSubmit event from being fired.\nif you have a button with onClick event that handle the submission of the form then ignore this warning\nbut don't forget to manually invoke the checkValidity() function to check if the form is valid before perfoming any action, for example:\nif (formState.checkValidity()) { \n\t//do somthing\n}\n`);
609
623
  }
610
624
  if (onInit) {
611
625
  const changes = onInit(state);
@@ -647,6 +661,12 @@ const GForm = forwardRef((_ref2, ref) => {
647
661
  }, props), children));
648
662
  });
649
663
 
664
+ const selectFields = [state => state.fields];
665
+ const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
666
+ const selected = keys.map(key => fields[key]).filter(Boolean);
667
+ return selected.length ? selected : null;
668
+ });
669
+
650
670
  const _excluded = ["formKey", "element", "title", "type", "fetch", "fetchDeps", "optimized", "debounce", "defaultChecked", "defaultValue", "checked", "validatorKey", "value"];
651
671
  const _GInput = forwardRef((_ref, ref) => {
652
672
  let {
@@ -701,6 +721,18 @@ const _GInput = forwardRef((_ref, ref) => {
701
721
  } : (e, unknown) => {
702
722
  store.handlers._updateInputHandler(inputState, e, unknown);
703
723
  };
724
+ if (!inputState.touched) {
725
+ _props.onFocus = rest.onFocus ? e => {
726
+ rest.onFocus(e);
727
+ inputState.dispatchChanges({
728
+ touched: true
729
+ });
730
+ } : () => {
731
+ inputState.dispatchChanges({
732
+ touched: true
733
+ });
734
+ };
735
+ }
704
736
  }
705
737
  if (element) {
706
738
  return element(inputState, _props);