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.
- package/README.md +4 -3
- package/dist/cjs/gform-react.development.js +280 -238
- 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 +286 -243
- 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 +25 -12
- package/native/dist/cjs/gform-react-native.development.js +222 -284
- 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 +228 -288
- 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 +27 -24
|
@@ -2,7 +2,6 @@
|
|
|
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');
|
|
6
5
|
var reactNative = require('react-native');
|
|
7
6
|
|
|
8
7
|
const isObject = o => o && typeof o === 'object' && !Array.isArray(o);
|
|
@@ -25,7 +24,7 @@ const generateId = () => (+new Date()).toString(36) + (1 - Math.random()).toStri
|
|
|
25
24
|
const _buildFormInitialValues = (rows = []) => {
|
|
26
25
|
const fields = {};
|
|
27
26
|
if (!Array.isArray(rows)) rows = [rows];
|
|
28
|
-
|
|
27
|
+
for (const row of rows) {
|
|
29
28
|
const inputConfigs = _findInputs(row);
|
|
30
29
|
inputConfigs.forEach(config => {
|
|
31
30
|
if (fields[config.formKey]) {
|
|
@@ -71,12 +70,9 @@ const _buildFormInitialValues = (rows = []) => {
|
|
|
71
70
|
if (typeof fields[config.formKey][key] === 'undefined') delete fields[config.formKey][key];
|
|
72
71
|
});
|
|
73
72
|
});
|
|
74
|
-
}
|
|
73
|
+
}
|
|
75
74
|
return {
|
|
76
|
-
|
|
77
|
-
fields,
|
|
78
|
-
loading: false
|
|
79
|
-
},
|
|
75
|
+
fields: fields,
|
|
80
76
|
key: generateId()
|
|
81
77
|
};
|
|
82
78
|
};
|
|
@@ -100,13 +96,25 @@ const _findValidityKey = validity => {
|
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
};
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
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:
|
|
106
116
|
return false;
|
|
107
|
-
}
|
|
108
117
|
}
|
|
109
|
-
return true;
|
|
110
118
|
};
|
|
111
119
|
const _toRawData = (fields, options = {}) => {
|
|
112
120
|
const data = {};
|
|
@@ -128,7 +136,7 @@ const _toRawData = (fields, options = {}) => {
|
|
|
128
136
|
for (const key in transform) {
|
|
129
137
|
var _fields$key2;
|
|
130
138
|
const set = transform[key];
|
|
131
|
-
data[key] = set((_fields$key2 = fields[key]) === null || _fields$key2 === void 0 ? void 0 : _fields$key2.value);
|
|
139
|
+
data[key] = set(((_fields$key2 = fields[key]) === null || _fields$key2 === void 0 ? void 0 : _fields$key2.value) || fields[key]);
|
|
132
140
|
}
|
|
133
141
|
}
|
|
134
142
|
return data;
|
|
@@ -196,147 +204,13 @@ const _merge = (target = {}, ...nodes) => {
|
|
|
196
204
|
return _merge(target, ...nodes);
|
|
197
205
|
};
|
|
198
206
|
|
|
199
|
-
|
|
200
|
-
let validityMap;
|
|
201
|
-
{
|
|
202
|
-
handlersMap = {
|
|
203
|
-
minLength: 'withMinLengthMessage',
|
|
204
|
-
maxLength: 'withMaxLengthMessage',
|
|
205
|
-
required: 'withRequiredMessage',
|
|
206
|
-
pattern: 'withPatternMismatchMessage',
|
|
207
|
-
min: 'withRangeUnderflowMessage',
|
|
208
|
-
max: 'withRangeOverflowMessage',
|
|
209
|
-
step: 'withStepMismatchMessage'
|
|
210
|
-
};
|
|
211
|
-
validityMap = {
|
|
212
|
-
tooShort: 'minLength',
|
|
213
|
-
valueMissing: 'required',
|
|
214
|
-
tooLong: 'maxLength',
|
|
215
|
-
patternMismatch: 'pattern',
|
|
216
|
-
rangeOverflow: 'max',
|
|
217
|
-
rangeUnderflow: 'min',
|
|
218
|
-
stepMismatch: 'step'
|
|
219
|
-
};
|
|
220
|
-
}
|
|
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 = new Array().concat(baseHandlers);
|
|
240
|
-
this._constraintHandlers = new Array().concat(baseConstraintHandlers);
|
|
241
|
-
this._asyncHandlers = new Array().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
|
-
|
|
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);
|
|
207
|
+
const useFormHandlers = (getState, setState, validators = {}, optimized = false) => {
|
|
334
208
|
const _viHandler = (input, e) => {
|
|
335
209
|
if (!input) return;
|
|
336
210
|
const element = e && e.target;
|
|
337
211
|
if (typeof document !== 'undefined' && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) {
|
|
338
212
|
if (!input.checkValidity) input.checkValidity = () => element.checkValidity();
|
|
339
|
-
if (!input.dirty && input.value) {
|
|
213
|
+
if (!input.dirty && input.value && !input.touched) {
|
|
340
214
|
_checkInputManually(input);
|
|
341
215
|
_dispatchChanges(input, input.formKey);
|
|
342
216
|
return;
|
|
@@ -357,6 +231,7 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
357
231
|
const _checkInputManually = input => {
|
|
358
232
|
let validityKey = _findValidityKey({
|
|
359
233
|
valueMissing: input.required && !input.value || false,
|
|
234
|
+
typeMismatch: _checkTypeMismatch(input),
|
|
360
235
|
tooShort: input.minLength && input.value.toString().length < input.minLength || false,
|
|
361
236
|
tooLong: input.maxLength && input.value.toString().length > input.maxLength || false,
|
|
362
237
|
patternMismatch: input.pattern && _checkResult(input.pattern, input.value) || false,
|
|
@@ -369,22 +244,17 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
369
244
|
_validateInput(input, validityKey);
|
|
370
245
|
return !input.error;
|
|
371
246
|
};
|
|
372
|
-
const _updateInputHandler = (
|
|
373
|
-
|
|
374
|
-
const input = _updateInput(key, value);
|
|
247
|
+
const _updateInputHandler = (input, e, unknown) => {
|
|
248
|
+
input.value = _extractValue(e, unknown);
|
|
375
249
|
_viHandler(input, e);
|
|
376
250
|
};
|
|
377
251
|
const _validateInput = (input, validityKey, setValidity) => {
|
|
378
252
|
const inputValidator = validators[input.validatorKey || input.formKey] || validators['*'];
|
|
379
|
-
|
|
253
|
+
if (inputValidator) {
|
|
254
|
+
__validateInput(input, inputValidator, validityKey, setValidity);
|
|
255
|
+
}
|
|
380
256
|
input.touched = true;
|
|
381
257
|
};
|
|
382
|
-
const _updateInput = (key, value) => {
|
|
383
|
-
const input = state.fields[key];
|
|
384
|
-
input.value = value;
|
|
385
|
-
input.dirty = true;
|
|
386
|
-
return input;
|
|
387
|
-
};
|
|
388
258
|
const _dispatchChanges = (changes, key) => setState(prev => {
|
|
389
259
|
if (key) {
|
|
390
260
|
return {
|
|
@@ -404,13 +274,14 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
404
274
|
};
|
|
405
275
|
});
|
|
406
276
|
const __validateInput = (input, inputValidator, validityKey, setValidity) => {
|
|
277
|
+
const fields = getState().fields;
|
|
407
278
|
for (const index in inputValidator.constraintHandlers) {
|
|
408
279
|
const result = inputValidator.constraintHandlers[index](input, validityKey);
|
|
409
280
|
input.error = _checkResult(result, input.value);
|
|
410
281
|
if (input.error) return;
|
|
411
282
|
}
|
|
412
283
|
for (const index in inputValidator.handlers) {
|
|
413
|
-
const result = inputValidator.handlers[index](input,
|
|
284
|
+
const result = inputValidator.handlers[index](input, fields);
|
|
414
285
|
input.error = _checkResult(result, input.value);
|
|
415
286
|
if (input.error) return;
|
|
416
287
|
}
|
|
@@ -420,7 +291,7 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
420
291
|
_debounce(input.debounce || 300, `${input.gid}-async`).then(() => {
|
|
421
292
|
const validateAsync = async () => {
|
|
422
293
|
for (const index in inputValidator.asyncHandlers) {
|
|
423
|
-
const result = await inputValidator.asyncHandlers[index](input,
|
|
294
|
+
const result = await inputValidator.asyncHandlers[index](input, fields);
|
|
424
295
|
input.error = _checkResult(result, input.value);
|
|
425
296
|
if (input.error) break;
|
|
426
297
|
}
|
|
@@ -429,138 +300,202 @@ const useForm = (children, validators = {}, optimized = false) => {
|
|
|
429
300
|
error: input.error,
|
|
430
301
|
errorText: input.errorText
|
|
431
302
|
}, input.formKey);
|
|
432
|
-
|
|
303
|
+
if (setValidity) {
|
|
304
|
+
setValidity(input.errorText);
|
|
305
|
+
}
|
|
433
306
|
};
|
|
434
307
|
validateAsync();
|
|
435
308
|
});
|
|
436
309
|
}
|
|
437
310
|
};
|
|
438
311
|
return {
|
|
439
|
-
state,
|
|
440
312
|
_updateInputHandler,
|
|
441
313
|
_viHandler,
|
|
442
314
|
_dispatchChanges,
|
|
443
315
|
optimized,
|
|
444
|
-
key: initialValues.key,
|
|
445
316
|
_createInputChecker: _checkInputManually
|
|
446
317
|
};
|
|
447
318
|
};
|
|
448
319
|
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
320
|
+
const GFormContext = React.createContext({});
|
|
321
|
+
const GFormContextProvider = ({
|
|
322
|
+
children,
|
|
323
|
+
initialState,
|
|
324
|
+
validators,
|
|
325
|
+
optimized
|
|
326
|
+
}) => {
|
|
327
|
+
const stateRef = React.useRef(initialState);
|
|
328
|
+
const listeners = React.useRef(new Set());
|
|
329
|
+
const setState = React.useCallback(updater => {
|
|
330
|
+
stateRef.current = typeof updater === 'function' ? updater(stateRef.current) : updater;
|
|
331
|
+
listeners.current.forEach(l => l());
|
|
332
|
+
}, []);
|
|
333
|
+
const handlers = useFormHandlers(() => stateRef.current, setState, validators, optimized);
|
|
334
|
+
const getState = React.useCallback(() => stateRef.current, []);
|
|
335
|
+
const subscribe = React.useCallback(listener => {
|
|
336
|
+
listeners.current.add(listener);
|
|
337
|
+
return () => listeners.current.delete(listener);
|
|
338
|
+
}, []);
|
|
339
|
+
React.useEffect(() => {
|
|
340
|
+
for (const fieldKey in initialState.fields) {
|
|
341
|
+
initialState.fields[fieldKey].dispatchChanges = changes => handlers._dispatchChanges(changes, fieldKey);
|
|
342
|
+
}
|
|
343
|
+
}, []);
|
|
344
|
+
const store = React.useRef({
|
|
345
|
+
getState,
|
|
346
|
+
setState,
|
|
347
|
+
subscribe,
|
|
348
|
+
handlers
|
|
349
|
+
});
|
|
350
|
+
return React.createElement(GFormContext.Provider, {
|
|
351
|
+
value: store.current
|
|
352
|
+
}, children);
|
|
353
|
+
};
|
|
354
|
+
const useFormStore = () => {
|
|
355
|
+
const store = React.useContext(GFormContext);
|
|
356
|
+
if (!store) throw new Error('useGFormStore must be used within `GForm` component');
|
|
357
|
+
return store;
|
|
358
|
+
};
|
|
359
|
+
const useFormSelector = selector => {
|
|
360
|
+
const store = useFormStore();
|
|
361
|
+
return React.useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
|
|
362
|
+
};
|
|
363
|
+
function createSelector(selectors, combiner) {
|
|
364
|
+
let lastArgs = [];
|
|
365
|
+
let lastResult;
|
|
366
|
+
return state => {
|
|
367
|
+
const args = selectors.map(fn => fn(state));
|
|
368
|
+
if (lastArgs.length === args.length && args.every((val, i) => val === lastArgs[i])) {
|
|
369
|
+
return lastResult;
|
|
370
|
+
}
|
|
371
|
+
lastArgs = args;
|
|
372
|
+
lastResult = combiner(...args);
|
|
373
|
+
return lastResult;
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const selectFields = [state => state.fields];
|
|
378
|
+
const selectFirstInvalidField = createSelector(selectFields, fields => {
|
|
379
|
+
for (const f in fields) {
|
|
380
|
+
if (fields[f].error) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
});
|
|
386
|
+
const makeSelectFields = (keys = []) => createSelector(selectFields, fields => {
|
|
387
|
+
const selected = keys.map(key => fields[key]).filter(Boolean);
|
|
388
|
+
return selected.length ? selected : null;
|
|
460
389
|
});
|
|
461
|
-
const useGenericFormContext = () => React.useContext(gFormContext);
|
|
462
|
-
const GFormContextProvider = gFormContext.Provider;
|
|
463
390
|
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
-
}
|
|
391
|
+
const FormRenderer = React.forwardRef(({
|
|
392
|
+
stateRef,
|
|
393
|
+
children,
|
|
394
|
+
onInit,
|
|
395
|
+
el: El,
|
|
396
|
+
...rest
|
|
397
|
+
}, ref) => {
|
|
398
|
+
const {
|
|
399
|
+
getState,
|
|
400
|
+
handlers
|
|
401
|
+
} = useFormStore();
|
|
402
|
+
const isFormInvalid = useFormSelector(selectFirstInvalidField);
|
|
403
|
+
const getFormState = React.useCallback(() => {
|
|
404
|
+
const fields = getState().fields;
|
|
405
|
+
const formState = {
|
|
406
|
+
...fields,
|
|
407
|
+
isValid: !isFormInvalid,
|
|
408
|
+
isInvalid: isFormInvalid,
|
|
409
|
+
toRawData: options => _toRawData(fields, options),
|
|
410
|
+
toURLSearchParams: _toURLSearchParams,
|
|
411
|
+
checkValidity: () => {
|
|
412
|
+
for (const i in fields) {
|
|
413
|
+
const valid = fields[i].checkValidity();
|
|
414
|
+
if (!valid) {
|
|
415
|
+
return false;
|
|
496
416
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
417
|
+
}
|
|
418
|
+
return true;
|
|
419
|
+
},
|
|
420
|
+
dispatchChanges: changes => handlers._dispatchChanges({
|
|
421
|
+
fields: _merge({}, fields, changes)
|
|
422
|
+
})
|
|
423
|
+
};
|
|
424
|
+
if (stateRef) stateRef.current = formState;
|
|
425
|
+
return formState;
|
|
426
|
+
}, [isFormInvalid]);
|
|
427
|
+
const formComponent = React.useMemo(() => {
|
|
428
|
+
const state = getFormState();
|
|
429
|
+
const formChildren = typeof children === 'function' ? children(state) : children;
|
|
430
|
+
return React.createElement(El, _extends({}, rest, {
|
|
431
|
+
ref: ref
|
|
432
|
+
}), formChildren);
|
|
433
|
+
}, [getFormState, children]);
|
|
434
|
+
React.useEffect(() => {
|
|
435
|
+
const state = getFormState();
|
|
436
|
+
if (onInit) {
|
|
437
|
+
const changes = onInit(state);
|
|
438
|
+
if (changes) {
|
|
439
|
+
const _handler = _c => handlers._dispatchChanges({
|
|
440
|
+
fields: _merge({}, state, _c)
|
|
513
441
|
});
|
|
514
|
-
|
|
515
|
-
|
|
442
|
+
if (changes instanceof Promise) {
|
|
443
|
+
changes.then(_handler);
|
|
444
|
+
} else _handler(changes);
|
|
516
445
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
446
|
+
}
|
|
447
|
+
const dispatchers = {};
|
|
448
|
+
const fields = getState().fields;
|
|
449
|
+
for (const fieldKey in fields) {
|
|
450
|
+
dispatchers[fieldKey] = {
|
|
451
|
+
dispatchChanges: changes => handlers._dispatchChanges(changes, fieldKey),
|
|
452
|
+
checkValidity: () => {
|
|
453
|
+
const result = handlers._createInputChecker(state[fieldKey]);
|
|
454
|
+
handlers._dispatchChanges(state[fieldKey], fieldKey);
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
const field = fields[fieldKey];
|
|
459
|
+
if (!field.value) continue;
|
|
460
|
+
handlers._viHandler(field);
|
|
461
|
+
}
|
|
462
|
+
handlers._dispatchChanges({
|
|
463
|
+
fields: _merge(dispatchers, state)
|
|
464
|
+
});
|
|
465
|
+
}, [getFormState]);
|
|
466
|
+
return formComponent;
|
|
467
|
+
});
|
|
468
|
+
const RNGForm = React.forwardRef(({
|
|
469
|
+
children,
|
|
470
|
+
validators,
|
|
471
|
+
...props
|
|
472
|
+
}, ref) => {
|
|
473
|
+
const initialState = React.useMemo(() => {
|
|
474
|
+
return _buildFormInitialValues(typeof children === 'function' ? children({}) : children);
|
|
475
|
+
}, [children]);
|
|
476
|
+
return React.createElement(GFormContextProvider, {
|
|
477
|
+
key: initialState.key,
|
|
478
|
+
initialState: initialState,
|
|
479
|
+
validators: validators
|
|
480
|
+
}, React.createElement(FormRenderer, _extends({
|
|
481
|
+
ref: ref
|
|
482
|
+
}, props), children));
|
|
483
|
+
});
|
|
541
484
|
|
|
542
|
-
const
|
|
485
|
+
const _RNGInput = React.forwardRef(({
|
|
543
486
|
formKey,
|
|
544
487
|
element,
|
|
545
488
|
type,
|
|
546
|
-
validatorKey,
|
|
547
489
|
fetch,
|
|
548
|
-
fetchDeps
|
|
490
|
+
fetchDeps,
|
|
491
|
+
debounce = 300,
|
|
549
492
|
defaultValue,
|
|
493
|
+
validatorKey,
|
|
550
494
|
value,
|
|
551
|
-
debounce = 300,
|
|
552
495
|
...rest
|
|
553
496
|
}, ref) => {
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
fields
|
|
557
|
-
},
|
|
558
|
-
_updateInputHandler,
|
|
559
|
-
_dispatchChanges,
|
|
560
|
-
_viHandler,
|
|
561
|
-
_createInputChecker
|
|
562
|
-
} = useGenericFormContext();
|
|
563
|
-
const inputState = fields[formKey];
|
|
497
|
+
const inputState = useFormSelector(state => state.fields[formKey]);
|
|
498
|
+
const store = useFormStore();
|
|
564
499
|
const _element = React.useMemo(() => {
|
|
565
500
|
const value = inputState.value || '';
|
|
566
501
|
const _props = {
|
|
@@ -569,41 +504,44 @@ const RNGInput = React.forwardRef(({
|
|
|
569
504
|
inputMode: type,
|
|
570
505
|
ref
|
|
571
506
|
};
|
|
572
|
-
_props.onEndEditing = e => {
|
|
573
|
-
_viHandler(inputState);
|
|
574
|
-
rest.onEndEditing
|
|
507
|
+
_props.onEndEditing = rest.onEndEditing ? e => {
|
|
508
|
+
store.handlers._viHandler(inputState);
|
|
509
|
+
rest.onEndEditing(e);
|
|
510
|
+
} : () => {
|
|
511
|
+
store.handlers._viHandler(inputState);
|
|
575
512
|
};
|
|
576
|
-
_props.onChangeText = e => {
|
|
577
|
-
_updateInputHandler(
|
|
513
|
+
_props.onChangeText = rest.onChangeText ? e => {
|
|
514
|
+
store.handlers._updateInputHandler(inputState, undefined, {
|
|
515
|
+
value: e
|
|
516
|
+
});
|
|
517
|
+
rest.onChangeText(e);
|
|
518
|
+
} : e => {
|
|
519
|
+
store.handlers._updateInputHandler(inputState, undefined, {
|
|
578
520
|
value: e
|
|
579
521
|
});
|
|
580
|
-
rest.onChangeText && rest.onChangeText(e);
|
|
581
522
|
};
|
|
582
523
|
if (element) {
|
|
583
524
|
return element(inputState, _props);
|
|
584
525
|
}
|
|
585
526
|
return React.createElement(reactNative.TextInput, _props);
|
|
586
527
|
}, [inputState, element]);
|
|
587
|
-
const _fetchDeps =
|
|
588
|
-
React.
|
|
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
|
-
}, []);
|
|
528
|
+
const _fetchDeps = useFormSelector(makeSelectFields(fetchDeps));
|
|
529
|
+
const stableFetchDeps = React.useMemo(() => JSON.stringify(_fetchDeps), [_fetchDeps]);
|
|
597
530
|
React.useEffect(() => {
|
|
598
531
|
if (fetch) {
|
|
599
532
|
_debounce(debounce, `${inputState.gid}-fetch`).then(() => {
|
|
600
|
-
const res = fetch(inputState, fields);
|
|
601
|
-
res instanceof Promise
|
|
533
|
+
const res = fetch(inputState, store.getState().fields);
|
|
534
|
+
if (res instanceof Promise) {
|
|
535
|
+
res.then(state => state && store.handlers._dispatchChanges(state, formKey));
|
|
536
|
+
} else if (res) {
|
|
537
|
+
store.handlers._dispatchChanges(res, formKey);
|
|
538
|
+
}
|
|
602
539
|
});
|
|
603
540
|
}
|
|
604
|
-
},
|
|
541
|
+
}, [stableFetchDeps]);
|
|
605
542
|
return _element;
|
|
606
543
|
});
|
|
544
|
+
const RNGInput = React.memo(_RNGInput);
|
|
607
545
|
|
|
608
546
|
exports.RNGForm = RNGForm;
|
|
609
547
|
exports.RNGInput = RNGInput;
|