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.
- package/dist/cjs/gform-react.development.js +314 -213
- package/dist/cjs/gform-react.development.js.map +1 -1
- package/dist/cjs/gform-react.production.js +1 -1
- package/dist/cjs/gform-react.production.js.map +1 -1
- package/dist/esm/GForm.production.js +1 -1
- package/dist/esm/GForm.production.js.map +1 -1
- package/dist/esm/GInput.production.js +1 -1
- package/dist/esm/GInput.production.js.map +1 -1
- package/dist/esm/GValidator.production.js +1 -1
- package/dist/esm/GValidator.production.js.map +1 -1
- package/dist/esm/index.development.js +320 -218
- package/dist/esm/index.development.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/shared.production.js +1 -1
- package/dist/esm/shared.production.js.map +1 -1
- package/dist/index.d.ts +13 -13
- package/native/dist/cjs/gform-react-native.development.js +254 -264
- package/native/dist/cjs/gform-react-native.development.js.map +1 -1
- package/native/dist/cjs/gform-react-native.production.js +1 -1
- package/native/dist/cjs/gform-react-native.production.js.map +1 -1
- package/native/dist/esm/RNGForm.production.js +1 -1
- package/native/dist/esm/RNGForm.production.js.map +1 -1
- package/native/dist/esm/RNGInput.production.js +1 -1
- package/native/dist/esm/RNGInput.production.js.map +1 -1
- package/native/dist/esm/index.development.js +260 -268
- package/native/dist/esm/index.development.js.map +1 -1
- package/native/dist/esm/shared.production.js +1 -1
- package/native/dist/esm/shared.production.js.map +1 -1
- package/native/dist/index.d.ts +4 -8
- package/package.json +2 -2
|
@@ -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,
|
|
@@ -72,10 +72,7 @@ const _buildFormInitialValues = (rows = []) => {
|
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
return {
|
|
75
|
-
|
|
76
|
-
fields,
|
|
77
|
-
loading: false
|
|
78
|
-
},
|
|
75
|
+
fields: fields,
|
|
79
76
|
key: generateId()
|
|
80
77
|
};
|
|
81
78
|
};
|
|
@@ -92,13 +89,34 @@ const _findInputs = (root, total = []) => {
|
|
|
92
89
|
}
|
|
93
90
|
return _findInputs((_root$props2 = root.props) === null || _root$props2 === void 0 ? void 0 : _root$props2.children, total);
|
|
94
91
|
};
|
|
95
|
-
const _findValidityKey = validity => {
|
|
92
|
+
const _findValidityKey = (validity, exclude = []) => {
|
|
96
93
|
for (const key in validity) {
|
|
94
|
+
if (exclude.includes(key)) continue;
|
|
97
95
|
if (key !== 'valid' && validity[key]) {
|
|
98
96
|
return key;
|
|
99
97
|
}
|
|
100
98
|
}
|
|
101
99
|
};
|
|
100
|
+
const _checkTypeMismatch = input => {
|
|
101
|
+
var _input$value;
|
|
102
|
+
const value = (_input$value = input.value) === null || _input$value === void 0 ? void 0 : _input$value.toString().trim();
|
|
103
|
+
if (!value) return false;
|
|
104
|
+
switch (input.type) {
|
|
105
|
+
case 'email':
|
|
106
|
+
return !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
107
|
+
case 'url':
|
|
108
|
+
try {
|
|
109
|
+
new URL(value);
|
|
110
|
+
return false;
|
|
111
|
+
} catch {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
case 'tel':
|
|
115
|
+
return !/^\+?[0-9\s\-().]{7,}$/.test(value);
|
|
116
|
+
default:
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
102
120
|
const hasSubmitter = form => {
|
|
103
121
|
if (!form) return false;
|
|
104
122
|
for (const element of form) {
|
|
@@ -106,14 +124,6 @@ const hasSubmitter = form => {
|
|
|
106
124
|
}
|
|
107
125
|
return false;
|
|
108
126
|
};
|
|
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
127
|
const _toRawData = (fields, options = {}) => {
|
|
118
128
|
const data = {};
|
|
119
129
|
const {
|
|
@@ -216,7 +226,8 @@ let validityMap;
|
|
|
216
226
|
pattern: 'withPatternMismatchMessage',
|
|
217
227
|
min: 'withRangeUnderflowMessage',
|
|
218
228
|
max: 'withRangeOverflowMessage',
|
|
219
|
-
step: 'withStepMismatchMessage'
|
|
229
|
+
step: 'withStepMismatchMessage',
|
|
230
|
+
type: 'withTypeMismatchMessage'
|
|
220
231
|
};
|
|
221
232
|
validityMap = {
|
|
222
233
|
tooShort: 'minLength',
|
|
@@ -225,7 +236,8 @@ let validityMap;
|
|
|
225
236
|
patternMismatch: 'pattern',
|
|
226
237
|
rangeOverflow: 'max',
|
|
227
238
|
rangeUnderflow: 'min',
|
|
228
|
-
stepMismatch: 'step'
|
|
239
|
+
stepMismatch: 'step',
|
|
240
|
+
typeMismatch: 'type'
|
|
229
241
|
};
|
|
230
242
|
}
|
|
231
243
|
class GValidator {
|
|
@@ -256,6 +268,10 @@ class GValidator {
|
|
|
256
268
|
}
|
|
257
269
|
}
|
|
258
270
|
}
|
|
271
|
+
hasConstraint(constraint) {
|
|
272
|
+
var _this$track;
|
|
273
|
+
return ((_this$track = this.track) === null || _this$track === void 0 ? void 0 : _this$track.includes(constraint)) || false;
|
|
274
|
+
}
|
|
259
275
|
withRequiredMessage(message) {
|
|
260
276
|
return this.__addConstraintValidationHandler('valueMissing', message);
|
|
261
277
|
}
|
|
@@ -294,14 +310,14 @@ class GValidator {
|
|
|
294
310
|
__addConstraintValidationHandler(validityKey, message) {
|
|
295
311
|
if (this.track) {
|
|
296
312
|
if (this.track.includes(validityKey)) {
|
|
297
|
-
console.warn(`[Duplicate Handlers] - handler for '${validityKey}' has already been defined`);
|
|
313
|
+
console.warn(`DEV ONLY - [Duplicate Handlers] - handler for '${validityKey}' has already been defined`);
|
|
298
314
|
}
|
|
299
315
|
this.track.push(validityKey);
|
|
300
316
|
}
|
|
301
317
|
this._constraintHandlers.push((input, key) => {
|
|
302
318
|
{
|
|
303
319
|
if (validityKey && validityMap[validityKey] && typeof input[validityMap[validityKey]] === 'undefined') {
|
|
304
|
-
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`);
|
|
320
|
+
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`);
|
|
305
321
|
}
|
|
306
322
|
}
|
|
307
323
|
if (key === validityKey) {
|
|
@@ -314,45 +330,22 @@ class GValidator {
|
|
|
314
330
|
}
|
|
315
331
|
}
|
|
316
332
|
|
|
317
|
-
const
|
|
318
|
-
const initialValues = React.useMemo(() => {
|
|
319
|
-
const values = _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
|
|
320
|
-
{
|
|
321
|
-
Object.keys(values.state.fields).forEach(key => {
|
|
322
|
-
const input = values.state.fields[key];
|
|
323
|
-
const validator = validators[key];
|
|
324
|
-
if (validator instanceof GValidator) {
|
|
325
|
-
var _validator$track;
|
|
326
|
-
const validityKeys = (_validator$track = validator.track) === null || _validator$track === void 0 ? void 0 : _validator$track.filter(key => validityMap[key]);
|
|
327
|
-
validityKeys === null || validityKeys === void 0 || validityKeys.forEach(vKey => {
|
|
328
|
-
if (typeof input[validityMap[vKey]] === 'undefined') {
|
|
329
|
-
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`);
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
Object.entries(validityMap).forEach(([validityKey, constraint]) => {
|
|
333
|
-
var _validator$track2;
|
|
334
|
-
if (typeof input[constraint] !== 'undefined' && !((_validator$track2 = validator.track) !== null && _validator$track2 !== void 0 && _validator$track2.some(trackKey => validityKey === trackKey))) {
|
|
335
|
-
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}`);
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
return values;
|
|
342
|
-
}, []);
|
|
343
|
-
const [state, setState] = React.useState(initialValues.state);
|
|
333
|
+
const useFormHandlers = (getState, setState, validators = {}, optimized = false) => {
|
|
344
334
|
const _viHandler = (input, e) => {
|
|
345
335
|
if (!input) return;
|
|
346
336
|
const element = e && e.target;
|
|
337
|
+
const hasInitialValue = !input.dirty && input.value && !input.touched;
|
|
338
|
+
if (!element && !hasInitialValue) return;
|
|
347
339
|
if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
|
|
348
340
|
if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
|
|
349
|
-
if (
|
|
341
|
+
if (hasInitialValue) {
|
|
350
342
|
_checkInputManually(input);
|
|
351
343
|
_dispatchChanges(input, input.formKey);
|
|
352
344
|
return;
|
|
353
345
|
}
|
|
354
346
|
element.setCustomValidity('');
|
|
355
|
-
const
|
|
347
|
+
const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
|
|
348
|
+
const validityKey = _findValidityKey(element.validity, exclude);
|
|
356
349
|
_validateInput(input, validityKey, v => element.setCustomValidity(v));
|
|
357
350
|
if (!validityKey && input.error) {
|
|
358
351
|
element.setCustomValidity(input.errorText || 'error');
|
|
@@ -365,36 +358,38 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
365
358
|
}
|
|
366
359
|
};
|
|
367
360
|
const _checkInputManually = input => {
|
|
361
|
+
const exclude = input.type && (input.pattern || hasCustomValidation(input)) ? ['typeMismatch'] : [];
|
|
368
362
|
let validityKey = _findValidityKey({
|
|
369
363
|
valueMissing: input.required && !input.value || false,
|
|
364
|
+
typeMismatch: _checkTypeMismatch(input),
|
|
370
365
|
tooShort: input.minLength && input.value.toString().length < input.minLength || false,
|
|
371
366
|
tooLong: input.maxLength && input.value.toString().length > input.maxLength || false,
|
|
372
367
|
patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
|
|
373
368
|
rangeUnderflow: input.min && Number(input.value) < Number(input.min) || false,
|
|
374
369
|
rangeOverflow: input.max && Number(input.value) > Number(input.max) || false
|
|
375
|
-
});
|
|
370
|
+
}, exclude);
|
|
376
371
|
if (!validityKey && input.error) {
|
|
377
372
|
validityKey = 'customError';
|
|
378
373
|
}
|
|
379
374
|
_validateInput(input, validityKey);
|
|
380
375
|
return !input.error;
|
|
381
376
|
};
|
|
382
|
-
const _updateInputHandler = (
|
|
383
|
-
|
|
384
|
-
const input = _updateInput(key, value);
|
|
377
|
+
const _updateInputHandler = (input, e, unknown) => {
|
|
378
|
+
input.value = _extractValue(e, unknown);
|
|
385
379
|
_viHandler(input, e);
|
|
386
380
|
};
|
|
387
381
|
const _validateInput = (input, validityKey, setValidity) => {
|
|
388
382
|
const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
|
|
389
|
-
|
|
383
|
+
{
|
|
384
|
+
if (validityKey && !(inputValidator !== null && inputValidator !== void 0 && inputValidator.hasConstraint(validityKey))) {
|
|
385
|
+
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`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (inputValidator) {
|
|
389
|
+
__validateInput(input, inputValidator, validityKey, setValidity);
|
|
390
|
+
}
|
|
390
391
|
input.touched = true;
|
|
391
392
|
};
|
|
392
|
-
const _updateInput = (key, value) => {
|
|
393
|
-
const input = state.fields[key];
|
|
394
|
-
input.value = value;
|
|
395
|
-
input.dirty = true;
|
|
396
|
-
return input;
|
|
397
|
-
};
|
|
398
393
|
const _dispatchChanges = (changes, key) => setState(prev => {
|
|
399
394
|
if (key) {
|
|
400
395
|
return {
|
|
@@ -414,13 +409,14 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
414
409
|
};
|
|
415
410
|
});
|
|
416
411
|
const __validateInput = (input, inputValidator, validityKey, setValidity) => {
|
|
412
|
+
const fields = getState().fields;
|
|
417
413
|
for (const index in inputValidator.constraintHandlers) {
|
|
418
414
|
const result = inputValidator.constraintHandlers[index](input, validityKey);
|
|
419
415
|
input.error = _checkResult(result, input.value);
|
|
420
416
|
if (input.error) return;
|
|
421
417
|
}
|
|
422
418
|
for (const index in inputValidator.handlers) {
|
|
423
|
-
const result = inputValidator.handlers[index](input,
|
|
419
|
+
const result = inputValidator.handlers[index](input, fields);
|
|
424
420
|
input.error = _checkResult(result, input.value);
|
|
425
421
|
if (input.error) return;
|
|
426
422
|
}
|
|
@@ -430,7 +426,7 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
430
426
|
_debounce(input.debounce || 300, `${input.gid}-async`).then(() => {
|
|
431
427
|
const validateAsync = async () => {
|
|
432
428
|
for (const index in inputValidator.asyncHandlers) {
|
|
433
|
-
const result = await inputValidator.asyncHandlers[index](input,
|
|
429
|
+
const result = await inputValidator.asyncHandlers[index](input, fields);
|
|
434
430
|
input.error = _checkResult(result, input.value);
|
|
435
431
|
if (input.error) break;
|
|
436
432
|
}
|
|
@@ -439,184 +435,264 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
439
435
|
error: input.error,
|
|
440
436
|
errorText: input.errorText
|
|
441
437
|
}, input.formKey);
|
|
442
|
-
|
|
438
|
+
if (setValidity) {
|
|
439
|
+
setValidity(input.errorText);
|
|
440
|
+
}
|
|
443
441
|
};
|
|
444
442
|
validateAsync();
|
|
445
443
|
});
|
|
446
444
|
}
|
|
447
445
|
};
|
|
446
|
+
const hasCustomValidation = input => {
|
|
447
|
+
const validator = validators[input.validatorKey || input.formKey] || validators['*'];
|
|
448
|
+
return validator && (validator.asyncHandlers.length > 0 || validator.handlers.length > 0);
|
|
449
|
+
};
|
|
448
450
|
return {
|
|
449
|
-
state,
|
|
450
451
|
_updateInputHandler,
|
|
451
452
|
_viHandler,
|
|
452
453
|
_dispatchChanges,
|
|
453
454
|
optimized,
|
|
454
|
-
key: initialValues.key,
|
|
455
455
|
_createInputChecker: _checkInputManually
|
|
456
456
|
};
|
|
457
457
|
};
|
|
458
458
|
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
459
|
+
const GFormContext = React.createContext({});
|
|
460
|
+
const GFormContextProvider = ({
|
|
461
|
+
children,
|
|
462
|
+
initialState,
|
|
463
|
+
validators,
|
|
464
|
+
optimized
|
|
465
|
+
}) => {
|
|
466
|
+
const stateRef = React.useRef(initialState);
|
|
467
|
+
const listeners = React.useRef(new Set());
|
|
468
|
+
const setState = React.useCallback(updater => {
|
|
469
|
+
stateRef.current = typeof updater === 'function' ? updater(stateRef.current) : updater;
|
|
470
|
+
listeners.current.forEach(l => l());
|
|
471
|
+
}, []);
|
|
472
|
+
const handlers = useFormHandlers(() => stateRef.current, setState, validators, optimized);
|
|
473
|
+
const getState = React.useCallback(() => stateRef.current, []);
|
|
474
|
+
const subscribe = React.useCallback(listener => {
|
|
475
|
+
listeners.current.add(listener);
|
|
476
|
+
return () => listeners.current.delete(listener);
|
|
477
|
+
}, []);
|
|
478
|
+
React.useEffect(() => {
|
|
479
|
+
for (const fieldKey in initialState.fields) {
|
|
480
|
+
initialState.fields[fieldKey].dispatchChanges = changes => handlers._dispatchChanges(changes, fieldKey);
|
|
481
|
+
}
|
|
482
|
+
}, []);
|
|
483
|
+
const store = React.useRef({
|
|
484
|
+
getState,
|
|
485
|
+
setState,
|
|
486
|
+
subscribe,
|
|
487
|
+
handlers
|
|
488
|
+
});
|
|
489
|
+
return React.createElement(GFormContext.Provider, {
|
|
490
|
+
value: store.current
|
|
491
|
+
}, children);
|
|
492
|
+
};
|
|
493
|
+
const useFormStore = () => {
|
|
494
|
+
const store = React.useContext(GFormContext);
|
|
495
|
+
if (!store) throw new Error('useGFormStore must be used within `GForm` component');
|
|
496
|
+
return store;
|
|
497
|
+
};
|
|
498
|
+
const useFormSelector = selector => {
|
|
499
|
+
const store = useFormStore();
|
|
500
|
+
return React.useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
|
|
501
|
+
};
|
|
502
|
+
function createSelector(selectors, combiner) {
|
|
503
|
+
let lastArgs = [];
|
|
504
|
+
let lastResult;
|
|
505
|
+
return state => {
|
|
506
|
+
const args = selectors.map(fn => fn(state));
|
|
507
|
+
if (lastArgs.length === args.length && args.every((val, i) => val === lastArgs[i])) {
|
|
508
|
+
return lastResult;
|
|
509
|
+
}
|
|
510
|
+
lastArgs = args;
|
|
511
|
+
lastResult = combiner(...args);
|
|
512
|
+
return lastResult;
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const selectFields = [state => state.fields];
|
|
517
|
+
const selectFirstInvalidField = createSelector(selectFields, fields => {
|
|
518
|
+
for (const f in fields) {
|
|
519
|
+
if (fields[f].error) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
});
|
|
525
|
+
const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
|
|
526
|
+
const selected = keys.map(key => fields[key]).filter(Boolean);
|
|
527
|
+
return selected.length ? selected : null;
|
|
470
528
|
});
|
|
471
|
-
const useGenericFormContext = () => React.useContext(gFormContext);
|
|
472
|
-
const GFormContextProvider = gFormContext.Provider;
|
|
473
529
|
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
530
|
+
const FormRenderer = React.forwardRef(({
|
|
531
|
+
stateRef,
|
|
532
|
+
onSubmit,
|
|
533
|
+
onChange,
|
|
534
|
+
onPaste,
|
|
535
|
+
onKeyDown,
|
|
536
|
+
onKeyUp,
|
|
537
|
+
children,
|
|
538
|
+
onInit,
|
|
539
|
+
...rest
|
|
540
|
+
}, ref) => {
|
|
541
|
+
const formRef = React.useRef(null);
|
|
542
|
+
const {
|
|
543
|
+
getState,
|
|
544
|
+
handlers
|
|
545
|
+
} = useFormStore();
|
|
546
|
+
const isFormInvalid = useFormSelector(selectFirstInvalidField);
|
|
547
|
+
const refHandler = React.useCallback(element => {
|
|
548
|
+
if (ref) {
|
|
549
|
+
if (typeof ref === 'function') {
|
|
550
|
+
ref(element);
|
|
551
|
+
} else {
|
|
552
|
+
ref.current = element;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
formRef.current = element;
|
|
556
|
+
}, [ref]);
|
|
557
|
+
const getFormState = React.useCallback(() => {
|
|
558
|
+
const fields = getState().fields;
|
|
559
|
+
const formState = {
|
|
560
|
+
...fields,
|
|
561
|
+
isValid: !isFormInvalid,
|
|
562
|
+
isInvalid: isFormInvalid,
|
|
563
|
+
toRawData: options => _toRawData(fields, options),
|
|
564
|
+
toFormData: () => _toFormData(formRef.current),
|
|
565
|
+
toURLSearchParams: _toURLSearchParams,
|
|
566
|
+
checkValidity: function () {
|
|
567
|
+
this.isValid = formRef.current && formRef.current.checkValidity() || false;
|
|
568
|
+
this.isInvalid = !this.isValid;
|
|
569
|
+
return this.isValid;
|
|
570
|
+
},
|
|
571
|
+
dispatchChanges: changes => handlers._dispatchChanges({
|
|
572
|
+
fields: _merge({}, fields, changes)
|
|
573
|
+
})
|
|
574
|
+
};
|
|
575
|
+
if (stateRef) stateRef.current = formState;
|
|
576
|
+
return formState;
|
|
577
|
+
}, [isFormInvalid]);
|
|
578
|
+
const formComponent = React.useMemo(() => {
|
|
579
|
+
const state = getFormState();
|
|
580
|
+
const formChildren = typeof children === 'function' ? children(state) : children;
|
|
581
|
+
const _onSubmit = e => {
|
|
582
|
+
const state = getFormState();
|
|
583
|
+
if (state.isValid && onSubmit) {
|
|
584
|
+
onSubmit(state, e);
|
|
503
585
|
}
|
|
504
|
-
formRef.current = element;
|
|
505
586
|
};
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
})
|
|
527
|
-
};
|
|
528
|
-
if (stateRef) stateRef.current = formState;
|
|
529
|
-
return formState;
|
|
530
|
-
}, [state.fields]);
|
|
531
|
-
const formComponent = React.useMemo(() => {
|
|
532
|
-
const formChildren = typeof children === 'function' ? children(formState) : children;
|
|
533
|
-
const _onSubmit = e => {
|
|
534
|
-
if (formState.isValid && onSubmit) {
|
|
535
|
-
onSubmit(formState, e);
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
let _onPaste;
|
|
539
|
-
if (onPaste) {
|
|
540
|
-
_onPaste = e => onPaste(formState, e);
|
|
587
|
+
let _onPaste, _onChange, _onKeyDown, _onKeyUp;
|
|
588
|
+
if (onPaste) {
|
|
589
|
+
_onPaste = e => onPaste(state, e);
|
|
590
|
+
}
|
|
591
|
+
if (onKeyDown) {
|
|
592
|
+
_onKeyDown = e => onKeyDown(state, e);
|
|
593
|
+
}
|
|
594
|
+
if (onKeyUp) {
|
|
595
|
+
_onKeyUp = e => onKeyUp(state, e);
|
|
596
|
+
}
|
|
597
|
+
if (handlers.optimized) {
|
|
598
|
+
if (onChange) {
|
|
599
|
+
_onChange = (e, unknown) => {
|
|
600
|
+
handlers._updateInputHandler(state[e.target.name], e, unknown);
|
|
601
|
+
onChange(state, e);
|
|
602
|
+
};
|
|
603
|
+
} else {
|
|
604
|
+
_onChange = (e, unknown) => {
|
|
605
|
+
handlers._updateInputHandler(state[e.target.name], e, unknown);
|
|
606
|
+
};
|
|
541
607
|
}
|
|
542
|
-
return
|
|
608
|
+
return React.createElement("form", _extends({}, rest, {
|
|
543
609
|
ref: refHandler,
|
|
544
610
|
onPaste: _onPaste,
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
611
|
+
onKeyDown: _onKeyDown,
|
|
612
|
+
onKeyUp: _onKeyUp,
|
|
613
|
+
onBlur: e => handlers._viHandler(state[e.target.name], e),
|
|
548
614
|
onInvalid: e => {
|
|
549
615
|
e.preventDefault();
|
|
550
|
-
_viHandler(state
|
|
551
|
-
},
|
|
552
|
-
onChange: (e, unknown) => {
|
|
553
|
-
_updateInputHandler(e.target.name, e, unknown);
|
|
554
|
-
onChange && onChange(formState, e);
|
|
616
|
+
handlers._viHandler(state[e.target.name], e);
|
|
555
617
|
},
|
|
618
|
+
onChange: _onChange,
|
|
556
619
|
onSubmit: _onSubmit
|
|
557
|
-
}), formChildren) : React.createElement("form", _extends({}, rest, {
|
|
558
|
-
onChange: e => onChange && onChange(formState, e),
|
|
559
|
-
ref: refHandler,
|
|
560
|
-
onSubmit: _onSubmit,
|
|
561
|
-
onPaste: _onPaste
|
|
562
620
|
}), formChildren);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
621
|
+
}
|
|
622
|
+
if (onChange) {
|
|
623
|
+
_onChange = e => onChange(state, e);
|
|
624
|
+
}
|
|
625
|
+
return React.createElement("form", _extends({}, rest, {
|
|
626
|
+
ref: refHandler,
|
|
627
|
+
onSubmit: _onSubmit,
|
|
628
|
+
onChange: _onChange,
|
|
629
|
+
onPaste: _onPaste,
|
|
630
|
+
onKeyDown: _onKeyDown,
|
|
631
|
+
onKeyUp: _onKeyUp
|
|
632
|
+
}), formChildren);
|
|
633
|
+
}, [children, getFormState]);
|
|
634
|
+
React.useEffect(() => {
|
|
635
|
+
const state = getFormState();
|
|
636
|
+
if (!hasSubmitter(formRef.current)) {
|
|
637
|
+
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`);
|
|
638
|
+
}
|
|
639
|
+
if (onInit) {
|
|
640
|
+
const changes = onInit(state);
|
|
641
|
+
if (changes) {
|
|
642
|
+
const _handler = _c => handlers._dispatchChanges({
|
|
643
|
+
fields: _merge({}, state, _c)
|
|
571
644
|
});
|
|
572
|
-
|
|
573
|
-
|
|
645
|
+
if (changes instanceof Promise) {
|
|
646
|
+
changes.then(_handler);
|
|
647
|
+
} else _handler(changes);
|
|
574
648
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
})
|
|
649
|
+
}
|
|
650
|
+
const fields = getState().fields;
|
|
651
|
+
for (const fieldKey in fields) {
|
|
652
|
+
const field = fields[fieldKey];
|
|
653
|
+
if (!field.value) continue;
|
|
654
|
+
handlers._viHandler(field);
|
|
655
|
+
}
|
|
656
|
+
}, [getFormState]);
|
|
657
|
+
return formComponent;
|
|
658
|
+
});
|
|
659
|
+
const GForm = React.forwardRef(({
|
|
660
|
+
children,
|
|
661
|
+
validators,
|
|
662
|
+
optimized,
|
|
663
|
+
...props
|
|
664
|
+
}, ref) => {
|
|
665
|
+
const initialState = React.useMemo(() => {
|
|
666
|
+
return _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
|
|
667
|
+
}, [children]);
|
|
668
|
+
return React.createElement(GFormContextProvider, {
|
|
669
|
+
key: initialState.key,
|
|
670
|
+
initialState: initialState,
|
|
671
|
+
validators: validators,
|
|
672
|
+
optimized: optimized
|
|
673
|
+
}, React.createElement(FormRenderer, _extends({
|
|
674
|
+
ref: ref
|
|
675
|
+
}, props), children));
|
|
676
|
+
});
|
|
593
677
|
|
|
594
|
-
const
|
|
678
|
+
const _GInput = React.forwardRef(({
|
|
595
679
|
formKey,
|
|
596
680
|
element,
|
|
597
681
|
title,
|
|
598
|
-
type,
|
|
599
|
-
validatorKey,
|
|
682
|
+
type = 'text',
|
|
600
683
|
fetch,
|
|
601
|
-
fetchDeps
|
|
684
|
+
fetchDeps,
|
|
602
685
|
optimized,
|
|
686
|
+
debounce = 300,
|
|
603
687
|
defaultChecked,
|
|
604
688
|
defaultValue,
|
|
605
689
|
checked,
|
|
690
|
+
validatorKey,
|
|
606
691
|
value,
|
|
607
|
-
debounce = 300,
|
|
608
692
|
...rest
|
|
609
693
|
}, ref) => {
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
fields
|
|
613
|
-
},
|
|
614
|
-
_updateInputHandler,
|
|
615
|
-
_dispatchChanges,
|
|
616
|
-
optimized: formOptimized,
|
|
617
|
-
_viHandler
|
|
618
|
-
} = useGenericFormContext();
|
|
619
|
-
const inputState = fields[formKey];
|
|
694
|
+
const inputState = useFormSelector(state => state.fields[formKey]);
|
|
695
|
+
const store = useFormStore();
|
|
620
696
|
const _element = React.useMemo(() => {
|
|
621
697
|
let value, checked;
|
|
622
698
|
if (type === 'checkbox') checked = inputState.value || false;else value = inputState.value || '';
|
|
@@ -631,40 +707,65 @@ const GInput = React.forwardRef(({
|
|
|
631
707
|
'aria-required': inputState.required,
|
|
632
708
|
title: title || inputState.errorText
|
|
633
709
|
};
|
|
634
|
-
if (!
|
|
635
|
-
_props.onBlur = e => {
|
|
636
|
-
_viHandler(inputState, e);
|
|
637
|
-
rest.onBlur
|
|
710
|
+
if (!store.handlers.optimized || !optimized) {
|
|
711
|
+
_props.onBlur = rest.onBlur ? e => {
|
|
712
|
+
store.handlers._viHandler(inputState, e);
|
|
713
|
+
rest.onBlur(e);
|
|
714
|
+
} : e => {
|
|
715
|
+
store.handlers._viHandler(inputState, e);
|
|
638
716
|
};
|
|
639
|
-
_props.onInvalid = e => {
|
|
717
|
+
_props.onInvalid = rest.onInvalid ? e => {
|
|
640
718
|
e.preventDefault();
|
|
641
|
-
_viHandler(inputState, e);
|
|
642
|
-
rest.onInvalid
|
|
719
|
+
store.handlers._viHandler(inputState, e);
|
|
720
|
+
rest.onInvalid(e);
|
|
721
|
+
} : e => {
|
|
722
|
+
e.preventDefault();
|
|
723
|
+
store.handlers._viHandler(inputState, e);
|
|
643
724
|
};
|
|
644
|
-
_props.onChange = (e, unknown) => {
|
|
645
|
-
_updateInputHandler(
|
|
646
|
-
rest.onChange
|
|
725
|
+
_props.onChange = rest.onChange ? (e, unknown) => {
|
|
726
|
+
store.handlers._updateInputHandler(inputState, e, unknown);
|
|
727
|
+
rest.onChange(e);
|
|
728
|
+
} : (e, unknown) => {
|
|
729
|
+
store.handlers._updateInputHandler(inputState, e, unknown);
|
|
647
730
|
};
|
|
731
|
+
if (!inputState.touched) {
|
|
732
|
+
_props.onFocus = rest.onFocus ? e => {
|
|
733
|
+
rest.onFocus(e);
|
|
734
|
+
inputState.dispatchChanges({
|
|
735
|
+
touched: true
|
|
736
|
+
});
|
|
737
|
+
} : () => {
|
|
738
|
+
inputState.dispatchChanges({
|
|
739
|
+
touched: true
|
|
740
|
+
});
|
|
741
|
+
};
|
|
742
|
+
}
|
|
648
743
|
}
|
|
649
744
|
if (element) {
|
|
650
745
|
return element(inputState, _props);
|
|
651
746
|
}
|
|
652
747
|
return React.createElement("input", _props);
|
|
653
748
|
}, [inputState, element]);
|
|
654
|
-
const _fetchDeps =
|
|
749
|
+
const _fetchDeps = useFormSelector(makeSelectFields(fetchDeps));
|
|
750
|
+
const stableFetchDeps = React.useMemo(() => JSON.stringify(_fetchDeps), [_fetchDeps]);
|
|
655
751
|
React.useEffect(() => {
|
|
656
752
|
if (fetch) {
|
|
657
|
-
inputState.dispatchChanges = changes => _dispatchChanges(changes, formKey);
|
|
658
753
|
_debounce(debounce, `${inputState.gid}-fetch`).then(() => {
|
|
659
|
-
const res = fetch(inputState, fields);
|
|
660
|
-
res instanceof Promise
|
|
754
|
+
const res = fetch(inputState, store.getState().fields);
|
|
755
|
+
if (res instanceof Promise) {
|
|
756
|
+
res.then(state => state && store.handlers._dispatchChanges(state, formKey));
|
|
757
|
+
} else if (res) {
|
|
758
|
+
store.handlers._dispatchChanges(res, formKey);
|
|
759
|
+
}
|
|
661
760
|
});
|
|
662
761
|
}
|
|
663
|
-
},
|
|
762
|
+
}, [stableFetchDeps]);
|
|
664
763
|
return _element;
|
|
665
764
|
});
|
|
765
|
+
const GInput = React.memo(_GInput);
|
|
666
766
|
|
|
667
767
|
exports.GForm = GForm;
|
|
668
768
|
exports.GInput = GInput;
|
|
669
769
|
exports.GValidator = GValidator;
|
|
770
|
+
exports.useFormSelector = useFormSelector;
|
|
670
771
|
//# sourceMappingURL=gform-react.development.js.map
|