react-form
Advanced tools
Comparing version 4.0.0-alpha.11 to 4.0.0-alpha.12
@@ -282,4 +282,190 @@ import React from 'react'; | ||
var formContext = React.createContext(); | ||
function FormContextProvider(_ref) { | ||
var value = _ref.value, | ||
children = _ref.children; | ||
return React.createElement(formContext.Provider, { | ||
value: value | ||
}, children); | ||
} | ||
function useFormContext(manualFormContext) { | ||
var formApi = React.useContext(formContext); | ||
if (manualFormContext) { | ||
return manualFormContext; | ||
} | ||
if (!formApi) { | ||
throw new Error("You are trying to use the form API outside of a form!"); | ||
} | ||
return formApi; | ||
} | ||
function useFormElement(contextValue) { | ||
var FormRef = React.useRef(); | ||
var FormApiRef = React.useRef(); | ||
FormApiRef.current = contextValue; // Create a new form element | ||
if (!FormRef.current) { | ||
FormRef.current = function Form(_ref) { | ||
var children = _ref.children, | ||
noFormElement = _ref.noFormElement, | ||
rest = _objectWithoutProperties(_ref, ["children", "noFormElement"]); | ||
var _FormApiRef$current = FormApiRef.current, | ||
handleSubmit = _FormApiRef$current.handleSubmit, | ||
isSubmitting = _FormApiRef$current.meta.isSubmitting, | ||
debugForm = _FormApiRef$current.debugForm; | ||
return React.createElement(FormContextProvider, { | ||
value: FormApiRef.current | ||
}, noFormElement ? children : React.createElement("form", _extends({ | ||
onSubmit: handleSubmit, | ||
disabled: isSubmitting | ||
}, rest), children, debugForm ? React.createElement("div", { | ||
style: { | ||
margin: '2rem 0' | ||
} | ||
}, React.createElement("div", { | ||
style: { | ||
fontWeight: 'bolder' | ||
} | ||
}, "Form State"), React.createElement("pre", null, React.createElement("code", null, JSON.stringify(_objectSpread({}, FormApiRef.current, { | ||
formContext: undefined | ||
}), safeStringifyReplace(new Set()), 2)))) : null)); | ||
}; | ||
} // Return the form element | ||
return FormRef.current; | ||
} | ||
function safeStringifyReplace(set) { | ||
return function (key, value) { | ||
if (_typeof(value) === 'object' || Array.isArray(value)) { | ||
if (set.has(value)) { | ||
return '(circular value)'; | ||
} | ||
set.add(value); | ||
} | ||
return typeof value === 'function' ? undefined : value; | ||
}; | ||
} | ||
function splitFormProps(_ref) { | ||
var field = _ref.field, | ||
defaultValue = _ref.defaultValue, | ||
defaultIsTouched = _ref.defaultIsTouched, | ||
defaultError = _ref.defaultError, | ||
defaultMeta = _ref.defaultMeta, | ||
validatePristine = _ref.validatePristine, | ||
validate = _ref.validate, | ||
onSubmit = _ref.onSubmit, | ||
defaultValues = _ref.defaultValues, | ||
filterValue = _ref.filterValue, | ||
debugForm = _ref.debugForm, | ||
rest = _objectWithoutProperties(_ref, ["field", "defaultValue", "defaultIsTouched", "defaultError", "defaultMeta", "validatePristine", "validate", "onSubmit", "defaultValues", "filterValue", "debugForm"]); | ||
return [field, { | ||
defaultValue: defaultValue, | ||
defaultIsTouched: defaultIsTouched, | ||
defaultError: defaultError, | ||
defaultMeta: defaultMeta, | ||
validatePristine: validatePristine, | ||
validate: validate, | ||
onSubmit: onSubmit, | ||
defaultValues: defaultValues, | ||
filterValue: filterValue, | ||
debugForm: debugForm | ||
}, rest]; | ||
} // Utils | ||
function getBy(obj, path) { | ||
if (!path) { | ||
throw new Error('A path string is required to use getBy'); | ||
} | ||
var pathArray = makePathArray(path); | ||
var pathObj = pathArray; | ||
return pathObj.reduce(function (current, pathPart) { | ||
if (typeof current !== 'undefined') { | ||
return current[pathPart]; | ||
} | ||
return undefined; | ||
}, obj); | ||
} | ||
function setBy(obj, path, updater) { | ||
path = makePathArray(path); | ||
function doSet(parent) { | ||
if (!path.length) { | ||
return typeof updater === 'function' ? updater(parent) : updater; | ||
} | ||
var key = path.shift(); | ||
if (typeof key === 'string') { | ||
if (_typeof(parent) === 'object') { | ||
return _objectSpread({}, parent, _defineProperty({}, key, doSet(parent[key]))); | ||
} | ||
return _defineProperty({}, key, doSet()); | ||
} | ||
if (typeof key === 'number') { | ||
if (Array.isArray(parent)) { | ||
var prefix = parent.slice(0, key); | ||
return [].concat(_toConsumableArray(prefix.length ? prefix : new Array(key)), [doSet(parent[key])], _toConsumableArray(parent.slice(key + 1))); | ||
} | ||
return [].concat(_toConsumableArray(new Array(key)), [doSet()]); | ||
} | ||
throw new Error('Uh oh!'); | ||
} | ||
return doSet(obj); | ||
} | ||
function getFieldID(str) { | ||
return makePathArray(str).join('_'); | ||
} | ||
var reFindNumbers0 = /^(\d*)$/gm; | ||
var reFindNumbers1 = /\.(\d*)\./gm; | ||
var reFindNumbers2 = /^(\d*)\./gm; | ||
var reFindNumbers3 = /\.(\d*$)/gm; | ||
var reFindMultiplePeriods = /\.{2,}/gm; | ||
function makePathArray(str) { | ||
return str.replace('[', '').replace(']', '.').replace(reFindNumbers0, '__int__$1').replace(reFindNumbers1, '.__int__$1.').replace(reFindNumbers2, '__int__$1.').replace(reFindNumbers3, '.__int__$1').replace(reFindMultiplePeriods, '.').split('.').map(function (d) { | ||
if (d.indexOf('__int__') === 0) { | ||
return parseInt(d.substring('__int__'.length), 10); | ||
} | ||
return d; | ||
}); | ||
} | ||
function loopObject(obj, fn, callback) { | ||
Object.keys(obj).forEach(function (key) { | ||
callback(fn(obj[key], key), key); | ||
}); | ||
} | ||
function someObject(obj, fn) { | ||
var found = false; | ||
loopObject(obj, fn, function (result, key) { | ||
if (found) { | ||
return; | ||
} | ||
if (result) { | ||
found = true; | ||
} | ||
}); | ||
return found; | ||
} | ||
var defaultDefaultValue = {}; | ||
var uid = 0; | ||
@@ -322,18 +508,22 @@ function makeState(decor) { | ||
var _React$useState3 = React.useState(false), | ||
_React$useState4 = _slicedToArray(_React$useState3, 2), | ||
shouldResubmit = _React$useState4[0], | ||
setShouldResubmit = _React$useState4[1]; | ||
var apiRef = React.useRef(); | ||
var metaRef = React.useRef({}); | ||
var __fieldMetaRefsRef = React.useRef({}); | ||
var __fieldMetaRefsRef = React.useRef({}); // Keep validate up to date with the latest version | ||
var validateRef = React.useRef(); // Keep validate up to date with the latest version | ||
validateRef.current = validate; | ||
var allFieldsTouched = !someObject(__fieldMeta, function (field) { | ||
return field && !field.isTouched; | ||
metaRef.current.validate = validate; | ||
var fieldsAreValidating = someObject(__fieldMeta, function (field) { | ||
return field && field.isValidating; | ||
}); | ||
var allFieldsValid = !someObject(__fieldMeta, function (field) { | ||
var fieldsAreValid = !someObject(__fieldMeta, function (field) { | ||
return field && field.error; | ||
}); // Can we submit this form? | ||
var isValid = isTouched && allFieldsValid && !meta.error; | ||
var isValid = !fieldsAreValidating && fieldsAreValid && !meta.error; | ||
var canSubmit = isValid && !isSubmitting; // Decorate form meta | ||
@@ -343,8 +533,8 @@ | ||
return _objectSpread({}, meta, { | ||
fieldsAreValidating: fieldsAreValidating, | ||
fieldsAreValid: fieldsAreValid, | ||
isValid: isValid, | ||
canSubmit: canSubmit, | ||
allFieldsTouched: allFieldsTouched, | ||
allFieldsValid: allFieldsValid | ||
canSubmit: canSubmit | ||
}); | ||
}, [meta, isValid, canSubmit, allFieldsTouched, allFieldsValid]); // We want the apiRef to change every time state updates | ||
}, [meta, fieldsAreValidating, fieldsAreValid, isValid, canSubmit]); // We want the apiRef to change every time state updates | ||
@@ -371,95 +561,141 @@ var api = React.useMemo(function () { | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref2 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee(e) { | ||
var needTouchedAndValidation; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
e.persist(); | ||
e.preventDefault(); // This lets sub-forms with form elements (despite them being invalid HTML) | ||
// handle submissions without triggering parent forms | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee() { | ||
var e, | ||
needsResubmit, | ||
fieldValidationPromises, | ||
_args = arguments; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
e = _args.length > 0 && _args[0] !== undefined ? _args[0] : {}; | ||
if (e.persist) e.persist(); | ||
if (e.preventDefault) e.preventDefault(); // This lets sub-forms with form elements (despite them being invalid HTML) | ||
// handle submissions without triggering parent forms | ||
if (!e.__handled) { | ||
_context.next = 4; | ||
break; | ||
} | ||
if (!e.__handled) { | ||
_context.next = 5; | ||
break; | ||
} | ||
return _context.abrupt("return"); | ||
return _context.abrupt("return"); | ||
case 4: | ||
e.__handled = true; | ||
Object.keys(apiRef.current.__fieldMetaRefs).forEach(function (key) { | ||
var fieldMeta = apiRef.current.__fieldMetaRefs[key].current; | ||
Object.keys(fieldMeta.instanceRefs).forEach(function (key) { | ||
var fieldInstance = fieldMeta.instanceRefs[key].current; | ||
case 5: | ||
e.__handled = true; // Don't let invalid forms submit | ||
if (fieldInstance.__validate && !fieldInstance.meta.isTouched) { | ||
needTouchedAndValidation = true; | ||
fieldInstance.setMeta({ | ||
isTouched: true | ||
}); | ||
if (apiRef.current.meta.isValid) { | ||
_context.next = 9; | ||
break; | ||
} | ||
// If the form can't submit, let's trigger all of the fields | ||
// to be touched. Thus, their validations will run | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
}); | ||
return _context.abrupt("return"); | ||
case 9: | ||
apiRef.current.setMeta({ | ||
isSubmitting: true | ||
}); | ||
needsResubmit = false; | ||
fieldValidationPromises = []; | ||
Object.keys(apiRef.current.__fieldMetaRefs).forEach(function (key) { | ||
var fieldMeta = apiRef.current.__fieldMetaRefs[key].current; | ||
Object.keys(fieldMeta.instanceRefs).forEach(function (key) { | ||
var fieldInstance = fieldMeta.instanceRefs[key].current; // If any fields are not touched | ||
if (!fieldInstance.meta.isTouched) { | ||
// Mark them as touched | ||
fieldInstance.setMeta({ | ||
isTouched: true | ||
}); // Likewise, if they need validation | ||
if (fieldInstance.__validate) { | ||
// Run their validation and keep track of the | ||
// promise | ||
fieldValidationPromises.push(fieldInstance.runValidation()); | ||
} | ||
}); | ||
}); // Don't let invalid forms submit | ||
} | ||
}); | ||
}); // If any validation needed to be run | ||
if (!(!apiRef.current.meta.canSubmit || needTouchedAndValidation)) { | ||
_context.next = 8; | ||
break; | ||
} | ||
if (fieldValidationPromises.length) { | ||
// Mark for resubmission | ||
needsResubmit = true; | ||
} | ||
return _context.abrupt("return"); | ||
if (!apiRef.current.meta.isTouched) { | ||
// Mark for resubmission | ||
needsResubmit = true; // Mark the form as touched | ||
case 8: | ||
apiRef.current.setMeta(function (old) { | ||
return _objectSpread({}, old, { | ||
// Submission attempts make the form dirty | ||
isTouched: true, | ||
// Submittion attempts mark the form as not submitted | ||
isSubmitted: false, | ||
// Count submission attempts | ||
submissionAttempts: old.submissionAttempts + 1 | ||
isTouched: true | ||
}); | ||
}); | ||
apiRef.current.setMeta({ | ||
isSubmitting: true | ||
}); | ||
_context.prev = 10; | ||
_context.next = 13; | ||
return apiRef.current.onSubmit(apiRef.current.values, apiRef.current); | ||
} | ||
case 13: | ||
apiRef.current.setMeta({ | ||
isSubmitted: true | ||
}); | ||
_context.next = 19; | ||
if (!needsResubmit) { | ||
_context.next = 23; | ||
break; | ||
} | ||
case 16: | ||
_context.prev = 16; | ||
_context.t0 = _context["catch"](10); | ||
throw _context.t0; | ||
_context.next = 18; | ||
return Promise.all(fieldValidationPromises); | ||
case 19: | ||
_context.prev = 19; | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
case 18: | ||
_context.next = 20; | ||
return apiRef.current.runValidation(); | ||
case 20: | ||
// Then rerun the submission attempt | ||
e.__handled = false; | ||
setShouldResubmit(e || true); // Do not continue | ||
return _context.abrupt("return"); | ||
case 23: | ||
apiRef.current.setMeta(function (old) { | ||
return _objectSpread({}, old, { | ||
// Submittion attempts mark the form as not submitted | ||
isSubmitted: false, | ||
// Count submission attempts | ||
submissionAttempts: old.submissionAttempts + 1 | ||
}); | ||
return _context.finish(19); | ||
}); | ||
_context.prev = 24; | ||
_context.next = 27; | ||
return apiRef.current.onSubmit(apiRef.current.values, apiRef.current); | ||
case 22: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
case 27: | ||
apiRef.current.setMeta({ | ||
isSubmitted: true | ||
}); | ||
_context.next = 33; | ||
break; | ||
case 30: | ||
_context.prev = 30; | ||
_context.t0 = _context["catch"](24); | ||
throw _context.t0; | ||
case 33: | ||
_context.prev = 33; | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
}); | ||
return _context.finish(33); | ||
case 36: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
}, _callee, null, [[10, 16, 19, 22]]); | ||
})); | ||
} | ||
}, _callee, null, [[24, 30, 33, 36]]); | ||
})), []); // Create a debounce for this field hook instance (not all instances) | ||
return function (_x) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}(), []); // Create a debounce for this field hook instance (not all instances) | ||
var debounce = useAsyncDebounce(); | ||
@@ -473,65 +709,98 @@ var setMeta = React.useCallback(function (updater) { | ||
}, [setState]); | ||
var runValidation = React.useCallback( | ||
/*#__PURE__*/ | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee2() { | ||
var id, checkLatest, error; | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (validateRef.current) { | ||
_context2.next = 2; | ||
break; | ||
} | ||
var runValidation = React.useCallback(function () { | ||
if (!metaRef.current.validate) { | ||
return; | ||
} | ||
return _context2.abrupt("return"); | ||
apiRef.current.setMeta({ | ||
isValidating: true | ||
}); // Use the validationCount for all field instances to | ||
// track freshness of the validation | ||
case 2: | ||
apiRef.current.setMeta({ | ||
isValidating: true | ||
}); // Use the validationCount for all field instances to | ||
// track freshness of the validation | ||
var id = (metaRef.current.validationCount || 0) + 1; | ||
metaRef.current.validationCount = id; | ||
id = (metaRef.current.validationCount || 0) + 1; | ||
metaRef.current.validationCount = id; | ||
var checkLatest = function checkLatest() { | ||
return id === metaRef.current.validationCount; | ||
}; | ||
checkLatest = function checkLatest() { | ||
return id === metaRef.current.validationCount; | ||
}; | ||
if (!metaRef.current.validationPromise) { | ||
metaRef.current.validationPromise = new Promise(function (resolve, reject) { | ||
metaRef.current.validationResolve = resolve; | ||
metaRef.current.validationReject = reject; | ||
}); | ||
} | ||
_context2.next = 8; | ||
return validateRef.current(apiRef.current.values, apiRef.current); | ||
var doValidation = | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref3 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee2() { | ||
var error; | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
_context2.prev = 0; | ||
_context2.next = 3; | ||
return metaRef.current.validate(apiRef.current.values, apiRef.current); | ||
case 8: | ||
error = _context2.sent; | ||
case 3: | ||
error = _context2.sent; | ||
if (checkLatest()) { | ||
apiRef.current.setMeta({ | ||
isValidating: false | ||
}); | ||
if (checkLatest()) { | ||
apiRef.current.setMeta({ | ||
isValidating: false | ||
}); | ||
if (typeof error !== 'undefined') { | ||
if (error) { | ||
if (typeof error === 'string') { | ||
apiRef.current.setMeta({ | ||
error: error | ||
}); | ||
if (typeof error !== 'undefined') { | ||
if (error) { | ||
if (typeof error === 'string') { | ||
apiRef.current.setMeta({ | ||
error: error | ||
}); | ||
} | ||
} else { | ||
apiRef.current.setMeta({ | ||
error: null | ||
}); | ||
} | ||
} | ||
} else { | ||
apiRef.current.setMeta({ | ||
error: null | ||
}); | ||
metaRef.current.validationResolve(); | ||
} | ||
} | ||
_context2.next = 10; | ||
break; | ||
case 7: | ||
_context2.prev = 7; | ||
_context2.t0 = _context2["catch"](0); | ||
if (checkLatest()) { | ||
metaRef.current.validationReject(_context2.t0); | ||
} | ||
case 10: | ||
_context2.prev = 10; | ||
delete metaRef.current.validationPromise; | ||
return _context2.finish(10); | ||
case 13: | ||
case "end": | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, null, [[0, 7, 10, 13]]); | ||
})); | ||
case 10: | ||
case "end": | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2); | ||
})), []); | ||
return function doValidation() { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
}(); | ||
doValidation(); | ||
return metaRef.current.validationPromise; | ||
}, []); | ||
var getFieldValue = React.useCallback(function (field) { | ||
@@ -562,4 +831,10 @@ return getBy(apiRef.current.values, field); | ||
setState(function (old) { | ||
var newFieldMeta = typeof updater === 'function' ? updater(old.__fieldMeta[fieldID]) : _objectSpread({}, old.__fieldMeta[fieldID], updater); | ||
return _objectSpread({}, old, { | ||
__fieldMeta: _objectSpread({}, old.__fieldMeta, _defineProperty({}, fieldID, typeof updater === 'function' ? updater(old.__fieldMeta[fieldID]) : _objectSpread({}, old.__fieldMeta[fieldID], updater))) | ||
// Any errors in fields should visually stop | ||
// form.isSubmitting | ||
meta: newFieldMeta && newFieldMeta.error ? _objectSpread({}, old.meta, { | ||
isSubmitting: false | ||
}) : old.meta, | ||
__fieldMeta: _objectSpread({}, old.__fieldMeta, _defineProperty({}, fieldID, newFieldMeta)) | ||
}); | ||
@@ -607,7 +882,3 @@ }); | ||
apiRef.current.setFieldValue(field, function (old) { | ||
if (Array.isArray(old)) { | ||
return [].concat(_toConsumableArray(old), [value]); | ||
} else { | ||
throw Error("Cannot push a field value into a non-array field. Check that this field's existing value is an array: ".concat(field, ".")); | ||
} | ||
return [].concat(_toConsumableArray(Array.isArray(old) ? old : []), [value]); | ||
}, options); | ||
@@ -678,3 +949,10 @@ }, []); | ||
formContext: api | ||
}); // When the form gets dirty and when the value changes | ||
}); // If shouldResubmit is true, do yo thang | ||
React.useEffect(function () { | ||
if (shouldResubmit) { | ||
handleSubmit(shouldResubmit); | ||
setShouldResubmit(false); | ||
} | ||
}, [handleSubmit, shouldResubmit]); // When the form gets dirty and when the value changes | ||
// validate | ||
@@ -702,15 +980,21 @@ | ||
} | ||
function useFormContext(manualFormContext) { | ||
var formApi = React.useContext(formContext); | ||
if (manualFormContext) { | ||
return manualFormContext; | ||
} | ||
function useFieldScope(contextValue) { | ||
var FieldScopeRef = React.useRef(); | ||
var FieldScopeApiRef = React.useRef(); | ||
FieldScopeApiRef.current = contextValue; // Create a new form element | ||
if (!formApi) { | ||
throw new Error("You are trying to use the form API outside of a form!"); | ||
if (!FieldScopeRef.current) { | ||
FieldScopeRef.current = function Field(_ref) { | ||
var children = _ref.children; | ||
return React.createElement(FormContextProvider, { | ||
value: FieldScopeApiRef.current | ||
}, children); | ||
}; | ||
} | ||
return formApi; | ||
return FieldScopeRef.current; | ||
} | ||
var uid = 0; | ||
var methodMap = ['setFieldValue', 'setFieldMeta', 'pushFieldValue', 'insertFieldValue', 'removeFieldValue', 'swapFieldValues']; | ||
@@ -723,14 +1007,14 @@ var defaultDefaultMeta = { | ||
function useField(fieldName) { | ||
var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
defaultValue = _ref5.defaultValue, | ||
_ref5$defaultIsTouche = _ref5.defaultIsTouched, | ||
defaultIsTouched = _ref5$defaultIsTouche === void 0 ? false : _ref5$defaultIsTouche, | ||
_ref5$defaultError = _ref5.defaultError, | ||
defaultError = _ref5$defaultError === void 0 ? null : _ref5$defaultError, | ||
_ref5$defaultMeta = _ref5.defaultMeta, | ||
defaultMeta = _ref5$defaultMeta === void 0 ? defaultDefaultMeta : _ref5$defaultMeta, | ||
validatePristine = _ref5.validatePristine, | ||
validate = _ref5.validate, | ||
filterValue = _ref5.filterValue, | ||
manualFormContext = _ref5.formContext; | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
defaultValue = _ref.defaultValue, | ||
_ref$defaultIsTouched = _ref.defaultIsTouched, | ||
defaultIsTouched = _ref$defaultIsTouched === void 0 ? false : _ref$defaultIsTouched, | ||
_ref$defaultError = _ref.defaultError, | ||
defaultError = _ref$defaultError === void 0 ? null : _ref$defaultError, | ||
_ref$defaultMeta = _ref.defaultMeta, | ||
defaultMeta = _ref$defaultMeta === void 0 ? defaultDefaultMeta : _ref$defaultMeta, | ||
validatePristine = _ref.validatePristine, | ||
validate = _ref.validate, | ||
filterValue = _ref.filterValue, | ||
manualFormContext = _ref.formContext; | ||
@@ -841,14 +1125,14 @@ if (!fieldName) { | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee4() { | ||
regeneratorRuntime.mark(function _callee2() { | ||
var id, checkLatest, doValidate; | ||
return regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (fieldApiRef.current.__validate) { | ||
_context4.next = 2; | ||
_context2.next = 2; | ||
break; | ||
} | ||
return _context4.abrupt("return"); | ||
return _context2.abrupt("return"); | ||
@@ -878,16 +1162,16 @@ case 2: | ||
function () { | ||
var _ref7 = _asyncToGenerator( | ||
var _ref3 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee3() { | ||
regeneratorRuntime.mark(function _callee() { | ||
var error; | ||
return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context3.prev = 0; | ||
_context3.next = 3; | ||
_context.prev = 0; | ||
_context.next = 3; | ||
return fieldApiRef.current.__validate(fieldApiRef.current.value, fieldApiRef.current); | ||
case 3: | ||
error = _context3.sent; | ||
error = _context.sent; | ||
@@ -916,20 +1200,20 @@ if (checkLatest()) { | ||
_context3.next = 12; | ||
_context.next = 12; | ||
break; | ||
case 7: | ||
_context3.prev = 7; | ||
_context3.t0 = _context3["catch"](0); | ||
_context.prev = 7; | ||
_context.t0 = _context["catch"](0); | ||
if (!checkLatest()) { | ||
_context3.next = 12; | ||
_context.next = 12; | ||
break; | ||
} | ||
__metaRef.current.validationReject(_context3.t0); | ||
__metaRef.current.validationReject(_context.t0); | ||
throw _context3.t0; | ||
throw _context.t0; | ||
case 12: | ||
_context3.prev = 12; | ||
_context.prev = 12; | ||
@@ -943,14 +1227,14 @@ if (checkLatest()) { | ||
return _context3.finish(12); | ||
return _context.finish(12); | ||
case 15: | ||
case "end": | ||
return _context3.stop(); | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee3, null, [[0, 7, 12, 15]]); | ||
}, _callee, null, [[0, 7, 12, 15]]); | ||
})); | ||
return function doValidate() { | ||
return _ref7.apply(this, arguments); | ||
return _ref3.apply(this, arguments); | ||
}; | ||
@@ -960,16 +1244,16 @@ }(); | ||
doValidate(); | ||
return _context4.abrupt("return", __metaRef.current.validationPromise); | ||
return _context2.abrupt("return", __metaRef.current.validationPromise); | ||
case 10: | ||
case "end": | ||
return _context4.stop(); | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee4); | ||
}, _callee2); | ||
})), [__metaRef, setMeta]); | ||
var getInputProps = React.useCallback(function () { | ||
var _ref8 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_onChange = _ref8.onChange, | ||
_onBlur = _ref8.onBlur, | ||
rest = _objectWithoutProperties(_ref8, ["onChange", "onBlur"]); | ||
var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_onChange = _ref4.onChange, | ||
_onBlur = _ref4.onBlur, | ||
rest = _objectWithoutProperties(_ref4, ["onChange", "onBlur"]); | ||
@@ -1018,3 +1302,4 @@ return _objectSpread({ | ||
React.useEffect(function () { | ||
var metaRef = __metaRef.current; | ||
var fieldID = getFieldID(fieldName); | ||
var metaRef = formApiRef.current.__fieldMetaRefs[fieldID].current; | ||
metaRef.instanceRefs = metaRef.instanceRefs || {}; | ||
@@ -1024,4 +1309,11 @@ metaRef.instanceRefs[instanceID] = fieldApiRef; | ||
delete metaRef.instanceRefs[instanceID]; | ||
if (!Object.keys(metaRef.instanceRefs).length) { | ||
fieldApiRef.current.setMeta(function () { | ||
return undefined; | ||
}); | ||
delete formApiRef.current.__fieldMetaRefs[fieldID]; | ||
} | ||
}; | ||
}, [__metaRef, fieldApiRef, instanceID]); // The default value effect handler | ||
}, [fieldName, instanceID]); // The default value effect handler | ||
@@ -1056,189 +1348,3 @@ React.useEffect(function () { | ||
function useFormElement(contextValue) { | ||
var FormRef = React.useRef(); | ||
var FormApiRef = React.useRef(); | ||
FormApiRef.current = contextValue; // Create a new form element | ||
if (!FormRef.current) { | ||
FormRef.current = function Form(_ref9) { | ||
var children = _ref9.children, | ||
noFormElement = _ref9.noFormElement, | ||
rest = _objectWithoutProperties(_ref9, ["children", "noFormElement"]); | ||
var _FormApiRef$current = FormApiRef.current, | ||
handleSubmit = _FormApiRef$current.handleSubmit, | ||
isSubmitting = _FormApiRef$current.meta.isSubmitting, | ||
debugForm = _FormApiRef$current.debugForm; | ||
return React.createElement(formContext.Provider, { | ||
value: FormApiRef.current | ||
}, noFormElement ? children : React.createElement("form", _extends({ | ||
onSubmit: handleSubmit, | ||
disabled: isSubmitting | ||
}, rest), children, debugForm ? React.createElement("div", { | ||
style: { | ||
margin: '2rem 0' | ||
} | ||
}, React.createElement("div", { | ||
style: { | ||
fontWeight: 'bolder' | ||
} | ||
}, "Form State"), React.createElement("pre", null, React.createElement("code", null, JSON.stringify(_objectSpread({}, FormApiRef.current, { | ||
formContext: undefined | ||
}), safeStringifyReplace(new Set()), 2)))) : null)); | ||
}; | ||
} // Return the form element | ||
return FormRef.current; | ||
} | ||
function useFieldScope(contextValue) { | ||
var FieldScopeRef = React.useRef(); | ||
var FieldScopeApiRef = React.useRef(); | ||
FieldScopeApiRef.current = contextValue; // Create a new form element | ||
if (!FieldScopeRef.current) { | ||
FieldScopeRef.current = function Field(_ref10) { | ||
var children = _ref10.children; | ||
return React.createElement(formContext.Provider, { | ||
value: FieldScopeApiRef.current | ||
}, children); | ||
}; | ||
} | ||
return FieldScopeRef.current; | ||
} | ||
function splitFormProps(_ref11) { | ||
var field = _ref11.field, | ||
defaultValue = _ref11.defaultValue, | ||
defaultIsTouched = _ref11.defaultIsTouched, | ||
defaultError = _ref11.defaultError, | ||
defaultMeta = _ref11.defaultMeta, | ||
validatePristine = _ref11.validatePristine, | ||
validate = _ref11.validate, | ||
onSubmit = _ref11.onSubmit, | ||
defaultValues = _ref11.defaultValues, | ||
filterValue = _ref11.filterValue, | ||
debugForm = _ref11.debugForm, | ||
rest = _objectWithoutProperties(_ref11, ["field", "defaultValue", "defaultIsTouched", "defaultError", "defaultMeta", "validatePristine", "validate", "onSubmit", "defaultValues", "filterValue", "debugForm"]); | ||
return [field, { | ||
defaultValue: defaultValue, | ||
defaultIsTouched: defaultIsTouched, | ||
defaultError: defaultError, | ||
defaultMeta: defaultMeta, | ||
validatePristine: validatePristine, | ||
validate: validate, | ||
onSubmit: onSubmit, | ||
defaultValues: defaultValues, | ||
filterValue: filterValue, | ||
debugForm: debugForm | ||
}, rest]; | ||
} // Utils | ||
function getBy(obj, path) { | ||
if (!path) { | ||
throw new Error('A path string is required to use getBy'); | ||
} | ||
var pathArray = makePathArray(path); | ||
var pathObj = pathArray; | ||
return pathObj.reduce(function (current, pathPart) { | ||
if (typeof current !== 'undefined') { | ||
return current[pathPart]; | ||
} | ||
return undefined; | ||
}, obj); | ||
} | ||
function setBy(obj, path, updater) { | ||
path = makePathArray(path); | ||
function doSet(parent) { | ||
if (!path.length) { | ||
return typeof updater === 'function' ? updater(parent) : updater; | ||
} | ||
var key = path.shift(); | ||
if (typeof key === 'string') { | ||
if (_typeof(parent) === 'object') { | ||
return _objectSpread({}, parent, _defineProperty({}, key, doSet(parent[key]))); | ||
} | ||
return _defineProperty({}, key, doSet()); | ||
} | ||
if (typeof key === 'number') { | ||
if (Array.isArray(parent)) { | ||
var prefix = parent.slice(0, key); | ||
return [].concat(_toConsumableArray(prefix.length ? prefix : new Array(key)), [doSet(parent[key])], _toConsumableArray(parent.slice(key + 1))); | ||
} | ||
return [].concat(_toConsumableArray(new Array(key)), [doSet()]); | ||
} | ||
throw new Error('Uh oh!'); | ||
} | ||
return doSet(obj); | ||
} | ||
function getFieldID(str) { | ||
return makePathArray(str).join('_'); | ||
} | ||
var reFindNumbers0 = /^(\d*)$/gm; | ||
var reFindNumbers1 = /\.(\d*)\./gm; | ||
var reFindNumbers2 = /^(\d*)\./gm; | ||
var reFindNumbers3 = /\.(\d*$)/gm; | ||
var reFindMultiplePeriods = /\.{2,}/gm; | ||
function makePathArray(str) { | ||
return str.replace('[', '').replace(']', '.').replace(reFindNumbers0, '__int__$1').replace(reFindNumbers1, '.__int__$1.').replace(reFindNumbers2, '__int__$1.').replace(reFindNumbers3, '.__int__$1').replace(reFindMultiplePeriods, '.').split('.').map(function (d) { | ||
if (d.indexOf('__int__') === 0) { | ||
return parseInt(d.substring('__int__'.length), 10); | ||
} | ||
return d; | ||
}); | ||
} | ||
function loopObject(obj, fn, callback) { | ||
Object.keys(obj).forEach(function (key) { | ||
callback(fn(obj[key], key), key); | ||
}); | ||
} | ||
function someObject(obj, fn) { | ||
var found = false; | ||
loopObject(obj, fn, function (result, key) { | ||
if (found) { | ||
return; | ||
} | ||
if (result) { | ||
found = true; | ||
} | ||
}); | ||
return found; | ||
} | ||
function safeStringifyReplace(set) { | ||
return function (key, value) { | ||
if (_typeof(value) === 'object' || Array.isArray(value)) { | ||
if (set.has(value)) { | ||
return '(circular value)'; | ||
} | ||
set.add(value); | ||
} | ||
return typeof value === 'function' ? undefined : value; | ||
}; | ||
} | ||
export { splitFormProps, useField, useForm, useFormContext }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -288,4 +288,190 @@ 'use strict'; | ||
var formContext = React.createContext(); | ||
function FormContextProvider(_ref) { | ||
var value = _ref.value, | ||
children = _ref.children; | ||
return React.createElement(formContext.Provider, { | ||
value: value | ||
}, children); | ||
} | ||
function useFormContext(manualFormContext) { | ||
var formApi = React.useContext(formContext); | ||
if (manualFormContext) { | ||
return manualFormContext; | ||
} | ||
if (!formApi) { | ||
throw new Error("You are trying to use the form API outside of a form!"); | ||
} | ||
return formApi; | ||
} | ||
function useFormElement(contextValue) { | ||
var FormRef = React.useRef(); | ||
var FormApiRef = React.useRef(); | ||
FormApiRef.current = contextValue; // Create a new form element | ||
if (!FormRef.current) { | ||
FormRef.current = function Form(_ref) { | ||
var children = _ref.children, | ||
noFormElement = _ref.noFormElement, | ||
rest = _objectWithoutProperties(_ref, ["children", "noFormElement"]); | ||
var _FormApiRef$current = FormApiRef.current, | ||
handleSubmit = _FormApiRef$current.handleSubmit, | ||
isSubmitting = _FormApiRef$current.meta.isSubmitting, | ||
debugForm = _FormApiRef$current.debugForm; | ||
return React.createElement(FormContextProvider, { | ||
value: FormApiRef.current | ||
}, noFormElement ? children : React.createElement("form", _extends({ | ||
onSubmit: handleSubmit, | ||
disabled: isSubmitting | ||
}, rest), children, debugForm ? React.createElement("div", { | ||
style: { | ||
margin: '2rem 0' | ||
} | ||
}, React.createElement("div", { | ||
style: { | ||
fontWeight: 'bolder' | ||
} | ||
}, "Form State"), React.createElement("pre", null, React.createElement("code", null, JSON.stringify(_objectSpread({}, FormApiRef.current, { | ||
formContext: undefined | ||
}), safeStringifyReplace(new Set()), 2)))) : null)); | ||
}; | ||
} // Return the form element | ||
return FormRef.current; | ||
} | ||
function safeStringifyReplace(set) { | ||
return function (key, value) { | ||
if (_typeof(value) === 'object' || Array.isArray(value)) { | ||
if (set.has(value)) { | ||
return '(circular value)'; | ||
} | ||
set.add(value); | ||
} | ||
return typeof value === 'function' ? undefined : value; | ||
}; | ||
} | ||
function splitFormProps(_ref) { | ||
var field = _ref.field, | ||
defaultValue = _ref.defaultValue, | ||
defaultIsTouched = _ref.defaultIsTouched, | ||
defaultError = _ref.defaultError, | ||
defaultMeta = _ref.defaultMeta, | ||
validatePristine = _ref.validatePristine, | ||
validate = _ref.validate, | ||
onSubmit = _ref.onSubmit, | ||
defaultValues = _ref.defaultValues, | ||
filterValue = _ref.filterValue, | ||
debugForm = _ref.debugForm, | ||
rest = _objectWithoutProperties(_ref, ["field", "defaultValue", "defaultIsTouched", "defaultError", "defaultMeta", "validatePristine", "validate", "onSubmit", "defaultValues", "filterValue", "debugForm"]); | ||
return [field, { | ||
defaultValue: defaultValue, | ||
defaultIsTouched: defaultIsTouched, | ||
defaultError: defaultError, | ||
defaultMeta: defaultMeta, | ||
validatePristine: validatePristine, | ||
validate: validate, | ||
onSubmit: onSubmit, | ||
defaultValues: defaultValues, | ||
filterValue: filterValue, | ||
debugForm: debugForm | ||
}, rest]; | ||
} // Utils | ||
function getBy(obj, path) { | ||
if (!path) { | ||
throw new Error('A path string is required to use getBy'); | ||
} | ||
var pathArray = makePathArray(path); | ||
var pathObj = pathArray; | ||
return pathObj.reduce(function (current, pathPart) { | ||
if (typeof current !== 'undefined') { | ||
return current[pathPart]; | ||
} | ||
return undefined; | ||
}, obj); | ||
} | ||
function setBy(obj, path, updater) { | ||
path = makePathArray(path); | ||
function doSet(parent) { | ||
if (!path.length) { | ||
return typeof updater === 'function' ? updater(parent) : updater; | ||
} | ||
var key = path.shift(); | ||
if (typeof key === 'string') { | ||
if (_typeof(parent) === 'object') { | ||
return _objectSpread({}, parent, _defineProperty({}, key, doSet(parent[key]))); | ||
} | ||
return _defineProperty({}, key, doSet()); | ||
} | ||
if (typeof key === 'number') { | ||
if (Array.isArray(parent)) { | ||
var prefix = parent.slice(0, key); | ||
return [].concat(_toConsumableArray(prefix.length ? prefix : new Array(key)), [doSet(parent[key])], _toConsumableArray(parent.slice(key + 1))); | ||
} | ||
return [].concat(_toConsumableArray(new Array(key)), [doSet()]); | ||
} | ||
throw new Error('Uh oh!'); | ||
} | ||
return doSet(obj); | ||
} | ||
function getFieldID(str) { | ||
return makePathArray(str).join('_'); | ||
} | ||
var reFindNumbers0 = /^(\d*)$/gm; | ||
var reFindNumbers1 = /\.(\d*)\./gm; | ||
var reFindNumbers2 = /^(\d*)\./gm; | ||
var reFindNumbers3 = /\.(\d*$)/gm; | ||
var reFindMultiplePeriods = /\.{2,}/gm; | ||
function makePathArray(str) { | ||
return str.replace('[', '').replace(']', '.').replace(reFindNumbers0, '__int__$1').replace(reFindNumbers1, '.__int__$1.').replace(reFindNumbers2, '__int__$1.').replace(reFindNumbers3, '.__int__$1').replace(reFindMultiplePeriods, '.').split('.').map(function (d) { | ||
if (d.indexOf('__int__') === 0) { | ||
return parseInt(d.substring('__int__'.length), 10); | ||
} | ||
return d; | ||
}); | ||
} | ||
function loopObject(obj, fn, callback) { | ||
Object.keys(obj).forEach(function (key) { | ||
callback(fn(obj[key], key), key); | ||
}); | ||
} | ||
function someObject(obj, fn) { | ||
var found = false; | ||
loopObject(obj, fn, function (result, key) { | ||
if (found) { | ||
return; | ||
} | ||
if (result) { | ||
found = true; | ||
} | ||
}); | ||
return found; | ||
} | ||
var defaultDefaultValue = {}; | ||
var uid = 0; | ||
@@ -328,18 +514,22 @@ function makeState(decor) { | ||
var _React$useState3 = React.useState(false), | ||
_React$useState4 = _slicedToArray(_React$useState3, 2), | ||
shouldResubmit = _React$useState4[0], | ||
setShouldResubmit = _React$useState4[1]; | ||
var apiRef = React.useRef(); | ||
var metaRef = React.useRef({}); | ||
var __fieldMetaRefsRef = React.useRef({}); | ||
var __fieldMetaRefsRef = React.useRef({}); // Keep validate up to date with the latest version | ||
var validateRef = React.useRef(); // Keep validate up to date with the latest version | ||
validateRef.current = validate; | ||
var allFieldsTouched = !someObject(__fieldMeta, function (field) { | ||
return field && !field.isTouched; | ||
metaRef.current.validate = validate; | ||
var fieldsAreValidating = someObject(__fieldMeta, function (field) { | ||
return field && field.isValidating; | ||
}); | ||
var allFieldsValid = !someObject(__fieldMeta, function (field) { | ||
var fieldsAreValid = !someObject(__fieldMeta, function (field) { | ||
return field && field.error; | ||
}); // Can we submit this form? | ||
var isValid = isTouched && allFieldsValid && !meta.error; | ||
var isValid = !fieldsAreValidating && fieldsAreValid && !meta.error; | ||
var canSubmit = isValid && !isSubmitting; // Decorate form meta | ||
@@ -349,8 +539,8 @@ | ||
return _objectSpread({}, meta, { | ||
fieldsAreValidating: fieldsAreValidating, | ||
fieldsAreValid: fieldsAreValid, | ||
isValid: isValid, | ||
canSubmit: canSubmit, | ||
allFieldsTouched: allFieldsTouched, | ||
allFieldsValid: allFieldsValid | ||
canSubmit: canSubmit | ||
}); | ||
}, [meta, isValid, canSubmit, allFieldsTouched, allFieldsValid]); // We want the apiRef to change every time state updates | ||
}, [meta, fieldsAreValidating, fieldsAreValid, isValid, canSubmit]); // We want the apiRef to change every time state updates | ||
@@ -377,95 +567,141 @@ var api = React.useMemo(function () { | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref2 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee(e) { | ||
var needTouchedAndValidation; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
e.persist(); | ||
e.preventDefault(); // This lets sub-forms with form elements (despite them being invalid HTML) | ||
// handle submissions without triggering parent forms | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee() { | ||
var e, | ||
needsResubmit, | ||
fieldValidationPromises, | ||
_args = arguments; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
e = _args.length > 0 && _args[0] !== undefined ? _args[0] : {}; | ||
if (e.persist) e.persist(); | ||
if (e.preventDefault) e.preventDefault(); // This lets sub-forms with form elements (despite them being invalid HTML) | ||
// handle submissions without triggering parent forms | ||
if (!e.__handled) { | ||
_context.next = 4; | ||
break; | ||
} | ||
if (!e.__handled) { | ||
_context.next = 5; | ||
break; | ||
} | ||
return _context.abrupt("return"); | ||
return _context.abrupt("return"); | ||
case 4: | ||
e.__handled = true; | ||
Object.keys(apiRef.current.__fieldMetaRefs).forEach(function (key) { | ||
var fieldMeta = apiRef.current.__fieldMetaRefs[key].current; | ||
Object.keys(fieldMeta.instanceRefs).forEach(function (key) { | ||
var fieldInstance = fieldMeta.instanceRefs[key].current; | ||
case 5: | ||
e.__handled = true; // Don't let invalid forms submit | ||
if (fieldInstance.__validate && !fieldInstance.meta.isTouched) { | ||
needTouchedAndValidation = true; | ||
fieldInstance.setMeta({ | ||
isTouched: true | ||
}); | ||
if (apiRef.current.meta.isValid) { | ||
_context.next = 9; | ||
break; | ||
} | ||
// If the form can't submit, let's trigger all of the fields | ||
// to be touched. Thus, their validations will run | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
}); | ||
return _context.abrupt("return"); | ||
case 9: | ||
apiRef.current.setMeta({ | ||
isSubmitting: true | ||
}); | ||
needsResubmit = false; | ||
fieldValidationPromises = []; | ||
Object.keys(apiRef.current.__fieldMetaRefs).forEach(function (key) { | ||
var fieldMeta = apiRef.current.__fieldMetaRefs[key].current; | ||
Object.keys(fieldMeta.instanceRefs).forEach(function (key) { | ||
var fieldInstance = fieldMeta.instanceRefs[key].current; // If any fields are not touched | ||
if (!fieldInstance.meta.isTouched) { | ||
// Mark them as touched | ||
fieldInstance.setMeta({ | ||
isTouched: true | ||
}); // Likewise, if they need validation | ||
if (fieldInstance.__validate) { | ||
// Run their validation and keep track of the | ||
// promise | ||
fieldValidationPromises.push(fieldInstance.runValidation()); | ||
} | ||
}); | ||
}); // Don't let invalid forms submit | ||
} | ||
}); | ||
}); // If any validation needed to be run | ||
if (!(!apiRef.current.meta.canSubmit || needTouchedAndValidation)) { | ||
_context.next = 8; | ||
break; | ||
} | ||
if (fieldValidationPromises.length) { | ||
// Mark for resubmission | ||
needsResubmit = true; | ||
} | ||
return _context.abrupt("return"); | ||
if (!apiRef.current.meta.isTouched) { | ||
// Mark for resubmission | ||
needsResubmit = true; // Mark the form as touched | ||
case 8: | ||
apiRef.current.setMeta(function (old) { | ||
return _objectSpread({}, old, { | ||
// Submission attempts make the form dirty | ||
isTouched: true, | ||
// Submittion attempts mark the form as not submitted | ||
isSubmitted: false, | ||
// Count submission attempts | ||
submissionAttempts: old.submissionAttempts + 1 | ||
isTouched: true | ||
}); | ||
}); | ||
apiRef.current.setMeta({ | ||
isSubmitting: true | ||
}); | ||
_context.prev = 10; | ||
_context.next = 13; | ||
return apiRef.current.onSubmit(apiRef.current.values, apiRef.current); | ||
} | ||
case 13: | ||
apiRef.current.setMeta({ | ||
isSubmitted: true | ||
}); | ||
_context.next = 19; | ||
if (!needsResubmit) { | ||
_context.next = 23; | ||
break; | ||
} | ||
case 16: | ||
_context.prev = 16; | ||
_context.t0 = _context["catch"](10); | ||
throw _context.t0; | ||
_context.next = 18; | ||
return Promise.all(fieldValidationPromises); | ||
case 19: | ||
_context.prev = 19; | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
case 18: | ||
_context.next = 20; | ||
return apiRef.current.runValidation(); | ||
case 20: | ||
// Then rerun the submission attempt | ||
e.__handled = false; | ||
setShouldResubmit(e || true); // Do not continue | ||
return _context.abrupt("return"); | ||
case 23: | ||
apiRef.current.setMeta(function (old) { | ||
return _objectSpread({}, old, { | ||
// Submittion attempts mark the form as not submitted | ||
isSubmitted: false, | ||
// Count submission attempts | ||
submissionAttempts: old.submissionAttempts + 1 | ||
}); | ||
return _context.finish(19); | ||
}); | ||
_context.prev = 24; | ||
_context.next = 27; | ||
return apiRef.current.onSubmit(apiRef.current.values, apiRef.current); | ||
case 22: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
case 27: | ||
apiRef.current.setMeta({ | ||
isSubmitted: true | ||
}); | ||
_context.next = 33; | ||
break; | ||
case 30: | ||
_context.prev = 30; | ||
_context.t0 = _context["catch"](24); | ||
throw _context.t0; | ||
case 33: | ||
_context.prev = 33; | ||
apiRef.current.setMeta({ | ||
isSubmitting: false | ||
}); | ||
return _context.finish(33); | ||
case 36: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
}, _callee, null, [[10, 16, 19, 22]]); | ||
})); | ||
} | ||
}, _callee, null, [[24, 30, 33, 36]]); | ||
})), []); // Create a debounce for this field hook instance (not all instances) | ||
return function (_x) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}(), []); // Create a debounce for this field hook instance (not all instances) | ||
var debounce = useAsyncDebounce(); | ||
@@ -479,65 +715,98 @@ var setMeta = React.useCallback(function (updater) { | ||
}, [setState]); | ||
var runValidation = React.useCallback( | ||
/*#__PURE__*/ | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee2() { | ||
var id, checkLatest, error; | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (validateRef.current) { | ||
_context2.next = 2; | ||
break; | ||
} | ||
var runValidation = React.useCallback(function () { | ||
if (!metaRef.current.validate) { | ||
return; | ||
} | ||
return _context2.abrupt("return"); | ||
apiRef.current.setMeta({ | ||
isValidating: true | ||
}); // Use the validationCount for all field instances to | ||
// track freshness of the validation | ||
case 2: | ||
apiRef.current.setMeta({ | ||
isValidating: true | ||
}); // Use the validationCount for all field instances to | ||
// track freshness of the validation | ||
var id = (metaRef.current.validationCount || 0) + 1; | ||
metaRef.current.validationCount = id; | ||
id = (metaRef.current.validationCount || 0) + 1; | ||
metaRef.current.validationCount = id; | ||
var checkLatest = function checkLatest() { | ||
return id === metaRef.current.validationCount; | ||
}; | ||
checkLatest = function checkLatest() { | ||
return id === metaRef.current.validationCount; | ||
}; | ||
if (!metaRef.current.validationPromise) { | ||
metaRef.current.validationPromise = new Promise(function (resolve, reject) { | ||
metaRef.current.validationResolve = resolve; | ||
metaRef.current.validationReject = reject; | ||
}); | ||
} | ||
_context2.next = 8; | ||
return validateRef.current(apiRef.current.values, apiRef.current); | ||
var doValidation = | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref3 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee2() { | ||
var error; | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
_context2.prev = 0; | ||
_context2.next = 3; | ||
return metaRef.current.validate(apiRef.current.values, apiRef.current); | ||
case 8: | ||
error = _context2.sent; | ||
case 3: | ||
error = _context2.sent; | ||
if (checkLatest()) { | ||
apiRef.current.setMeta({ | ||
isValidating: false | ||
}); | ||
if (checkLatest()) { | ||
apiRef.current.setMeta({ | ||
isValidating: false | ||
}); | ||
if (typeof error !== 'undefined') { | ||
if (error) { | ||
if (typeof error === 'string') { | ||
apiRef.current.setMeta({ | ||
error: error | ||
}); | ||
if (typeof error !== 'undefined') { | ||
if (error) { | ||
if (typeof error === 'string') { | ||
apiRef.current.setMeta({ | ||
error: error | ||
}); | ||
} | ||
} else { | ||
apiRef.current.setMeta({ | ||
error: null | ||
}); | ||
} | ||
} | ||
} else { | ||
apiRef.current.setMeta({ | ||
error: null | ||
}); | ||
metaRef.current.validationResolve(); | ||
} | ||
} | ||
_context2.next = 10; | ||
break; | ||
case 7: | ||
_context2.prev = 7; | ||
_context2.t0 = _context2["catch"](0); | ||
if (checkLatest()) { | ||
metaRef.current.validationReject(_context2.t0); | ||
} | ||
case 10: | ||
_context2.prev = 10; | ||
delete metaRef.current.validationPromise; | ||
return _context2.finish(10); | ||
case 13: | ||
case "end": | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, null, [[0, 7, 10, 13]]); | ||
})); | ||
case 10: | ||
case "end": | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2); | ||
})), []); | ||
return function doValidation() { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
}(); | ||
doValidation(); | ||
return metaRef.current.validationPromise; | ||
}, []); | ||
var getFieldValue = React.useCallback(function (field) { | ||
@@ -568,4 +837,10 @@ return getBy(apiRef.current.values, field); | ||
setState(function (old) { | ||
var newFieldMeta = typeof updater === 'function' ? updater(old.__fieldMeta[fieldID]) : _objectSpread({}, old.__fieldMeta[fieldID], updater); | ||
return _objectSpread({}, old, { | ||
__fieldMeta: _objectSpread({}, old.__fieldMeta, _defineProperty({}, fieldID, typeof updater === 'function' ? updater(old.__fieldMeta[fieldID]) : _objectSpread({}, old.__fieldMeta[fieldID], updater))) | ||
// Any errors in fields should visually stop | ||
// form.isSubmitting | ||
meta: newFieldMeta && newFieldMeta.error ? _objectSpread({}, old.meta, { | ||
isSubmitting: false | ||
}) : old.meta, | ||
__fieldMeta: _objectSpread({}, old.__fieldMeta, _defineProperty({}, fieldID, newFieldMeta)) | ||
}); | ||
@@ -613,7 +888,3 @@ }); | ||
apiRef.current.setFieldValue(field, function (old) { | ||
if (Array.isArray(old)) { | ||
return [].concat(_toConsumableArray(old), [value]); | ||
} else { | ||
throw Error("Cannot push a field value into a non-array field. Check that this field's existing value is an array: ".concat(field, ".")); | ||
} | ||
return [].concat(_toConsumableArray(Array.isArray(old) ? old : []), [value]); | ||
}, options); | ||
@@ -684,3 +955,10 @@ }, []); | ||
formContext: api | ||
}); // When the form gets dirty and when the value changes | ||
}); // If shouldResubmit is true, do yo thang | ||
React.useEffect(function () { | ||
if (shouldResubmit) { | ||
handleSubmit(shouldResubmit); | ||
setShouldResubmit(false); | ||
} | ||
}, [handleSubmit, shouldResubmit]); // When the form gets dirty and when the value changes | ||
// validate | ||
@@ -708,15 +986,21 @@ | ||
} | ||
function useFormContext(manualFormContext) { | ||
var formApi = React.useContext(formContext); | ||
if (manualFormContext) { | ||
return manualFormContext; | ||
} | ||
function useFieldScope(contextValue) { | ||
var FieldScopeRef = React.useRef(); | ||
var FieldScopeApiRef = React.useRef(); | ||
FieldScopeApiRef.current = contextValue; // Create a new form element | ||
if (!formApi) { | ||
throw new Error("You are trying to use the form API outside of a form!"); | ||
if (!FieldScopeRef.current) { | ||
FieldScopeRef.current = function Field(_ref) { | ||
var children = _ref.children; | ||
return React.createElement(FormContextProvider, { | ||
value: FieldScopeApiRef.current | ||
}, children); | ||
}; | ||
} | ||
return formApi; | ||
return FieldScopeRef.current; | ||
} | ||
var uid = 0; | ||
var methodMap = ['setFieldValue', 'setFieldMeta', 'pushFieldValue', 'insertFieldValue', 'removeFieldValue', 'swapFieldValues']; | ||
@@ -729,14 +1013,14 @@ var defaultDefaultMeta = { | ||
function useField(fieldName) { | ||
var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
defaultValue = _ref5.defaultValue, | ||
_ref5$defaultIsTouche = _ref5.defaultIsTouched, | ||
defaultIsTouched = _ref5$defaultIsTouche === void 0 ? false : _ref5$defaultIsTouche, | ||
_ref5$defaultError = _ref5.defaultError, | ||
defaultError = _ref5$defaultError === void 0 ? null : _ref5$defaultError, | ||
_ref5$defaultMeta = _ref5.defaultMeta, | ||
defaultMeta = _ref5$defaultMeta === void 0 ? defaultDefaultMeta : _ref5$defaultMeta, | ||
validatePristine = _ref5.validatePristine, | ||
validate = _ref5.validate, | ||
filterValue = _ref5.filterValue, | ||
manualFormContext = _ref5.formContext; | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
defaultValue = _ref.defaultValue, | ||
_ref$defaultIsTouched = _ref.defaultIsTouched, | ||
defaultIsTouched = _ref$defaultIsTouched === void 0 ? false : _ref$defaultIsTouched, | ||
_ref$defaultError = _ref.defaultError, | ||
defaultError = _ref$defaultError === void 0 ? null : _ref$defaultError, | ||
_ref$defaultMeta = _ref.defaultMeta, | ||
defaultMeta = _ref$defaultMeta === void 0 ? defaultDefaultMeta : _ref$defaultMeta, | ||
validatePristine = _ref.validatePristine, | ||
validate = _ref.validate, | ||
filterValue = _ref.filterValue, | ||
manualFormContext = _ref.formContext; | ||
@@ -847,14 +1131,14 @@ if (!fieldName) { | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee4() { | ||
regeneratorRuntime.mark(function _callee2() { | ||
var id, checkLatest, doValidate; | ||
return regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
return regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (fieldApiRef.current.__validate) { | ||
_context4.next = 2; | ||
_context2.next = 2; | ||
break; | ||
} | ||
return _context4.abrupt("return"); | ||
return _context2.abrupt("return"); | ||
@@ -884,16 +1168,16 @@ case 2: | ||
function () { | ||
var _ref7 = _asyncToGenerator( | ||
var _ref3 = _asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee3() { | ||
regeneratorRuntime.mark(function _callee() { | ||
var error; | ||
return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context3.prev = 0; | ||
_context3.next = 3; | ||
_context.prev = 0; | ||
_context.next = 3; | ||
return fieldApiRef.current.__validate(fieldApiRef.current.value, fieldApiRef.current); | ||
case 3: | ||
error = _context3.sent; | ||
error = _context.sent; | ||
@@ -922,20 +1206,20 @@ if (checkLatest()) { | ||
_context3.next = 12; | ||
_context.next = 12; | ||
break; | ||
case 7: | ||
_context3.prev = 7; | ||
_context3.t0 = _context3["catch"](0); | ||
_context.prev = 7; | ||
_context.t0 = _context["catch"](0); | ||
if (!checkLatest()) { | ||
_context3.next = 12; | ||
_context.next = 12; | ||
break; | ||
} | ||
__metaRef.current.validationReject(_context3.t0); | ||
__metaRef.current.validationReject(_context.t0); | ||
throw _context3.t0; | ||
throw _context.t0; | ||
case 12: | ||
_context3.prev = 12; | ||
_context.prev = 12; | ||
@@ -949,14 +1233,14 @@ if (checkLatest()) { | ||
return _context3.finish(12); | ||
return _context.finish(12); | ||
case 15: | ||
case "end": | ||
return _context3.stop(); | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee3, null, [[0, 7, 12, 15]]); | ||
}, _callee, null, [[0, 7, 12, 15]]); | ||
})); | ||
return function doValidate() { | ||
return _ref7.apply(this, arguments); | ||
return _ref3.apply(this, arguments); | ||
}; | ||
@@ -966,16 +1250,16 @@ }(); | ||
doValidate(); | ||
return _context4.abrupt("return", __metaRef.current.validationPromise); | ||
return _context2.abrupt("return", __metaRef.current.validationPromise); | ||
case 10: | ||
case "end": | ||
return _context4.stop(); | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee4); | ||
}, _callee2); | ||
})), [__metaRef, setMeta]); | ||
var getInputProps = React.useCallback(function () { | ||
var _ref8 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_onChange = _ref8.onChange, | ||
_onBlur = _ref8.onBlur, | ||
rest = _objectWithoutProperties(_ref8, ["onChange", "onBlur"]); | ||
var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_onChange = _ref4.onChange, | ||
_onBlur = _ref4.onBlur, | ||
rest = _objectWithoutProperties(_ref4, ["onChange", "onBlur"]); | ||
@@ -1024,3 +1308,4 @@ return _objectSpread({ | ||
React.useEffect(function () { | ||
var metaRef = __metaRef.current; | ||
var fieldID = getFieldID(fieldName); | ||
var metaRef = formApiRef.current.__fieldMetaRefs[fieldID].current; | ||
metaRef.instanceRefs = metaRef.instanceRefs || {}; | ||
@@ -1030,4 +1315,11 @@ metaRef.instanceRefs[instanceID] = fieldApiRef; | ||
delete metaRef.instanceRefs[instanceID]; | ||
if (!Object.keys(metaRef.instanceRefs).length) { | ||
fieldApiRef.current.setMeta(function () { | ||
return undefined; | ||
}); | ||
delete formApiRef.current.__fieldMetaRefs[fieldID]; | ||
} | ||
}; | ||
}, [__metaRef, fieldApiRef, instanceID]); // The default value effect handler | ||
}, [fieldName, instanceID]); // The default value effect handler | ||
@@ -1062,188 +1354,2 @@ React.useEffect(function () { | ||
function useFormElement(contextValue) { | ||
var FormRef = React.useRef(); | ||
var FormApiRef = React.useRef(); | ||
FormApiRef.current = contextValue; // Create a new form element | ||
if (!FormRef.current) { | ||
FormRef.current = function Form(_ref9) { | ||
var children = _ref9.children, | ||
noFormElement = _ref9.noFormElement, | ||
rest = _objectWithoutProperties(_ref9, ["children", "noFormElement"]); | ||
var _FormApiRef$current = FormApiRef.current, | ||
handleSubmit = _FormApiRef$current.handleSubmit, | ||
isSubmitting = _FormApiRef$current.meta.isSubmitting, | ||
debugForm = _FormApiRef$current.debugForm; | ||
return React.createElement(formContext.Provider, { | ||
value: FormApiRef.current | ||
}, noFormElement ? children : React.createElement("form", _extends({ | ||
onSubmit: handleSubmit, | ||
disabled: isSubmitting | ||
}, rest), children, debugForm ? React.createElement("div", { | ||
style: { | ||
margin: '2rem 0' | ||
} | ||
}, React.createElement("div", { | ||
style: { | ||
fontWeight: 'bolder' | ||
} | ||
}, "Form State"), React.createElement("pre", null, React.createElement("code", null, JSON.stringify(_objectSpread({}, FormApiRef.current, { | ||
formContext: undefined | ||
}), safeStringifyReplace(new Set()), 2)))) : null)); | ||
}; | ||
} // Return the form element | ||
return FormRef.current; | ||
} | ||
function useFieldScope(contextValue) { | ||
var FieldScopeRef = React.useRef(); | ||
var FieldScopeApiRef = React.useRef(); | ||
FieldScopeApiRef.current = contextValue; // Create a new form element | ||
if (!FieldScopeRef.current) { | ||
FieldScopeRef.current = function Field(_ref10) { | ||
var children = _ref10.children; | ||
return React.createElement(formContext.Provider, { | ||
value: FieldScopeApiRef.current | ||
}, children); | ||
}; | ||
} | ||
return FieldScopeRef.current; | ||
} | ||
function splitFormProps(_ref11) { | ||
var field = _ref11.field, | ||
defaultValue = _ref11.defaultValue, | ||
defaultIsTouched = _ref11.defaultIsTouched, | ||
defaultError = _ref11.defaultError, | ||
defaultMeta = _ref11.defaultMeta, | ||
validatePristine = _ref11.validatePristine, | ||
validate = _ref11.validate, | ||
onSubmit = _ref11.onSubmit, | ||
defaultValues = _ref11.defaultValues, | ||
filterValue = _ref11.filterValue, | ||
debugForm = _ref11.debugForm, | ||
rest = _objectWithoutProperties(_ref11, ["field", "defaultValue", "defaultIsTouched", "defaultError", "defaultMeta", "validatePristine", "validate", "onSubmit", "defaultValues", "filterValue", "debugForm"]); | ||
return [field, { | ||
defaultValue: defaultValue, | ||
defaultIsTouched: defaultIsTouched, | ||
defaultError: defaultError, | ||
defaultMeta: defaultMeta, | ||
validatePristine: validatePristine, | ||
validate: validate, | ||
onSubmit: onSubmit, | ||
defaultValues: defaultValues, | ||
filterValue: filterValue, | ||
debugForm: debugForm | ||
}, rest]; | ||
} // Utils | ||
function getBy(obj, path) { | ||
if (!path) { | ||
throw new Error('A path string is required to use getBy'); | ||
} | ||
var pathArray = makePathArray(path); | ||
var pathObj = pathArray; | ||
return pathObj.reduce(function (current, pathPart) { | ||
if (typeof current !== 'undefined') { | ||
return current[pathPart]; | ||
} | ||
return undefined; | ||
}, obj); | ||
} | ||
function setBy(obj, path, updater) { | ||
path = makePathArray(path); | ||
function doSet(parent) { | ||
if (!path.length) { | ||
return typeof updater === 'function' ? updater(parent) : updater; | ||
} | ||
var key = path.shift(); | ||
if (typeof key === 'string') { | ||
if (_typeof(parent) === 'object') { | ||
return _objectSpread({}, parent, _defineProperty({}, key, doSet(parent[key]))); | ||
} | ||
return _defineProperty({}, key, doSet()); | ||
} | ||
if (typeof key === 'number') { | ||
if (Array.isArray(parent)) { | ||
var prefix = parent.slice(0, key); | ||
return [].concat(_toConsumableArray(prefix.length ? prefix : new Array(key)), [doSet(parent[key])], _toConsumableArray(parent.slice(key + 1))); | ||
} | ||
return [].concat(_toConsumableArray(new Array(key)), [doSet()]); | ||
} | ||
throw new Error('Uh oh!'); | ||
} | ||
return doSet(obj); | ||
} | ||
function getFieldID(str) { | ||
return makePathArray(str).join('_'); | ||
} | ||
var reFindNumbers0 = /^(\d*)$/gm; | ||
var reFindNumbers1 = /\.(\d*)\./gm; | ||
var reFindNumbers2 = /^(\d*)\./gm; | ||
var reFindNumbers3 = /\.(\d*$)/gm; | ||
var reFindMultiplePeriods = /\.{2,}/gm; | ||
function makePathArray(str) { | ||
return str.replace('[', '').replace(']', '.').replace(reFindNumbers0, '__int__$1').replace(reFindNumbers1, '.__int__$1.').replace(reFindNumbers2, '__int__$1.').replace(reFindNumbers3, '.__int__$1').replace(reFindMultiplePeriods, '.').split('.').map(function (d) { | ||
if (d.indexOf('__int__') === 0) { | ||
return parseInt(d.substring('__int__'.length), 10); | ||
} | ||
return d; | ||
}); | ||
} | ||
function loopObject(obj, fn, callback) { | ||
Object.keys(obj).forEach(function (key) { | ||
callback(fn(obj[key], key), key); | ||
}); | ||
} | ||
function someObject(obj, fn) { | ||
var found = false; | ||
loopObject(obj, fn, function (result, key) { | ||
if (found) { | ||
return; | ||
} | ||
if (result) { | ||
found = true; | ||
} | ||
}); | ||
return found; | ||
} | ||
function safeStringifyReplace(set) { | ||
return function (key, value) { | ||
if (_typeof(value) === 'object' || Array.isArray(value)) { | ||
if (set.has(value)) { | ||
return '(circular value)'; | ||
} | ||
set.add(value); | ||
} | ||
return typeof value === 'function' ? undefined : value; | ||
}; | ||
} | ||
exports.splitFormProps = splitFormProps; | ||
@@ -1250,0 +1356,0 @@ exports.useField = useField; |
{ | ||
"name": "react-form", | ||
"version": "4.0.0-alpha.11", | ||
"version": "4.0.0-alpha.12", | ||
"description": "⚛️ 💼 React hooks for managing form state and lifecycle", | ||
@@ -5,0 +5,0 @@ "author": "tannerlinsley", |
@@ -28,3 +28,3 @@ # ⚛️ 💼 React Form | ||
- Highly practical validation API with 1st-class asynchronous support | ||
- Built-in validation debouncing with auto cancellation for stale promises | ||
- Built-in validation debouncing with auto cancellation for stale validations | ||
- Field Scoping for deeply nested form values | ||
@@ -406,2 +406,47 @@ - No nonsense meta management for both forms and form fields | ||
Validation in React Form supports validation both individual fields and the entire form. | ||
A form submission can be attempted when either: | ||
- The form has not been touched `!instance.meta.isTouched` | ||
**OR** | ||
- All fields **with a validation option** | ||
- Have been touched (`field.meta.isTouched`) | ||
- Are not validating (`!field.meta.isValidating`) | ||
- Do not have an error (`field.meta.error`) | ||
- The form has been touched `instance.meta.isTouched` | ||
- The form is not validating `!instance.meta.isValidating` | ||
- The form does not have an error `instance.meta.error` | ||
To simplify handling this state, the following additional booleans are available on the `instance.meta`: | ||
- `instance.meta.fieldsAreValidating` | ||
- Will be `true` if there are any fields validating | ||
- `instance.meta.fieldsAreValid` | ||
- Will be `true` if there are no fields with an error (`field.meta.error`) | ||
- `instance.meta.isValid` | ||
- Will be `true` if every field is valid and there is no form error (`allFieldsValid && !meta.error`) | ||
- `instance.meta.canSubmit` | ||
- Will be `true` if the form is valid and not in the middle of a submission attempt (`instance.meta.isValid && !instance.meta.isSubmitting`) | ||
### Submission Attempt Flow | ||
Every time a submission attempt is made, the following submission flow will takes place: | ||
- If there are fields that have not been touched or the form has not been touched: | ||
- All fields will be touched (`field.meta.isTouched === true`) | ||
- The form is touched (`instance.meta.isTouched === true`) | ||
- All fields with a `validate` option that have not been touched will be validated | ||
- If the form `validate` option is set and has not been touched, the form will be validated | ||
- The submission attempt will wait for any field and form validations to resolve | ||
- If any field validations or the form validation throw a runtime error | ||
- The submission attempt will abort 🛑 | ||
- Once all validations settle | ||
- A new submission will be attempted with the new post-validation state 🔁 | ||
- If there are any field or form validation(s) errors | ||
- The current submission will abort 🛑 | ||
- The form's `onSubmit` function will be called | ||
### Synchronous Validation | ||
@@ -408,0 +453,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
230773
2258
745