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
@@ -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 {
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) {
@@ -272,9 +255,9 @@ class GValidator {
272
255
  const baseHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.handlers) || [];
273
256
  const baseConstraintHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.constraintHandlers) || [];
274
257
  const baseHandlersAsync = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.asyncHandlers) || [];
275
- this._handlers = new Array().concat(baseHandlers);
276
- this._constraintHandlers = new Array().concat(baseConstraintHandlers);
277
- this._asyncHandlers = new Array().concat(baseHandlersAsync);
258
+ this._handlers = [].concat(baseHandlers);
259
+ this._constraintHandlers = [].concat(baseConstraintHandlers);
260
+ this._asyncHandlers = [].concat(baseHandlersAsync);
278
261
  {
279
262
  this.track = [];
280
263
  if (baseValidator !== null && baseValidator !== void 0 && baseValidator.track) {
@@ -340,39 +323,13 @@ class GValidator {
340
323
  }
341
324
  }
342
325
 
343
- const useForm = (children, validators = {}, optimized = false) => {
344
- const initialValues = React.useMemo(() => {
345
- const values = _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
346
- {
347
- Object.keys(values.state.fields).forEach(key => {
348
- const input = values.state.fields[key];
349
- const validator = validators[key];
350
- if (validator instanceof GValidator) {
351
- var _validator$track;
352
- const validityKeys = (_validator$track = validator.track) === null || _validator$track === void 0 ? void 0 : _validator$track.filter(key => validityMap[key]);
353
- validityKeys === null || validityKeys === void 0 || validityKeys.forEach(vKey => {
354
- if (typeof input[validityMap[vKey]] === 'undefined') {
355
- 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`);
356
- }
357
- });
358
- Object.entries(validityMap).forEach(([validityKey, constraint]) => {
359
- var _validator$track2;
360
- if (typeof input[constraint] !== 'undefined' && !((_validator$track2 = validator.track) !== null && _validator$track2 !== void 0 && _validator$track2.some(trackKey => validityKey === trackKey))) {
361
- 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}`);
362
- }
363
- });
364
- }
365
- });
366
- }
367
- return values;
368
- }, []);
369
- const [state, setState] = React.useState(initialValues.state);
326
+ const useFormHandlers = (getState, setState, validators = {}, optimized = false) => {
370
327
  const _viHandler = (input, e) => {
371
328
  if (!input) return;
372
329
  const element = e && e.target;
373
330
  if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
374
331
  if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
375
- if (!input.dirty && input.value) {
332
+ if (!input.dirty && input.value && !input.touched) {
376
333
  _checkInputManually(input);
377
334
  _dispatchChanges(input, input.formKey);
378
335
  return;
@@ -393,6 +350,7 @@ const useForm = (children, validators = {}, optimized = false) => {
393
350
  const _checkInputManually = input => {
394
351
  let validityKey = _findValidityKey({
395
352
  valueMissing: input.required && !input.value || false,
353
+ typeMismatch: _checkTypeMismatch(input),
396
354
  tooShort: input.minLength && input.value.toString().length < input.minLength || false,
397
355
  tooLong: input.maxLength && input.value.toString().length > input.maxLength || false,
398
356
  patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
@@ -405,22 +363,17 @@ const useForm = (children, validators = {}, optimized = false) => {
405
363
  _validateInput(input, validityKey);
406
364
  return !input.error;
407
365
  };
408
- const _updateInputHandler = (key, e, unknown) => {
409
- const value = _extractValue(e, unknown);
410
- const input = _updateInput(key, value);
366
+ const _updateInputHandler = (input, e, unknown) => {
367
+ input.value = _extractValue(e, unknown);
411
368
  _viHandler(input, e);
412
369
  };
413
370
  const _validateInput = (input, validityKey, setValidity) => {
414
371
  const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
415
- inputValidator && __validateInput(input, inputValidator, validityKey, setValidity);
372
+ if (inputValidator) {
373
+ __validateInput(input, inputValidator, validityKey, setValidity);
374
+ }
416
375
  input.touched = true;
417
376
  };
418
- const _updateInput = (key, value) => {
419
- const input = state.fields[key];
420
- input.value = value;
421
- input.dirty = true;
422
- return input;
423
- };
424
377
  const _dispatchChanges = (changes, key) => setState(prev => {
425
378
  if (key) {
426
379
  return {
@@ -440,13 +393,14 @@ const useForm = (children, validators = {}, optimized = false) => {
440
393
  };
441
394
  });
442
395
  const __validateInput = (input, inputValidator, validityKey, setValidity) => {
396
+ const fields = getState().fields;
443
397
  for (const index in inputValidator.constraintHandlers) {
444
398
  const result = inputValidator.constraintHandlers[index](input, validityKey);
445
399
  input.error = _checkResult(result, input.value);
446
400
  if (input.error) return;
447
401
  }
448
402
  for (const index in inputValidator.handlers) {
449
- const result = inputValidator.handlers[index](input, state.fields);
403
+ const result = inputValidator.handlers[index](input, fields);
450
404
  input.error = _checkResult(result, input.value);
451
405
  if (input.error) return;
452
406
  }
@@ -456,7 +410,7 @@ const useForm = (children, validators = {}, optimized = false) => {
456
410
  _debounce(input.debounce || 300, `${input.gid}-async`).then(() => {
457
411
  const validateAsync = async () => {
458
412
  for (const index in inputValidator.asyncHandlers) {
459
- const result = await inputValidator.asyncHandlers[index](input, state.fields);
413
+ const result = await inputValidator.asyncHandlers[index](input, fields);
460
414
  input.error = _checkResult(result, input.value);
461
415
  if (input.error) break;
462
416
  }
@@ -465,185 +419,260 @@ const useForm = (children, validators = {}, optimized = false) => {
465
419
  error: input.error,
466
420
  errorText: input.errorText
467
421
  }, input.formKey);
468
- setValidity && setValidity(input.errorText);
422
+ if (setValidity) {
423
+ setValidity(input.errorText);
424
+ }
469
425
  };
470
426
  validateAsync();
471
427
  });
472
428
  }
473
429
  };
474
430
  return {
475
- state,
476
431
  _updateInputHandler,
477
432
  _viHandler,
478
433
  _dispatchChanges,
479
434
  optimized,
480
- key: initialValues.key,
481
435
  _createInputChecker: _checkInputManually
482
436
  };
483
437
  };
484
438
 
485
- const gFormContext = React.createContext({
486
- state: {
487
- fields: {},
488
- loading: false
489
- },
490
- _updateInputHandler: () => null,
491
- _viHandler: () => null,
492
- _dispatchChanges: () => null,
493
- _createInputChecker: () => false,
494
- optimized: false,
495
- key: ''
439
+ const GFormContext = React.createContext({});
440
+ const GFormContextProvider = ({
441
+ children,
442
+ initialState,
443
+ validators,
444
+ optimized
445
+ }) => {
446
+ const stateRef = React.useRef(initialState);
447
+ const listeners = React.useRef(new Set());
448
+ const setState = React.useCallback(updater => {
449
+ stateRef.current = typeof updater === 'function' ? updater(stateRef.current) : updater;
450
+ listeners.current.forEach(l => l());
451
+ }, []);
452
+ const handlers = useFormHandlers(() => stateRef.current, setState, validators, optimized);
453
+ const getState = React.useCallback(() => stateRef.current, []);
454
+ const subscribe = React.useCallback(listener => {
455
+ listeners.current.add(listener);
456
+ return () => listeners.current.delete(listener);
457
+ }, []);
458
+ React.useEffect(() => {
459
+ for (const fieldKey in initialState.fields) {
460
+ initialState.fields[fieldKey].dispatchChanges = changes => handlers._dispatchChanges(changes, fieldKey);
461
+ }
462
+ }, []);
463
+ const store = React.useRef({
464
+ getState,
465
+ setState,
466
+ subscribe,
467
+ handlers
468
+ });
469
+ return React.createElement(GFormContext.Provider, {
470
+ value: store.current
471
+ }, children);
472
+ };
473
+ const useFormStore = () => {
474
+ const store = React.useContext(GFormContext);
475
+ if (!store) throw new Error('useGFormStore must be used within `GForm` component');
476
+ return store;
477
+ };
478
+ const useFormSelector = selector => {
479
+ const store = useFormStore();
480
+ return React.useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
481
+ };
482
+ function createSelector(selectors, combiner) {
483
+ let lastArgs = [];
484
+ let lastResult;
485
+ return state => {
486
+ const args = selectors.map(fn => fn(state));
487
+ if (lastArgs.length === args.length && args.every((val, i) => val === lastArgs[i])) {
488
+ return lastResult;
489
+ }
490
+ lastArgs = args;
491
+ lastResult = combiner(...args);
492
+ return lastResult;
493
+ };
494
+ }
495
+
496
+ const selectFields = [state => state.fields];
497
+ const selectFirstInvalidField = createSelector(selectFields, fields => {
498
+ for (const f in fields) {
499
+ if (fields[f].error) {
500
+ return true;
501
+ }
502
+ }
503
+ return false;
504
+ });
505
+ const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
506
+ const selected = keys.map(key => fields[key]).filter(Boolean);
507
+ return selected.length ? selected : null;
496
508
  });
497
- const useGenericFormContext = () => React.useContext(gFormContext);
498
- const GFormContextProvider = gFormContext.Provider;
499
509
 
500
- const GForm = (() => {
501
- return React.forwardRef(({
502
- loader = React.createElement("div", null, "loading"),
503
- stateRef,
504
- onSubmit,
505
- onChange,
506
- onPaste,
507
- children,
508
- validators,
509
- onInit,
510
- optimized,
511
- ...rest
512
- }, ref) => {
513
- const formRef = React.useRef(null);
514
- const values = useForm(children, validators, optimized);
515
- const {
516
- state,
517
- _updateInputHandler,
518
- _viHandler,
519
- _dispatchChanges,
520
- key
521
- } = values;
522
- const refHandler = element => {
523
- if (ref) {
524
- if (typeof ref === 'function') {
525
- ref(element);
526
- } else {
527
- ref.current = element;
528
- }
510
+ const FormRenderer = React.forwardRef(({
511
+ stateRef,
512
+ onSubmit,
513
+ onChange,
514
+ onPaste,
515
+ onKeyDown,
516
+ onKeyUp,
517
+ children,
518
+ onInit,
519
+ ...rest
520
+ }, ref) => {
521
+ const formRef = React.useRef(null);
522
+ const {
523
+ getState,
524
+ handlers
525
+ } = useFormStore();
526
+ const isFormInvalid = useFormSelector(selectFirstInvalidField);
527
+ const refHandler = React.useCallback(element => {
528
+ if (ref) {
529
+ if (typeof ref === 'function') {
530
+ ref(element);
531
+ } else {
532
+ ref.current = element;
533
+ }
534
+ }
535
+ formRef.current = element;
536
+ }, [ref]);
537
+ const getFormState = React.useCallback(() => {
538
+ const fields = getState().fields;
539
+ const formState = {
540
+ ...fields,
541
+ isValid: !isFormInvalid,
542
+ isInvalid: isFormInvalid,
543
+ toRawData: options => _toRawData(fields, options),
544
+ toFormData: () => _toFormData(formRef.current),
545
+ toURLSearchParams: _toURLSearchParams,
546
+ checkValidity: function () {
547
+ this.isValid = formRef.current && formRef.current.checkValidity() || false;
548
+ this.isInvalid = !this.isValid;
549
+ return this.isValid;
550
+ },
551
+ dispatchChanges: changes => handlers._dispatchChanges({
552
+ fields: _merge({}, fields, changes)
553
+ })
554
+ };
555
+ if (stateRef) stateRef.current = formState;
556
+ return formState;
557
+ }, [isFormInvalid]);
558
+ const formComponent = React.useMemo(() => {
559
+ const state = getFormState();
560
+ const formChildren = typeof children === 'function' ? children(state) : children;
561
+ const _onSubmit = e => {
562
+ const state = getFormState();
563
+ if (state.isValid && onSubmit) {
564
+ onSubmit(state, e);
529
565
  }
530
- formRef.current = element;
531
566
  };
532
- const formState = React.useMemo(() => {
533
- const _isFormValid = _checkIfFormIsValid(state.fields);
534
- const formState = {
535
- ...state.fields,
536
- isValid: _isFormValid,
537
- isInvalid: !_isFormValid,
538
- loading: state.loading,
539
- toRawData: options => _toRawData(state.fields, options),
540
- toFormData: () => _toFormData(formRef.current),
541
- toURLSearchParams: _toURLSearchParams,
542
- checkValidity: function () {
543
- this.isValid = formRef.current && formRef.current.checkValidity() || false;
544
- this.isInvalid = !this.isValid;
545
- return this.isValid;
546
- },
547
- setLoading: p => _dispatchChanges({
548
- loading: typeof p === 'function' ? p(state.loading) : p
549
- }),
550
- dispatchChanges: changes => _dispatchChanges({
551
- fields: _merge({}, state.fields, changes)
552
- })
553
- };
554
- if (stateRef) stateRef.current = formState;
555
- return formState;
556
- }, [state.fields]);
557
- const formComponent = React.useMemo(() => {
558
- const formChildren = typeof children === 'function' ? children(formState) : children;
559
- const _onSubmit = e => {
560
- e.preventDefault();
561
- if (formState.isValid && onSubmit) {
562
- onSubmit(formState, e);
563
- }
564
- };
565
- let _onPaste;
566
- if (onPaste) {
567
- _onPaste = e => onPaste(formState, e);
567
+ let _onPaste, _onChange, _onKeyDown, _onKeyUp;
568
+ if (onPaste) {
569
+ _onPaste = e => onPaste(state, e);
570
+ }
571
+ if (onKeyDown) {
572
+ _onKeyDown = e => onKeyDown(state, e);
573
+ }
574
+ if (onKeyUp) {
575
+ _onKeyUp = e => onKeyUp(state, e);
576
+ }
577
+ if (handlers.optimized) {
578
+ if (onChange) {
579
+ _onChange = (e, unknown) => {
580
+ handlers._updateInputHandler(state[e.target.name], e, unknown);
581
+ onChange(state, e);
582
+ };
583
+ } else {
584
+ _onChange = (e, unknown) => {
585
+ handlers._updateInputHandler(state[e.target.name], e, unknown);
586
+ };
568
587
  }
569
- return optimized ? React.createElement("form", _extends({}, rest, {
588
+ return React.createElement("form", _extends({}, rest, {
570
589
  ref: refHandler,
571
590
  onPaste: _onPaste,
572
- onBlur: e => {
573
- _viHandler(state.fields[e.target.name], e);
574
- },
591
+ onKeyDown: _onKeyDown,
592
+ onKeyUp: _onKeyUp,
593
+ onBlur: e => handlers._viHandler(state[e.target.name], e),
575
594
  onInvalid: e => {
576
595
  e.preventDefault();
577
- _viHandler(state.fields[e.target.name], e);
578
- },
579
- onChange: (e, unknown) => {
580
- _updateInputHandler(e.target.name, e, unknown);
581
- onChange && onChange(formState, e);
596
+ handlers._viHandler(state[e.target.name], e);
582
597
  },
598
+ onChange: _onChange,
583
599
  onSubmit: _onSubmit
584
- }), formChildren) : React.createElement("form", _extends({}, rest, {
585
- onChange: e => onChange && onChange(formState, e),
586
- ref: refHandler,
587
- onSubmit: _onSubmit,
588
- onPaste: _onPaste
589
600
  }), formChildren);
590
- }, [formState, children]);
591
- React.useEffect(() => {
592
- if (!hasSubmitter(formRef.current)) {
593
- 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`);
594
- }
595
- if (onInit) {
596
- const _handler = _c => _dispatchChanges({
597
- fields: _merge({}, state.fields, _c)
601
+ }
602
+ if (onChange) {
603
+ _onChange = e => onChange(state, e);
604
+ }
605
+ return React.createElement("form", _extends({}, rest, {
606
+ ref: refHandler,
607
+ onSubmit: _onSubmit,
608
+ onChange: _onChange,
609
+ onPaste: _onPaste,
610
+ onKeyDown: _onKeyDown,
611
+ onKeyUp: _onKeyUp
612
+ }), formChildren);
613
+ }, [children, getFormState]);
614
+ React.useEffect(() => {
615
+ const state = getFormState();
616
+ if (!hasSubmitter(formRef.current)) {
617
+ 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`);
618
+ }
619
+ if (onInit) {
620
+ const changes = onInit(state);
621
+ if (changes) {
622
+ const _handler = _c => handlers._dispatchChanges({
623
+ fields: _merge({}, state, _c)
598
624
  });
599
- const changes = onInit(formState);
600
- changes instanceof Promise ? changes.then(_handler) : _handler(changes);
625
+ if (changes instanceof Promise) {
626
+ changes.then(_handler);
627
+ } else _handler(changes);
601
628
  }
602
- const dipatchers = {};
603
- Object.values(state.fields).forEach(field => {
604
- dipatchers[field.formKey] = {
605
- dispatchChanges: changes => _dispatchChanges(changes, field.formKey)
606
- };
607
- if (!field.value) return;
608
- _viHandler(field);
609
- });
610
- _dispatchChanges({
611
- fields: _merge(dipatchers, state.fields)
612
- });
613
- }, []);
614
- return React.createElement(GFormContextProvider, {
615
- value: values,
616
- key: key
617
- }, state.loading ? loader : formComponent);
618
- });
619
- })();
629
+ }
630
+ const fields = getState().fields;
631
+ for (const fieldKey in fields) {
632
+ const field = fields[fieldKey];
633
+ if (!field.value) continue;
634
+ handlers._viHandler(field);
635
+ }
636
+ }, [getFormState]);
637
+ return formComponent;
638
+ });
639
+ const GForm = React.forwardRef(({
640
+ children,
641
+ validators,
642
+ optimized,
643
+ ...props
644
+ }, ref) => {
645
+ const initialState = React.useMemo(() => {
646
+ return _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
647
+ }, [children]);
648
+ return React.createElement(GFormContextProvider, {
649
+ key: initialState.key,
650
+ initialState: initialState,
651
+ validators: validators,
652
+ optimized: optimized
653
+ }, React.createElement(FormRenderer, _extends({
654
+ ref: ref
655
+ }, props), children));
656
+ });
620
657
 
621
- const GInput = React.forwardRef(({
658
+ const _GInput = React.forwardRef(({
622
659
  formKey,
623
660
  element,
624
661
  title,
625
- type,
626
- validatorKey,
662
+ type = 'text',
627
663
  fetch,
628
- fetchDeps = [],
664
+ fetchDeps,
629
665
  optimized,
666
+ debounce = 300,
630
667
  defaultChecked,
631
668
  defaultValue,
632
669
  checked,
670
+ validatorKey,
633
671
  value,
634
- debounce = 300,
635
672
  ...rest
636
673
  }, ref) => {
637
- const {
638
- state: {
639
- fields
640
- },
641
- _updateInputHandler,
642
- _dispatchChanges,
643
- optimized: formOptimized,
644
- _viHandler
645
- } = useGenericFormContext();
646
- const inputState = fields[formKey];
674
+ const inputState = useFormSelector(state => state.fields[formKey]);
675
+ const store = useFormStore();
647
676
  const _element = React.useMemo(() => {
648
677
  let value, checked;
649
678
  if (type === 'checkbox') checked = inputState.value || false;else value = inputState.value || '';
@@ -658,19 +687,26 @@ const GInput = React.forwardRef(({
658
687
  'aria-required': inputState.required,
659
688
  title: title || inputState.errorText
660
689
  };
661
- if (!formOptimized || !optimized) {
662
- _props.onBlur = e => {
663
- _viHandler(inputState, e);
664
- rest.onBlur && rest.onBlur(e);
690
+ if (!store.handlers.optimized || !optimized) {
691
+ _props.onBlur = rest.onBlur ? e => {
692
+ store.handlers._viHandler(inputState, e);
693
+ rest.onBlur(e);
694
+ } : e => {
695
+ store.handlers._viHandler(inputState, e);
665
696
  };
666
- _props.onInvalid = e => {
697
+ _props.onInvalid = rest.onInvalid ? e => {
698
+ e.preventDefault();
699
+ store.handlers._viHandler(inputState, e);
700
+ rest.onInvalid(e);
701
+ } : e => {
667
702
  e.preventDefault();
668
- _viHandler(inputState, e);
669
- rest.onInvalid && rest.onInvalid(e);
703
+ store.handlers._viHandler(inputState, e);
670
704
  };
671
- _props.onChange = (e, unknown) => {
672
- _updateInputHandler(formKey, e, unknown);
673
- rest.onChange && rest.onChange(e);
705
+ _props.onChange = rest.onChange ? (e, unknown) => {
706
+ store.handlers._updateInputHandler(inputState, e, unknown);
707
+ rest.onChange(e);
708
+ } : (e, unknown) => {
709
+ store.handlers._updateInputHandler(inputState, e, unknown);
674
710
  };
675
711
  }
676
712
  if (element) {
@@ -678,20 +714,26 @@ const GInput = React.forwardRef(({
678
714
  }
679
715
  return React.createElement("input", _props);
680
716
  }, [inputState, element]);
681
- const _fetchDeps = React.useMemo(() => fetchDeps.map(key => fields[key].value), [fields]);
717
+ const _fetchDeps = useFormSelector(makeSelectFields(fetchDeps));
718
+ const stableFetchDeps = React.useMemo(() => JSON.stringify(_fetchDeps), [_fetchDeps]);
682
719
  React.useEffect(() => {
683
720
  if (fetch) {
684
- inputState.dispatchChanges = changes => _dispatchChanges(changes, formKey);
685
721
  _debounce(debounce, `${inputState.gid}-fetch`).then(() => {
686
- const res = fetch(inputState, fields);
687
- res instanceof Promise ? res.then(state => state && _dispatchChanges(state, formKey)) : res && _dispatchChanges(res, formKey);
722
+ const res = fetch(inputState, store.getState().fields);
723
+ if (res instanceof Promise) {
724
+ res.then(state => state && store.handlers._dispatchChanges(state, formKey));
725
+ } else if (res) {
726
+ store.handlers._dispatchChanges(res, formKey);
727
+ }
688
728
  });
689
729
  }
690
- }, _fetchDeps);
730
+ }, [stableFetchDeps]);
691
731
  return _element;
692
732
  });
733
+ const GInput = React.memo(_GInput);
693
734
 
694
735
  exports.GForm = GForm;
695
736
  exports.GInput = GInput;
696
737
  exports.GValidator = GValidator;
738
+ exports.useFormSelector = useFormSelector;
697
739
  //# sourceMappingURL=gform-react.development.js.map