gform-react 2.0.1 → 2.5.2

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 (30) hide show
  1. package/dist/cjs/gform-react.development.js +314 -213
  2. package/dist/cjs/gform-react.development.js.map +1 -1
  3. package/dist/cjs/gform-react.production.js +1 -1
  4. package/dist/cjs/gform-react.production.js.map +1 -1
  5. package/dist/esm/GForm.production.js +1 -1
  6. package/dist/esm/GForm.production.js.map +1 -1
  7. package/dist/esm/GInput.production.js +1 -1
  8. package/dist/esm/GInput.production.js.map +1 -1
  9. package/dist/esm/GValidator.production.js +1 -1
  10. package/dist/esm/GValidator.production.js.map +1 -1
  11. package/dist/esm/index.development.js +320 -218
  12. package/dist/esm/index.development.js.map +1 -1
  13. package/dist/esm/index.js +2 -1
  14. package/dist/esm/shared.production.js +1 -1
  15. package/dist/esm/shared.production.js.map +1 -1
  16. package/dist/index.d.ts +13 -13
  17. package/native/dist/cjs/gform-react-native.development.js +254 -264
  18. package/native/dist/cjs/gform-react-native.development.js.map +1 -1
  19. package/native/dist/cjs/gform-react-native.production.js +1 -1
  20. package/native/dist/cjs/gform-react-native.production.js.map +1 -1
  21. package/native/dist/esm/RNGForm.production.js +1 -1
  22. package/native/dist/esm/RNGForm.production.js.map +1 -1
  23. package/native/dist/esm/RNGInput.production.js +1 -1
  24. package/native/dist/esm/RNGInput.production.js.map +1 -1
  25. package/native/dist/esm/index.development.js +260 -268
  26. package/native/dist/esm/index.development.js.map +1 -1
  27. package/native/dist/esm/shared.production.js +1 -1
  28. package/native/dist/esm/shared.production.js.map +1 -1
  29. package/native/dist/index.d.ts +4 -8
  30. package/package.json +2 -2
@@ -2,7 +2,7 @@
2
2
 
3
3
  var _extends = require('@babel/runtime/helpers/extends');
4
4
  var React = require('react');
5
- var _defineProperty = require('@babel/runtime/helpers/defineProperty');
5
+ require('@babel/runtime/helpers/defineProperty');
6
6
  var reactNative = require('react-native');
7
7
 
8
8
  const isObject = o => o && typeof o === 'object' && !Array.isArray(o);
@@ -29,7 +29,7 @@ const _buildFormInitialValues = (rows = []) => {
29
29
  const inputConfigs = _findInputs(row);
30
30
  inputConfigs.forEach(config => {
31
31
  if (fields[config.formKey]) {
32
- console.warn(`[Duplicate Keys] - field with key '${config.formKey}' has already been defined.`);
32
+ console.warn(`DEV ONLY - [Duplicate Keys] - field with key '${config.formKey}' has already been defined.`);
33
33
  }
34
34
  const {
35
35
  required = false,
@@ -73,10 +73,7 @@ const _buildFormInitialValues = (rows = []) => {
73
73
  });
74
74
  }
75
75
  return {
76
- state: {
77
- fields,
78
- loading: false
79
- },
76
+ fields: fields,
80
77
  key: generateId()
81
78
  };
82
79
  };
@@ -93,20 +90,33 @@ const _findInputs = (root, total = []) => {
93
90
  }
94
91
  return _findInputs((_root$props2 = root.props) === null || _root$props2 === void 0 ? void 0 : _root$props2.children, total);
95
92
  };
