gform-react 1.11.1 → 2.5.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.
Files changed (31) hide show
  1. package/README.md +4 -3
  2. package/dist/cjs/gform-react.development.js +280 -238
  3. package/dist/cjs/gform-react.development.js.map +1 -1
  4. package/dist/cjs/gform-react.production.js +1 -1
  5. package/dist/cjs/gform-react.production.js.map +1 -1
  6. package/dist/esm/GForm.production.js +1 -1
  7. package/dist/esm/GForm.production.js.map +1 -1
  8. package/dist/esm/GInput.production.js +1 -1
  9. package/dist/esm/GInput.production.js.map +1 -1
  10. package/dist/esm/GValidator.production.js +1 -1
  11. package/dist/esm/GValidator.production.js.map +1 -1
  12. package/dist/esm/index.development.js +286 -243
  13. package/dist/esm/index.development.js.map +1 -1
  14. package/dist/esm/index.js +2 -1
  15. package/dist/esm/shared.production.js +1 -1
  16. package/dist/esm/shared.production.js.map +1 -1
  17. package/dist/index.d.ts +25 -12
  18. package/native/dist/cjs/gform-react-native.development.js +222 -284
  19. package/native/dist/cjs/gform-react-native.development.js.map +1 -1
  20. package/native/dist/cjs/gform-react-native.production.js +1 -1
  21. package/native/dist/cjs/gform-react-native.production.js.map +1 -1
  22. package/native/dist/esm/RNGForm.production.js +1 -1
  23. package/native/dist/esm/RNGForm.production.js.map +1 -1
  24. package/native/dist/esm/RNGInput.production.js +1 -1
  25. package/native/dist/esm/RNGInput.production.js.map +1 -1
  26. package/native/dist/esm/index.development.js +228 -288
  27. package/native/dist/esm/index.development.js.map +1 -1
  28. package/native/dist/esm/shared.production.js +1 -1
  29. package/native/dist/esm/shared.production.js.map +1 -1
  30. package/native/dist/index.d.ts +4 -8
  31. package/package.json +27 -24
@@ -1,7 +1,7 @@
1
1
  import _extends from '@babel/runtime/helpers/esm/extends';
2
2
  import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
3
3
  import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
4
- import React, { useMemo, useState, createContext, useContext, forwardRef, useRef, useEffect } from 'react';
4
+ import React, { useSyncExternalStore, useRef, useCallback, useEffect, createContext, useContext, forwardRef, useMemo, memo } from 'react';
5
5
  import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
6
6
 
7
7
  const isObject = o => o && typeof o === 'object' && !Array.isArray(o);
@@ -24,7 +24,7 @@ const generateId = () => (+new Date()).toString(36) + (1 - Math.random()).toStri
24
24
  const _buildFormInitialValues = (rows = []) => {
25
25
  const fields = {};
26
26
  if (!Array.isArray(rows)) rows = [rows];
27
- rows.forEach(row => {
27
+ for (const row of rows) {
28
28
  const inputConfigs = _findInputs(row);
29
29
  inputConfigs.forEach(config => {
30
30
  if (fields[config.formKey]) {
@@ -70,12 +70,9 @@ const _buildFormInitialValues = (rows = []) => {
70
70
  if (typeof fields[config.formKey][key] === 'undefined') delete fields[config.formKey][key];
71
71
  });
72
72
  });
73
- });
73
+ }
74
74
  return {
75
- state: {
76
- fields,
77
- loading: false
78
- },
75
+ fields: fields,
79
76
  key: generateId()
80
77
  };
81
78
  };
@@ -99,6 +96,26 @@ const _findValidityKey = validity => {
99
96
  }
100
97
  }
101
98
  };