96
- const _findValidityKey = validity => {
93
+ const _findValidityKey = (validity, exclude = []) => {
97
94
  for (const key in validity) {
95
+ if (exclude.includes(key)) continue;
98
96
  if (key !== 'valid' && validity[key]) {
99
97
  return key;
100
98
  }
101
99
  }
102
100
  };
103
- const _checkIfFormIsValid = fields => {
104
- for (const f in fields) {
105
- if (fields[f].error) {
101
+ const _checkTypeMismatch = input => {
102
+ var _input$value;
103
+ const value = (_input$value = input.value) === null || _input$value === void 0 ? void 0 : _input$value.toString().trim();
104
+ if (!value) return false;
105
+ switch (input.type) {
106
+ case 'email':
107
+ return !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
108
+ case 'url':
109
+ try {
110
+ new URL(value);
111
+ return false;
112
+ } catch {
113
+ return true;
114
+ }
115
+ case 'tel':
116
+ return !/^\+?[0-9\s\-().]{7,}$/.test(value);
117
+ default:
106
118
  return false;
107
- }
108
119
  }
109
- return true;
110
120
  };
111
121
  const _toRawData = (fields, options = {}) => {
112
122
  const data = {};
@@ -206,7 +216,8 @@ let validityMap;
206
216
  pattern: 'withPatternMismatchMessage',
207
217
  min: 'withRangeUnderflowMessage',
208
218
  max: 'withRangeOverflowMessage',
209
- step: 'withStepMismatchMessage'
219
+ step: 'withStepMismatchMessage',
220
+ type: 'withTypeMismatchMessage'
210
221
  };
211
222
  validityMap = {
212
223
  tooShort: 'minLength',
@@ -215,134 +226,27 @@ let validityMap;
215
226
  patternMismatch: 'pattern',
216
227
  rangeOverflow: 'max',
217
228
  rangeUnderflow: 'min',
218
- stepMismatch: 'step'
229
+ stepMismatch: 'step',
230
+ typeMismatch: 'type'
219
231
  };
220
232
  }
221
- class GValidator {
222
- get handlers() {
223
- return this._handlers;
224
- }
225
- get constraintHandlers() {
226
- return this._constraintHandlers;
227
- }
228
- get asyncHandlers() {
229
- return this._asyncHandlers;
230
- }
231
- constructor(baseValidator) {
232
- _defineProperty(this, "_handlers", void 0);
233
- _defineProperty(this, "_constraintHandlers", void 0);
234
- _defineProperty(this, "_asyncHandlers", void 0);
235
- _defineProperty(this, "track", void 0);
236
- const baseHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.handlers) || [];
237
- const baseConstraintHandlers = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.constraintHandlers) || [];
238
- const baseHandlersAsync = (baseValidator === null || baseValidator === void 0 ? void 0 : baseValidator.asyncHandlers) || [];
239
- this._handlers = [].concat(baseHandlers);
240
- this._constraintHandlers = [].concat(baseConstraintHandlers);
241
- this._asyncHandlers = [].concat(baseHandlersAsync);
242
- {
243
- this.track = [];
244
- if (baseValidator !== null && baseValidator !== void 0 && baseValidator.track) {
245
- this.track = this.track.concat(baseValidator.track);
246
- }
247
- }
248
- }
249
- withRequiredMessage(message) {
250
- return this.__addConstraintValidationHandler('valueMissing', message);
251
- }
252
- withMaxLengthMessage(message) {
253
- return this.__addConstraintValidationHandler('tooLong', message);
254
- }
255
- withMinLengthMessage(message) {
256
- return this.__addConstraintValidationHandler('tooShort', message);
257
- }
258
- withPatternMismatchMessage(message) {
259
- return this.__addConstraintValidationHandler('patternMismatch', message);
260
- }
261
- withBadInputMessage(message) {
262
- return this.__addConstraintValidationHandler('badInput', message);
263
- }
264
- withRangeUnderflowMessage(message) {
265
- return this.__addConstraintValidationHandler('rangeUnderflow', message);
266
- }
267
- withRangeOverflowMessage(message) {
268
- return this.__addConstraintValidationHandler('rangeOverflow', message);
269
- }
270
- withTypeMismatchMessage(message) {
271
- return this.__addConstraintValidationHandler('typeMismatch', message);
272
- }
273
- withStepMismatchMessage(message) {
274
- return this.__addConstraintValidationHandler('stepMismatch', message);
275
- }
276
- withCustomValidation(handler) {
277
- this._handlers.push(handler);
278
- return this;
279
- }
280
- withCustomValidationAsync(handler) {
281
- this._asyncHandlers.push(handler);
282
- return this;
283
- }
284
- __addConstraintValidationHandler(validityKey, message) {
285
- if (this.track) {
286
- if (this.track.includes(validityKey)) {
287
- console.warn(`[Duplicate Handlers] - handler for '${validityKey}' has already been defined`);
288
- }
289
- this.track.push(validityKey);
290
- }
291
- this._constraintHandlers.push((input, key) => {
292
- {
293
- if (validityKey && validityMap[validityKey] && typeof input[validityMap[validityKey]] === 'undefined') {
294
- 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`);
295
- }
296
- }
297
- if (key === validityKey) {
298
- input.errorText = typeof message === 'string' ? message : message(input);
299
- return true;
300
- }
301
- return false;
302
- });
303
- return this;
304
- }
305
- }
306
233
 
307
- const useForm = (children, validators = {}, optimized = false) => {
308
- const initialValues = React.useMemo(() => {
309
- const values = _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
310
- {
311
- Object.keys(values.state.fields).forEach(key => {
312
- const input = values.state.fields[key];
313
- const validator = validators[key];
314
- if (validator instanceof GValidator) {
315
- var _validator$track;
316
- const validityKeys = (_validator$track = validator.track) === null || _validator$track === void 0 ? void 0 : _validator$track.filter(key => validityMap[key]);
317
- validityKeys === null || validityKeys === void 0 || validityKeys.forEach(vKey => {
318
- if (typeof input[validityMap[vKey]] === 'undefined') {
319
- 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`);
320
- }
321
- });
322
- Object.entries(validityMap).forEach(([validityKey, constraint]) => {
323
- var _validator$track2;
324
- if (typeof input[constraint] !== 'undefined' && !((_validator$track2 = validator.track) !== null && _validator$track2 !== void 0 && _validator$track2.some(trackKey => validityKey === trackKey))) {
325
- 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}`);
326
- }
327
- });
328
- }
329
- });
330
- }
331
- return values;
332
- }, []);
333
- const [state, setState] = React.useState(initialValues.state);
234
+ const useFormHandlers = (getState, setState, validators = {}, optimized = false) => {
334
235
  const _viHandler = (input, e) => {
335
236
  if (!input) return;
336
237
  const element = e && e.target;
238
+ const hasInitialValue = !input.dirty && input.value && !input.touched;
239
+ if (!element && !hasInitialValue) return;
337
240
  if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
338
241
  if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
339
- if (!input.dirty && input.value) {
242
+ if (hasInitialValue) {
340
243
  _checkInputManually(input);
341
244
  _dispatchChanges(input, input.formKey);
342
245
  return;
343
246
  }
344
247
  element.setCustomValidity('');
345
- const validityKey = _findValidityKey(element.validity);
248
+ const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
249
+ const validityKey = _findValidityKey(element.validity, exclude);
346
250
  _validateInput(input, validityKey, v => element.setCustomValidity(v));
347
251
  if (!validityKey && input.error) {
348
252
  element.setCustomValidity(input.errorText || 'error');
@@ -355,36 +259,38 @@ const useForm = (children, validators = {}, optimized = false) => {
355
259
  }
356
260
  };
357
261
  const _checkInputManually = input => {
262
+ const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
358
263
  let validityKey = _findValidityKey({
359
264
  valueMissing: input.required && !input.value || false,
265
+ typeMismatch: _checkTypeMismatch(input),
360
266
  tooShort: input.minLength && input.value.toString().length < input.minLength || false,
361
267
  tooLong: input.maxLength && input.value.toString().length > input.maxLength || false,
362
268
  patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
363
269
  rangeUnderflow: input.min && Number(input.value) < Number(input.min) || false,
364
270
  rangeOverflow: input.max && Number(input.value) > Number(input.max) || false
365
- });
271
+ }, exclude);
366
272
  if (!validityKey && input.error) {
367
273
  validityKey = 'customError';
368
274
  }
369
275
  _validateInput(input, validityKey);
370
276
  return !input.error;
371
277
  };
372
- const _updateInputHandler = (key, e, unknown) => {
373
- const value = _extractValue(e, unknown);
374
- const input = _updateInput(key, value);
278
+ const _updateInputHandler = (input, e, unknown) => {
279
+ input.value = _extractValue(e, unknown);
375
280
  _viHandler(input, e);
376
281
  };
377
282
  const _validateInput = (input, validityKey, setValidity) => {
378
283
  const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
379
- inputValidator && __validateInput(input, inputValidator, validityKey, setValidity);
284
+ {
285
+ if (validityKey && !(inputValidator !== null && inputValidator !== void 0 && inputValidator.hasConstraint(validityKey))) {
286
+ 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`);
287
+ }
288
+ }
289
+ if (inputValidator) {
290
+ __validateInput(input, inputValidator, validityKey, setValidity);
291
+ }
380
292
  input.touched = true;
381
293
  };
382
- const _updateInput = (key, value) => {
383
- const input = state.fields[key];
384
- input.value = value;
385
- input.dirty = true;
386
- return input;
387
- };
388
294
  const _dispatchChanges = (changes, key) => setState(prev => {
389
295
  if (key) {
390
296
  return {
@@ -404,13 +310,14 @@ const useForm = (children, validators = {}, optimized = false) => {
404
310
  };
405
311
  });
406
312
  const __validateInput = (input, inputValidator, validityKey, setValidity) => {
313
+ const fields = getState().fields;
407
314
  for (const index in inputValidator.constraintHandlers) {
408
315
  const result = inputValidator.constraintHandlers[index](input, validityKey);
409
316
  input.error = _checkResult(result, input.value);
410
317
  if (input.error) return;
411
318
  }
412
319
  for (const index in inputValidator.handlers) {
413
- const result = inputValidator.handlers[index](input, state.fields);
320
+ const result = inputValidator.handlers[index](input, fields);
414
321
  input.error = _checkResult(result, input.value);
415
322
  if (input.error) return;
416
323
  }
@@ -420,7 +327,7 @@ const useForm = (children, validators = {}, optimized = false) => {
420
327
  _debounce(input.debounce || 300, `${input.gid}-async`).then(() => {
421
328
  const validateAsync = async () => {
422
329
  for (const index in inputValidator.asyncHandlers) {
423
- const result = await inputValidator.asyncHandlers[index](input, state.fields);
330
+ const result = await inputValidator.asyncHandlers[index](input, fields);
424
331
  input.error = _checkResult(result, input.value);
425
332
  if (input.error) break;
426
333
  }
@@ -429,138 +336,206 @@ const useForm = (children, validators = {}, optimized = false) => {
429
336
  error: input.error,
430
337
  errorText: input.errorText
431
338
  }, input.formKey);
432
- setValidity && setValidity(input.errorText);
339
+ if (setValidity) {
340
+ setValidity(input.errorText);
341
+ }
433
342
  };
434
343
  validateAsync();
435
344
  });
436
345
  }
437
346
  };
347
+ const hasCustomValidation = input => {
348
+ const validator = validators[input.validatorKey || input.formKey] || validators['*'];
349
+ return validator && (validator.asyncHandlers.length > 0 || validator.handlers.length > 0);
350
+ };
438
351
  return {
439
- state,
440
352
  _updateInputHandler,
441
353
  _viHandler,
442
354
  _dispatchChanges,
443
355
  optimized,
444
- key: initialValues.key,
445
356
  _createInputChecker: _checkInputManually
446
357
  };
447
358
  };