99
+ const _checkTypeMismatch = input => {
100
+ var _input$value;
101
+ const value = (_input$value = input.value) === null || _input$value === void 0 ? void 0 : _input$value.toString().trim();
102
+ if (!value) return false;
103
+ switch (input.type) {
104
+ case 'email':
105
+ return !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
106
+ case 'url':
107
+ try {
108
+ new URL(value);
109
+ return false;
110
+ } catch (_unused) {
111
+ return true;
112
+ }
113
+ case 'tel':
114
+ return !/^\+?[0-9\s\-().]{7,}$/.test(value);
115
+ default:
116
+ return false;
117
+ }
118
+ };
102
119
  const hasSubmitter = form => {
103
120
  if (!form) return false;
104
121
  for (const element of form) {
@@ -106,14 +123,6 @@ const hasSubmitter = form => {
106
123
  }
107
124
  return false;
108
125
  };
109
- const _checkIfFormIsValid = fields => {
110
- for (const f in fields) {
111
- if (fields[f].error) {
112
- return false;
113
- }
114
- }
115
- return true;
116
- };
117
126
  const _toRawData = (fields, options = {}) => {
118
127
  const data = {};
119
128
  const {
@@ -134,39 +143,13 @@ const _toRawData = (fields, options = {}) => {
134
143
  for (const key in transform) {
135
144
  var _fields$key2;
136
145
  const set = transform[key];
137
- data[key] = set((_fields$key2 = fields[key]) === null || _fields$key2 === void 0 ? void 0 : _fields$key2.value);
146
+ data[key] = set(((_fields$key2 = fields[key]) === null || _fields$key2 === void 0 ? void 0 : _fields$key2.value) || fields[key]);
138
147
  }
139
148
  }
140
149
  return data;
141
150
  };
142
151
  const _toFormData = (form, options) => {
143
152
  if (!form) return new FormData();
144
- if (options) {
145
- const {
146
- exclude,
147
- include,
148
- transform
149
- } = options;
150
- let formData;
151
- if (include) {
152
- formData = new FormData();
153
- include.forEach(key => {
154
- var _form;
155
- return formData.set(key, (_form = form[key]) === null || _form === void 0 ? void 0 : _form.value);
156
- });
157
- } else {
158
- formData = new FormData(form);
159
- exclude === null || exclude === void 0 || exclude.forEach(key => formData.delete(key));
160
- }
161
- if (transform) {
162
- for (const key in transform) {
163
- var _form$key;
164
- const set = transform[key];
165
- formData.set(key, set((_form$key = form[key]) === null || _form$key === void 0 ? void 0 : _form$key.value));
166
- }
167
- }
168
- return formData;
169
- }
170
153
  return new FormData(form);
171
154
  };
172
155
  function _toURLSearchParams(options) {
@@ -269,9 +252,9 @@ class GValidator {
269
252
  const baseHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.handlers) || [];
270
253
  const baseConstraintHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.constraintHandlers) || [];
271
254
  const baseHandlersAsync = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.asyncHandlers) || [];
272
- this._handlers = new Array().concat(baseHandlers);
273
- this._constraintHandlers = new Array().concat(baseConstraintHandlers);
274
- this._asyncHandlers = new Array().concat(baseHandlersAsync);
255
+ this._handlers = [].concat(baseHandlers);
256
+ this._constraintHandlers = [].concat(baseConstraintHandlers);
257
+ this._asyncHandlers = [].concat(baseHandlersAsync);
275
258
  {
276
259
  this.track = [];
277
260
  if (baseValidator !== null && baseValidator !== void 0 && baseValidator.track) {
@@ -337,39 +320,13 @@ class GValidator {
337
320
  }
338
321
  }
339
322
 
340
- const useForm = (children, validators = {}, optimized = false) => {
341
- const initialValues = useMemo(() => {
342
- const values = _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
343
- {
344
- Object.keys(values.state.fields).forEach(key => {
345
- const input = values.state.fields[key];
346
- const validator = validators[key];
347
- if (validator instanceof GValidator) {
348
- var _validator$track;
349
- const validityKeys = (_validator$track = validator.track) === null || _validator$track === void 0 ? void 0 : _validator$track.filter(key => validityMap[key]);
350
- validityKeys === null || validityKeys === void 0 || validityKeys.forEach(vKey => {
351
- if (typeof input[validityMap[vKey]] === 'undefined') {
352
- console.warn(`[Missing Prop] - the input '${input.formKey}' has registered validator for the violation '${vKey}' but the input hasn't described the constraint '${validityMap[vKey]}'.\nadd '${validityMap[vKey]}' to the input props.\nexample:\n<GInput formKey='${input.formKey}' ${validityMap[vKey]}={...} />\n\nor either remove '.${handlersMap[validityMap[vKey]]}(...)' validation`);
353
- }
354
- });
355
- Object.entries(validityMap).forEach(([validityKey, constraint]) => {
356
- var _validator$track2;
357
- if (typeof input[constraint] !== 'undefined' && !((_validator$track2 = validator.track) !== null && _validator$track2 !== void 0 && _validator$track2.some(trackKey => validityKey === trackKey))) {
358
- console.warn(`[Missing Validator] - the input '${input.formKey}' has described the constraint '${constraint}' but the input hasn't registered a validator to handle it.\nregister a handler '${handlersMap[constraint]}' for the input validator to handle the '${validityKey}' violation.\nexample:\ncosnt validators = {\n\t${input.formKey}: new GValidator().${handlersMap[constraint]}(...)\n}`);
359
- }
360
- });
361
- }
362
- });
363
- }
364
- return values;
365
- }, []);
366
- const [state, setState] = useState(initialValues.state);
323
+ const useFormHandlers = (getState, setState, validators = {}, optimized = false) => {
367
324
  const _viHandler = (input, e) => {
368
325
  if (!input) return;
369
326
  const element = e && e.target;
370
327
  if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
371
328
  if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
372
- if (!input.dirty && input.value) {
329
+ if (!input.dirty && input.value && !input.touched) {
373
330
  _checkInputManually(input);
374
331
  _dispatchChanges(input, input.formKey);
375
332
  return;
@@ -390,6 +347,7 @@ const useForm = (children, validators = {}, optimized = false) => {
390
347
  const _checkInputManually = input => {
391
348
  let validityKey = _findValidityKey({
392
349
  valueMissing: input.required && !input.value || false,
350
+ typeMismatch: _checkTypeMismatch(input),
393
351
  tooShort: input.minLength && input.value.toString().length < input.minLength || false,
394
352
  tooLong: input.maxLength && input.value.toString().length > input.maxLength || false,
395
353
  patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
@@ -402,22 +360,17 @@ const useForm = (children, validators = {}, optimized = false) => {
402
360
  _validateInput(input, validityKey);
403
361
  return !input.error;
404
362
  };
405
- const _updateInputHandler = (key, e, unknown) => {
406
- const value = _extractValue(e, unknown);
407
- const input = _updateInput(key, value);
363
+ const _updateInputHandler = (input, e, unknown) => {
364
+ input.value = _extractValue(e, unknown);
408
365
  _viHandler(input, e);
409
366
  };
410
367
  const _validateInput = (input, validityKey, setValidity) => {
411
368
  const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
412
- inputValidator && __validateInput(input, inputValidator, validityKey, setValidity);
369
+ if (inputValidator) {
370
+ __validateInput(input, inputValidator, validityKey, setValidity);
371
+ }
413
372
  input.touched = true;
414
373
  };
415
- const _updateInput = (key, value) => {
416
- const input = state.fields[key];
417
- input.value = value;
418
- input.dirty = true;
419
- return input;
420
- };
421
374
  const _dispatchChanges = (changes, key) => setState(prev => {
422
375
  if (key) {
423
376
  return _objectSpread(_objectSpread({}, prev), {}, {
@@ -429,13 +382,14 @@ const useForm = (children, validators = {}, optimized = false) => {
429
382
  return _objectSpread(_objectSpread({}, prev), changes);
430
383
  });
431
384
  const __validateInput = (input, inputValidator, validityKey, setValidity) => {
385
+ const fields = getState().fields;
432
386
  for (const index in inputValidator.constraintHandlers) {
433
387
  const result = inputValidator.constraintHandlers[index](input, validityKey);
434
388
  input.error = _checkResult(result, input.value);
435
389
  if (input.error) return;
436
390
  }
437
391
  for (const index in inputValidator.handlers) {
438
- const result = inputValidator.handlers[index](input, state.fields);
392
+ const result = inputValidator.handlers[index](input, fields);
439
393
  input.error = _checkResult(result, input.value);
440
394
  if (input.error) return;
441
395
  }
@@ -445,7 +399,7 @@ const useForm = (children, validators = {}, optimized = false) => {
445
399
  _debounce(input.debounce || 300, `${input.gid}-async`).then(() => {
446
400
  const validateAsync = async () => {
447
401
  for (const index in inputValidator.asyncHandlers) {
448
- const result = await inputValidator.asyncHandlers[index](input, state.fields);
402
+ const result = await inputValidator.asyncHandlers[index](input, fields);
449
403
  input.error = _checkResult(result, input.value);
450
404
  if (input.error) break;
451
405
  }
@@ -454,188 +408,265 @@ const useForm = (children, validators = {}, optimized = false) => {
454
408
  error: input.error,
455
409
  errorText: input.errorText
456
410
  }, input.formKey);
457
- setValidity && setValidity(input.errorText);
411
+ if (setValidity) {
412
+ setValidity(input.errorText);
413
+ }
458
414
  };
459
415
  validateAsync();
460
416
  });
461
417
  }
462
418
  };
463
419
  return {
464
- state,
465
420
  _updateInputHandler,
466
421
  _viHandler,
467
422
  _dispatchChanges,
468
423
  optimized,
469
- key: initialValues.key,
470
424
  _createInputChecker: _checkInputManually
471
425
  };
472
426
  };
473
427
 
474
- const gFormContext = createContext({
475
- state: {
476
- fields: {},
477
- loading: false
478
- },
479
- _updateInputHandler: () => null,
480
- _viHandler: () => null,
481
- _dispatchChanges: () => null,
482
- _createInputChecker: () => false,
483
- optimized: false,
484
- key: ''
428
+ const GFormContext = createContext({});
429
+ const GFormContextProvider = ({
430
+ children,
431
+ initialState,
432
+ validators,
433
+ optimized
434
+ }) => {
435
+ const stateRef = useRef(initialState);
436
+ const listeners = useRef(new Set());
437
+ const setState = useCallback(updater => {
438
+ stateRef.current = typeof updater === 'function' ? updater(stateRef.current) : updater;
439
+ listeners.current.forEach(l => l());
440
+ }, []);
441
+ const handlers = useFormHandlers(() => stateRef.current, setState, validators, optimized);
442
+ const getState = useCallback(() => stateRef.current, []);
443
+ const subscribe = useCallback(listener => {
444
+ listeners.current.add(listener);
445
+ return () => listeners.current.delete(listener);
446
+ }, []);
447
+ useEffect(() => {
448
+ for (const fieldKey in initialState.fields) {
449
+ initialState.fields[fieldKey].dispatchChanges = changes => handlers._dispatchChanges(changes, fieldKey);
450
+ }
451
+ }, []);
452
+ const store = useRef({
453
+ getState,
454
+ setState,
455
+ subscribe,
456
+ handlers
457
+ });
458
+ return React.createElement(GFormContext.Provider, {
459
+ value: store.current
460
+ }, children);
461
+ };
462
+ const useFormStore = () => {
463
+ const store = useContext(GFormContext);
464
+ if (!store) throw new Error('useGFormStore must be used within `GForm` component');
465
+ return store;
466
+ };
467
+ const useFormSelector = selector => {
468
+ const store = useFormStore();
469
+ return useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
470
+ };
471
+ function createSelector(selectors, combiner) {
472
+ let lastArgs = [];
473
+ let lastResult;
474
+ return state => {
475
+ const args = selectors.map(fn => fn(state));
476
+ if (lastArgs.length === args.length && args.every((val, i) => val === lastArgs[i])) {
477
+ return lastResult;
478
+ }
479
+ lastArgs = args;
480
+ lastResult = combiner(...args);
481
+ return lastResult;
482
+ };
483
+ }
484
+
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;
485
497
  });
486
- const useGenericFormContext = () => useContext(gFormContext);
487
- const GFormContextProvider = gFormContext.Provider;
488
498
 
489
- const _excluded$1 = ["loader", "stateRef", "onSubmit", "onChange", "onPaste", "children", "validators", "onInit", "optimized"];
490
- const GForm = (() => {
491
- return forwardRef((_ref, ref) => {
492
- let {
493
- loader = React.createElement("div", null, "loading"),
494
- stateRef,
495
- onSubmit,
496
- onChange,
497
- onPaste,
498
- children,
499
- validators,
500
- onInit,
501
- optimized
502
- } = _ref,
503
- rest = _objectWithoutProperties(_ref, _excluded$1);
504
- const formRef = useRef(null);
505
- const values = useForm(children, validators, optimized);
506
- const {
507
- state,
508
- _updateInputHandler,
509
- _viHandler,
510
- _dispatchChanges,
511
- key
512
- } = values;
513
- const refHandler = element => {
514
- if (ref) {
515
- if (typeof ref === 'function') {
516
- ref(element);
517
- } else {
518
- ref.current = element;
519
- }
499
+ const _excluded$1 = ["stateRef", "onSubmit", "onChange", "onPaste", "onKeyDown", "onKeyUp", "children", "onInit"],
500
+ _excluded2 = ["children", "validators", "optimized"];
501
+ const FormRenderer = forwardRef((_ref, ref) => {
502
+ let {
503
+ stateRef,
504
+ onSubmit,
505
+ onChange,
506
+ onPaste,
507
+ onKeyDown,
508
+ onKeyUp,
509
+ children,
510
+ onInit
511
+ } = _ref,
512
+ rest = _objectWithoutProperties(_ref, _excluded$1);
513
+ const formRef = useRef(null);
514
+ const {
515
+ getState,
516
+ handlers
517
+ } = useFormStore();
518
+ const isFormInvalid = useFormSelector(selectFirstInvalidField);
519
+ const refHandler = useCallback(element => {
520
+ if (ref) {
521
+ if (typeof ref === 'function') {
522
+ ref(element);
523
+ } else {
524
+ ref.current = element;
525
+ }
526
+ }
527
+ formRef.current = element;
528
+ }, [ref]);
529
+ const getFormState = useCallback(() => {
530
+ const fields = getState().fields;
531
+ const formState = _objectSpread(_objectSpread({}, fields), {}, {
532
+ isValid: !isFormInvalid,
533
+ isInvalid: isFormInvalid,
534
+ toRawData: options => _toRawData(fields, options),
535
+ toFormData: () => _toFormData(formRef.current),
536
+ toURLSearchParams: _toURLSearchParams,
537
+ checkValidity: function () {
538
+ this.isValid = formRef.current && formRef.current.checkValidity() || false;
539
+ this.isInvalid = !this.isValid;
540
+ return this.isValid;
541
+ },
542
+ dispatchChanges: changes => handlers._dispatchChanges({
543
+ fields: _merge({}, fields, changes)
544
+ })
545
+ });
546
+ if (stateRef) stateRef.current = formState;
547
+ return formState;
548
+ }, [isFormInvalid]);
549
+ const formComponent = useMemo(() => {
550
+ const state = getFormState();
551
+ const formChildren = typeof children === 'function' ? children(state) : children;
552
+ const _onSubmit = e => {
553
+ const state = getFormState();
554
+ if (state.isValid && onSubmit) {
555
+ onSubmit(state, e);
520
556
  }
521
- formRef.current = element;
522
557
  };
523
- const formState = useMemo(() => {
524
- const _isFormValid = _checkIfFormIsValid(state.fields);
525
- const formState = _objectSpread(_objectSpread({}, state.fields), {}, {
526
- isValid: _isFormValid,
527
- isInvalid: !_isFormValid,
528
- loading: state.loading,
529
- toRawData: options => _toRawData(state.fields, options),
530
- toFormData: () => _toFormData(formRef.current),
531
- toURLSearchParams: _toURLSearchParams,
532
- checkValidity: function () {
533
- this.isValid = formRef.current && formRef.current.checkValidity() || false;
534
- this.isInvalid = !this.isValid;
535
- return this.isValid;
536
- },
537
- setLoading: p => _dispatchChanges({
538
- loading: typeof p === 'function' ? p(state.loading) : p
539
- }),
540
- dispatchChanges: changes => _dispatchChanges({
541
- fields: _merge({}, state.fields, changes)
542
- })
543
- });
544
- if (stateRef) stateRef.current = formState;
545
- return formState;
546
- }, [state.fields]);
547
- const formComponent = useMemo(() => {
548
- const formChildren = typeof children === 'function' ? children(formState) : children;
549
- const _onSubmit = e => {
550
- e.preventDefault();
551
- if (formState.isValid && onSubmit) {
552
- onSubmit(formState, e);
553
- }
554
- };
555
- let _onPaste;
556
- if (onPaste) {
557
- _onPaste = e => onPaste(formState, e);
558
+ let _onPaste, _onChange, _onKeyDown, _onKeyUp;
559
+ if (onPaste) {
560
+ _onPaste = e => onPaste(state, e);
561
+ }
562
+ if (onKeyDown) {
563
+ _onKeyDown = e => onKeyDown(state, e);
564
+ }
565
+ if (onKeyUp) {
566
+ _onKeyUp = e => onKeyUp(state, e);
567
+ }
568
+ if (handlers.optimized) {
569
+ if (onChange) {
570
+ _onChange = (e, unknown) => {
571
+ handlers._updateInputHandler(state[e.target.name], e, unknown);
572
+ onChange(state, e);
573
+ };
574
+ } else {
575
+ _onChange = (e, unknown) => {
576
+ handlers._updateInputHandler(state[e.target.name], e, unknown);
577
+ };
558
578
  }
559
- return optimized ? React.createElement("form", _extends({}, rest, {
579
+ return React.createElement("form", _extends({}, rest, {
560
580
  ref: refHandler,
561
581
  onPaste: _onPaste,
562
- onBlur: e => {
563
- _viHandler(state.fields[e.target.name], e);
564
- },
582
+ onKeyDown: _onKeyDown,
583
+ onKeyUp: _onKeyUp,
584
+ onBlur: e => handlers._viHandler(state[e.target.name], e),
565
585
  onInvalid: e => {
566
586
  e.preventDefault();
567
- _viHandler(state.fields[e.target.name], e);
568
- },
569
- onChange: (e, unknown) => {
570
- _updateInputHandler(e.target.name, e, unknown);
571
- onChange && onChange(formState, e);
587
+ handlers._viHandler(state[e.target.name], e);
572
588
  },
589
+ onChange: _onChange,
573
590
  onSubmit: _onSubmit
574
- }), formChildren) : React.createElement("form", _extends({}, rest, {
575
- onChange: e => onChange && onChange(formState, e),
576
- ref: refHandler,
577
- onSubmit: _onSubmit,
578
- onPaste: _onPaste
579
591
  }), formChildren);
580
- }, [formState, children]);
581
- useEffect(() => {
582
- if (!hasSubmitter(formRef.current)) {
583
- 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`);
584
- }
585
- if (onInit) {
586
- const _handler = _c => _dispatchChanges({
587
- fields: _merge({}, state.fields, _c)
592
+ }
593
+ if (onChange) {
594
+ _onChange = e => onChange(state, e);
595
+ }
596
+ return React.createElement("form", _extends({}, rest, {
597
+ ref: refHandler,
598
+ onSubmit: _onSubmit,
599
+ onChange: _onChange,
600
+ onPaste: _onPaste,
601
+ onKeyDown: _onKeyDown,
602
+ onKeyUp: _onKeyUp
603
+ }), formChildren);
604
+ }, [children, getFormState]);
605
+ useEffect(() => {
606
+ const state = getFormState();
607
+ 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`);
609
+ }
610
+ if (onInit) {
611
+ const changes = onInit(state);
612
+ if (changes) {
613
+ const _handler = _c => handlers._dispatchChanges({
614
+ fields: _merge({}, state, _c)
588
615
  });
589
- const changes = onInit(formState);
590
- changes instanceof Promise ? changes.then(_handler) : _handler(changes);
616
+ if (changes instanceof Promise) {
617
+ changes.then(_handler);
618
+ } else _handler(changes);
591
619
  }
592
- const dipatchers = {};
593
- Object.values(state.fields).forEach(field => {
594
- dipatchers[field.formKey] = {
595
- dispatchChanges: changes => _dispatchChanges(changes, field.formKey)
596
- };
597
- if (!field.value) return;
598
- _viHandler(field);
599
- });
600
- _dispatchChanges({
601
- fields: _merge(dipatchers, state.fields)
602
- });
603
- }, []);
604
- return React.createElement(GFormContextProvider, {
605
- value: values,
606
- key: key
607
- }, state.loading ? loader : formComponent);
608
- });
609
- })();
620
+ }
621
+ const fields = getState().fields;
622
+ for (const fieldKey in fields) {
623
+ const field = fields[fieldKey];
624
+ if (!field.value) continue;
625
+ handlers._viHandler(field);
626
+ }
627
+ }, [getFormState]);
628
+ return formComponent;
629
+ });
630
+ const GForm = forwardRef((_ref2, ref) => {
631
+ let {
632
+ children,
633
+ validators,
634
+ optimized
635
+ } = _ref2,
636
+ props = _objectWithoutProperties(_ref2, _excluded2);
637
+ const initialState = useMemo(() => {
638
+ return _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
639
+ }, [children]);
640
+ return React.createElement(GFormContextProvider, {
641
+ key: initialState.key,
642
+ initialState: initialState,
643
+ validators: validators,
644
+ optimized: optimized
645
+ }, React.createElement(FormRenderer, _extends({
646
+ ref: ref
647
+ }, props), children));
648
+ });
610
649
 
611
- const _excluded = ["formKey", "element", "title", "type", "validatorKey", "fetch", "fetchDeps", "optimized", "defaultChecked", "defaultValue", "checked", "value", "debounce"];
612
- const GInput = forwardRef((_ref, ref) => {
650
+ const _excluded = ["formKey", "element", "title", "type", "fetch", "fetchDeps", "optimized", "debounce", "defaultChecked", "defaultValue", "checked", "validatorKey", "value"];
651
+ const _GInput = forwardRef((_ref, ref) => {
613
652
  let {
614
653
  formKey,
615
654
  element,
616
655
  title,
617
- type,
618
- validatorKey,
656
+ type = 'text',
619
657
  fetch,
620
- fetchDeps = [],
658
+ fetchDeps,
621
659
  optimized,
660
+ debounce = 300,
622
661
  defaultChecked,
623
662
  defaultValue,
624
663
  checked,
625
- value,
626
- debounce = 300
664
+ validatorKey,
665
+ value
627
666
  } = _ref,
628
667
  rest = _objectWithoutProperties(_ref, _excluded);
629
- const {
630
- state: {
631
- fields
632
- },
633
- _updateInputHandler,
634
- _dispatchChanges,
635
- optimized: formOptimized,
636
- _viHandler
637
- } = useGenericFormContext();
638
- const inputState = fields[formKey];
668
+ const inputState = useFormSelector(state => state.fields[formKey]);
669
+ const store = useFormStore();
639
670
  const _element = useMemo(() => {
640
671
  let value, checked;
641
672
  if (type === 'checkbox') checked = inputState.value || false;else value = inputState.value || '';
@@ -649,19 +680,26 @@ const GInput = forwardRef((_ref, ref) => {
649
680
  'aria-required': inputState.required,
650
681
  title: title || inputState.errorText
651
682
  });
652
- if (!formOptimized || !optimized) {
653
- _props.onBlur = e => {
654
- _viHandler(inputState, e);
655
- rest.onBlur && rest.onBlur(e);
683
+ if (!store.handlers.optimized || !optimized) {
684
+ _props.onBlur = rest.onBlur ? e => {
685
+ store.handlers._viHandler(inputState, e);
686
+ rest.onBlur(e);
687
+ } : e => {
688
+ store.handlers._viHandler(inputState, e);
656
689
  };
657
- _props.onInvalid = e => {
690
+ _props.onInvalid = rest.onInvalid ? e => {
691
+ e.preventDefault();
692
+ store.handlers._viHandler(inputState, e);
693
+ rest.onInvalid(e);
694
+ } : e => {
658
695
  e.preventDefault();
659
- _viHandler(inputState, e);
660
- rest.onInvalid && rest.onInvalid(e);
696
+ store.handlers._viHandler(inputState, e);
661
697
  };
662
- _props.onChange = (e, unknown) => {
663
- _updateInputHandler(formKey, e, unknown);
664
- rest.onChange && rest.onChange(e);
698
+ _props.onChange = rest.onChange ? (e, unknown) => {
699
+ store.handlers._updateInputHandler(inputState, e, unknown);
700
+ rest.onChange(e);
701
+ } : (e, unknown) => {
702
+ store.handlers._updateInputHandler(inputState, e, unknown);
665
703
  };
666
704
  }
667
705
  if (element) {
@@ -669,18 +707,23 @@ const GInput = forwardRef((_ref, ref) => {
669
707
  }
670
708
  return React.createElement("input", _props);
671
709
  }, [inputState, element]);
672
- const _fetchDeps = useMemo(() => fetchDeps.map(key => fields[key].value), [fields]);
710
+ const _fetchDeps = useFormSelector(makeSelectFields(fetchDeps));
711
+ const stableFetchDeps = useMemo(() => JSON.stringify(_fetchDeps), [_fetchDeps]);
673
712
  useEffect(() => {
674
713
  if (fetch) {
675
- inputState.dispatchChanges = changes => _dispatchChanges(changes, formKey);
676
714
  _debounce(debounce, `${inputState.gid}-fetch`).then(() => {
677
- const res = fetch(inputState, fields);
678
- res instanceof Promise ? res.then(state => state && _dispatchChanges(state, formKey)) : res && _dispatchChanges(res, formKey);
715
+ const res = fetch(inputState, store.getState().fields);
716
+ if (res instanceof Promise) {
717
+ res.then(state => state && store.handlers._dispatchChanges(state, formKey));
718
+ } else if (res) {
719
+ store.handlers._dispatchChanges(res, formKey);
720
+ }
679
721
  });
680
722
  }
681
- }, _fetchDeps);
723
+ }, [stableFetchDeps]);
682
724
  return _element;
683
725
  });
726
+ const GInput = memo(_GInput);
684
727
 
685
- export { GForm, GInput, GValidator };
728
+ export { GForm, GInput, GValidator, useFormSelector };
686
729
  //# sourceMappingURL=index.development.js.map