448
359
 
449
- const gFormContext = React.createContext({
450
- state: {
451
- fields: {},
452
- loading: false
453
- },
454
- _updateInputHandler: () => null,
455
- _viHandler: () => null,
456
- _dispatchChanges: () => null,
457
- _createInputChecker: () => false,
458
- optimized: false,
459
- key: ''
360
+ const GFormContext = React.createContext({});
361
+ const GFormContextProvider = ({
362
+ children,
363
+ initialState,
364
+ validators,
365
+ optimized
366
+ }) => {
367
+ const stateRef = React.useRef(initialState);
368
+ const listeners = React.useRef(new Set());
369
+ const setState = React.useCallback(updater => {
370
+ stateRef.current = typeof updater === 'function' ? updater(stateRef.current) : updater;
371
+ listeners.current.forEach(l => l());
372
+ }, []);
373
+ const handlers = useFormHandlers(() => stateRef.current, setState, validators, optimized);
374
+ const getState = React.useCallback(() => stateRef.current, []);
375
+ const subscribe = React.useCallback(listener => {
376
+ listeners.current.add(listener);
377
+ return () => listeners.current.delete(listener);
378
+ }, []);
379
+ React.useEffect(() => {
380
+ for (const fieldKey in initialState.fields) {
381
+ initialState.fields[fieldKey].dispatchChanges = changes => handlers._dispatchChanges(changes, fieldKey);
382
+ }
383
+ }, []);
384
+ const store = React.useRef({
385
+ getState,
386
+ setState,
387
+ subscribe,
388
+ handlers
389
+ });
390
+ return React.createElement(GFormContext.Provider, {
391
+ value: store.current
392
+ }, children);
393
+ };
394
+ const useFormStore = () => {
395
+ const store = React.useContext(GFormContext);
396
+ if (!store) throw new Error('useGFormStore must be used within `GForm` component');
397
+ return store;
398
+ };
399
+ const useFormSelector = selector => {
400
+ const store = useFormStore();
401
+ return React.useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
402
+ };
403
+ function createSelector(selectors, combiner) {
404
+ let lastArgs = [];
405
+ let lastResult;
406
+ return state => {
407
+ const args = selectors.map(fn => fn(state));
408
+ if (lastArgs.length === args.length && args.every((val, i) => val === lastArgs[i])) {
409
+ return lastResult;
410
+ }
411
+ lastArgs = args;
412
+ lastResult = combiner(...args);
413
+ return lastResult;
414
+ };
415
+ }
416
+
417
+ const selectFields = [state => state.fields];
418
+ const selectFirstInvalidField = createSelector(selectFields, fields => {
419
+ for (const f in fields) {
420
+ if (fields[f].error) {
421
+ return true;
422
+ }
423
+ }
424
+ return false;
425
+ });
426
+ const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
427
+ const selected = keys.map(key => fields[key]).filter(Boolean);
428
+ return selected.length ? selected : null;
460
429
  });
461
- const useGenericFormContext = () => React.useContext(gFormContext);
462
- const GFormContextProvider = gFormContext.Provider;
463
430
 
464
- const RNGForm = (() => {
465
- return React.forwardRef(({
466
- loader = React.createElement("div", null, "loading"),
467
- stateRef,
468
- children,
469
- validators,
470
- onInit,
471
- el: El,
472
- ...rest
473
- }, ref) => {
474
- const values = useForm(children, validators);
475
- const {
476
- state,
477
- _dispatchChanges,
478
- key,
479
- _viHandler
480
- } = values;
481
- const formState = React.useMemo(() => {
482
- const _isFormValid = _checkIfFormIsValid(state.fields);
483
- const formState = {
484
- ...state.fields,
485
- isValid: _isFormValid,
486
- isInvalid: !_isFormValid,
487
- loading: state.loading,
488
- toRawData: options => _toRawData(state.fields, options),
489
- toURLSearchParams: _toURLSearchParams,
490
- checkValidity: () => {
491
- for (const i in state.fields) {
492
- const valid = state.fields[i].checkValidity();
493
- if (!valid) {
494
- return false;
495
- }
431
+ const FormRenderer = React.forwardRef(({
432
+ stateRef,
433
+ children,
434
+ onInit,
435
+ el: El,
436
+ ...rest
437
+ }, ref) => {
438
+ const {
439
+ getState,
440
+ handlers
441
+ } = useFormStore();
442
+ const isFormInvalid = useFormSelector(selectFirstInvalidField);
443
+ const getFormState = React.useCallback(() => {
444
+ const fields = getState().fields;
445
+ const formState = {
446
+ ...fields,
447
+ isValid: !isFormInvalid,
448
+ isInvalid: isFormInvalid,
449
+ toRawData: options => _toRawData(fields, options),
450
+ toURLSearchParams: _toURLSearchParams,
451
+ checkValidity: () => {
452
+ for (const i in fields) {
453
+ const valid = fields[i].checkValidity();
454
+ if (!valid) {
455
+ return false;
496
456
  }
497
- return true;
498
- },
499
- setLoading: p => _dispatchChanges({
500
- loading: typeof p === 'function' ? p(state.loading) : p
501
- }),
502
- dispatchChanges: changes => _dispatchChanges({
503
- fields: _merge({}, state.fields, changes)
504
- })
505
- };
506
- if (stateRef) stateRef.current = formState;
507
- return formState;
508
- }, [state.fields]);
509
- React.useEffect(() => {
510
- if (onInit) {
511
- const _handler = _c => _dispatchChanges({
512
- fields: _merge({}, state.fields, _c)
457
+ }
458
+ return true;
459
+ },
460
+ dispatchChanges: changes => handlers._dispatchChanges({
461
+ fields: _merge({}, fields, changes)
462
+ })
463
+ };
464
+ if (stateRef) stateRef.current = formState;
465
+ return formState;
466
+ }, [isFormInvalid]);
467
+ const formComponent = React.useMemo(() => {
468
+ const state = getFormState();
469
+ const formChildren = typeof children === 'function' ? children(state) : children;
470
+ return React.createElement(El, _extends({}, rest, {
471
+ ref: ref
472
+ }), formChildren);
473
+ }, [getFormState, children]);
474
+ React.useEffect(() => {
475
+ const state = getFormState();
476
+ if (onInit) {
477
+ const changes = onInit(state);
478
+ if (changes) {
479
+ const _handler = _c => handlers._dispatchChanges({
480
+ fields: _merge({}, state, _c)
513
481
  });
514
- const changes = onInit(formState);
515
- changes instanceof Promise ? changes.then(_handler) : _handler(changes);
482
+ if (changes instanceof Promise) {
483
+ changes.then(_handler);
484
+ } else _handler(changes);
516
485
  }
517
- const dipatchers = {};
518
- Object.values(state.fields).forEach(field => {
519
- dipatchers[field.formKey] = {
520
- dispatchChanges: changes => _dispatchChanges(changes, field.formKey)
521
- };
522
- if (!field.value) return;
523
- _viHandler(field);
524
- });
525
- _dispatchChanges({
526
- fields: _merge(dipatchers, state.fields)
527
- });
528
- }, []);
529
- const formComponent = React.useMemo(() => {
530
- const formChildren = typeof children === 'function' ? children(formState) : children;
531
- return React.createElement(El, _extends({}, rest, {
532
- ref: ref
533
- }), formChildren);
534
- }, [formState, children]);
535
- return React.createElement(GFormContextProvider, {
536
- value: values,
537
- key: key
538
- }, state.loading ? loader : formComponent);
539
- });
540
- })();
486
+ }
487
+ const dispatchers = {};
488
+ const fields = getState().fields;
489
+ for (const fieldKey in fields) {
490
+ dispatchers[fieldKey] = {
491
+ dispatchChanges: changes => handlers._dispatchChanges(changes, fieldKey),
492
+ checkValidity: () => {
493
+ const result = handlers._createInputChecker(state[fieldKey]);
494
+ handlers._dispatchChanges(state[fieldKey], fieldKey);
495
+ return result;
496
+ }
497
+ };
498
+ const field = fields[fieldKey];
499
+ if (!field.value) continue;
500
+ handlers._viHandler(field);
501
+ }
502
+ handlers._dispatchChanges({
503
+ fields: _merge(dispatchers, state)
504
+ });
505
+ }, [getFormState]);
506
+ return formComponent;
507
+ });
508
+ const RNGForm = React.forwardRef(({
509
+ children,
510
+ validators,
511
+ ...props
512
+ }, ref) => {
513
+ const initialState = React.useMemo(() => {
514
+ return _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
515
+ }, [children]);
516
+ return React.createElement(GFormContextProvider, {
517
+ key: initialState.key,
518
+ initialState: initialState,
519
+ validators: validators
520
+ }, React.createElement(FormRenderer, _extends({
521
+ ref: ref
522
+ }, props), children));
523
+ });
541
524
 
542
- const RNGInput = React.forwardRef(({
525
+ const _RNGInput = React.forwardRef(({
543
526
  formKey,
544
527
  element,
545
528
  type,
546
- validatorKey,
547
529
  fetch,
548
- fetchDeps = [],
530
+ fetchDeps,
531
+ debounce = 300,
549
532
  defaultValue,
533
+ validatorKey,
550
534
  value,
551
- debounce = 300,
552
535
  ...rest
553
536
  }, ref) => {
554
- const {
555
- state: {
556
- fields
557
- },
558
- _updateInputHandler,
559
- _dispatchChanges,
560
- _viHandler,
561
- _createInputChecker
562
- } = useGenericFormContext();
563
- const inputState = fields[formKey];
537
+ const inputState = useFormSelector(state => state.fields[formKey]);
538
+ const store = useFormStore();
564
539
  const _element = React.useMemo(() => {
565
540
  const value = inputState.value || '';
566
541
  const _props = {
@@ -569,41 +544,56 @@ const RNGInput = React.forwardRef(({
569
544
  inputMode: type,
570
545
  ref
571
546
  };
572
- _props.onEndEditing = e => {
573
- _viHandler(inputState);
574
- rest.onEndEditing && rest.onEndEditing(e);
547
+ _props.onEndEditing = rest.onEndEditing ? e => {
548
+ store.handlers._viHandler(inputState);
549
+ rest.onEndEditing(e);
550
+ } : () => {
551
+ store.handlers._viHandler(inputState);
575
552
  };
576
- _props.onChangeText = e => {
577
- _updateInputHandler(formKey, undefined, {
553
+ _props.onChangeText = rest.onChangeText ? e => {
554
+ store.handlers._updateInputHandler(inputState, undefined, {
555
+ value: e
556
+ });
557
+ rest.onChangeText(e);
558
+ } : e => {
559
+ store.handlers._updateInputHandler(inputState, undefined, {
578
560
  value: e
579
561
  });
580
- rest.onChangeText && rest.onChangeText(e);
581
562
  };
563
+ if (!inputState.touched) {
564
+ _props.onFocus = rest.onFocus ? e => {
565
+ rest.onFocus(e);
566
+ inputState.dispatchChanges({
567
+ touched: true
568
+ });
569
+ } : () => {
570
+ inputState.dispatchChanges({
571
+ touched: true
572
+ });
573
+ };
574
+ }
582
575
  if (element) {
583
576
  return element(inputState, _props);
584
577
  }
585
578
  return React.createElement(reactNative.TextInput, _props);
586
579
  }, [inputState, element]);
587
- const _fetchDeps = React.useMemo(() => fetchDeps.map(key => fields[key].value), [fields]);
588
- React.useEffect(() => {
589
- inputState.checkValidity = () => {
590
- const result = _createInputChecker(inputState);
591
- _dispatchChanges(inputState, formKey);
592
- return result;
593
- };
594
- inputState.dispatchChanges = changes => _dispatchChanges(changes, formKey);
595
- _dispatchChanges(inputState, formKey);
596
- }, []);
580
+ const _fetchDeps = useFormSelector(makeSelectFields(fetchDeps));
581
+ const stableFetchDeps = React.useMemo(() => JSON.stringify(_fetchDeps), [_fetchDeps]);
597
582
  React.useEffect(() => {
598
583
  if (fetch) {
599
584
  _debounce(debounce, `${inputState.gid}-fetch`).then(() => {
600
- const res = fetch(inputState, fields);
601
- res instanceof Promise ? res.then(state => state && _dispatchChanges(state, formKey)) : res && _dispatchChanges(res, formKey);
585
+ const res = fetch(inputState, store.getState().fields);
586
+ if (res instanceof Promise) {
587
+ res.then(state => state && store.handlers._dispatchChanges(state, formKey));
588
+ } else if (res) {
589
+ store.handlers._dispatchChanges(res, formKey);
590
+ }
602
591
  });
603
592
  }
604
- }, _fetchDeps);
593
+ }, [stableFetchDeps]);
605
594
  return _element;
606
595
  });
596
+ const RNGInput = React.memo(_RNGInput);
607
597
 
608
598
  exports.RNGForm = RNGForm;
609
599
  exports.RNGInput = RNGInput;