UNPKG

formik

Version:

Forms in React, without tears

1,208 lines (1,078 loc) 36.1 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var isEqual = _interopDefault(require('react-fast-compare')); var deepmerge = _interopDefault(require('deepmerge')); var clone = _interopDefault(require('lodash/clone')); var toPath = _interopDefault(require('lodash/toPath')); var invariant = _interopDefault(require('tiny-warning')); var hoistNonReactStatics = _interopDefault(require('hoist-non-react-statics')); var cloneDeep = _interopDefault(require('lodash/cloneDeep')); const isFunction = obj => typeof obj === 'function'; const isObject = obj => obj !== null && typeof obj === 'object'; const isInteger = obj => String(Math.floor(Number(obj))) === obj; const isString = obj => Object.prototype.toString.call(obj) === '[object String]'; const isNaN$1 = obj => obj !== obj; const isEmptyChildren = children => React.Children.count(children) === 0; const isPromise = value => isObject(value) && isFunction(value.then); const isInputEvent = value => value && isObject(value) && isObject(value.target); function getActiveElement(doc) { doc = doc || (typeof document !== 'undefined' ? document : undefined); if (typeof doc === 'undefined') { return null; } try { return doc.activeElement || doc.body; } catch (e) { return doc.body; } } function makeCancelable(promise) { let hasCanceled = false; const wrappedPromise = new Promise((resolve, reject) => { promise.then(val => hasCanceled ? reject({ isCanceled: true }) : resolve(val), error => hasCanceled ? reject({ isCanceled: true }) : reject(error)); }); return [wrappedPromise, function cancel() { hasCanceled = true; }]; } function getIn(obj, key, def, p = 0) { const path = toPath(key); while (obj && p < path.length) { obj = obj[path[p++]]; } return obj === undefined ? def : obj; } function setIn(obj, path, value) { let res = clone(obj); let resVal = res; let i = 0; let pathArray = toPath(path); for (; i < pathArray.length - 1; i++) { const currentPath = pathArray[i]; let currentObj = getIn(obj, pathArray.slice(0, i + 1)); if (currentObj) { resVal = resVal[currentPath] = clone(currentObj); } else { const nextPath = pathArray[i + 1]; resVal = resVal[currentPath] = isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {}; } } if ((i === 0 ? obj : resVal)[pathArray[i]] === value) { return obj; } if (value === undefined) { delete resVal[pathArray[i]]; } else { resVal[pathArray[i]] = value; } if (i === 0 && value === undefined) { delete res[pathArray[i]]; } return res; } function setNestedObjectValues(object, value, visited = new WeakMap(), response = {}) { for (let k of Object.keys(object)) { const val = object[k]; if (isObject(val)) { if (!visited.get(val)) { visited.set(val, true); response[k] = Array.isArray(val) ? [] : {}; setNestedObjectValues(val, value, visited, response[k]); } } else { response[k] = value; } } return response; } const PrivateFormikContext = /*#__PURE__*/ React.createContext({}); const FormikProvider = PrivateFormikContext.Provider; const FormikConsumer = PrivateFormikContext.Consumer; function useFormikContext() { return React.useContext(PrivateFormikContext); } function formikReducer(state, msg) { switch (msg.type) { case 'SET_VALUES': return { ...state, values: msg.payload }; case 'SET_TOUCHED': return { ...state, touched: msg.payload }; case 'SET_ERRORS': return { ...state, errors: msg.payload }; case 'SET_STATUS': return { ...state, status: msg.payload }; case 'SET_ISSUBMITTING': return { ...state, isSubmitting: msg.payload }; case 'SET_ISVALIDATING': return { ...state, isValidating: msg.payload }; case 'SET_FIELD_VALUE': return { ...state, values: setIn(state.values, msg.payload.field, msg.payload.value) }; case 'SET_FIELD_TOUCHED': return { ...state, touched: setIn(state.touched, msg.payload.field, msg.payload.value) }; case 'SET_FIELD_ERROR': return { ...state, errors: setIn(state.errors, msg.payload.field, msg.payload.value) }; case 'RESET_FORM': case 'SET_FORMIK_STATE': return { ...state, ...msg.payload }; case 'SUBMIT_ATTEMPT': return { ...state, touched: setNestedObjectValues(state.values, true), isSubmitting: true, submitCount: state.submitCount + 1 }; case 'SUBMIT_FAILURE': return { ...state, isSubmitting: false }; case 'SUBMIT_SUCCESS': return { ...state, isSubmitting: false }; default: return state; } } function usePrevious(val) { const ref = React.useRef(val); React.useEffect(() => { ref.current = val; }, [val]); return ref.current; } function useFormik({ validateOnChange = true, validateOnBlur = true, isInitialValid, enableReinitialize = false, onSubmit, ...rest }) { const props = { validateOnChange, validateOnBlur, onSubmit, ...rest }; const initialValues = React.useRef(props.initialValues); const initialErrors = React.useRef(props.initialErrors || {}); const initialTouched = React.useRef(props.initialTouched || {}); const initialStatus = React.useRef(props.initialStatus); const isMounted = React.useRef(false); const fields = React.useRef({}); React.useEffect(() => { { !(typeof isInitialValid === 'undefined') ? invariant(false, 'isInitialValid has been deprecated and will be removed in future versions of Formik. Please use initialErrors instead.') : void 0; } }, [isInitialValid]); React.useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); const [state, dispatch] = React.useReducer(formikReducer, { values: props.initialValues, errors: props.initialErrors || {}, touched: props.initialTouched || {}, status: props.initialStatus, isSubmitting: false, isValidating: false, submitCount: 0 }); const prevState = usePrevious(state); const runValidateHandler = React.useCallback((values, field) => { return new Promise(resolve => { const maybePromisedErrors = props.validate(values, field); if (maybePromisedErrors === undefined) { resolve({}); } else if (isPromise(maybePromisedErrors)) { maybePromisedErrors.then(() => { resolve({}); }, errors => { resolve(errors); }); } else { resolve(maybePromisedErrors); } }); }, [props.validate]); const runValidationSchema = React.useCallback((values, field) => { return new Promise(resolve => { const validationSchema = props.validationSchema; const schema = isFunction(validationSchema) ? validationSchema(field) : validationSchema; let promise = field && schema.validateAt ? schema.validateAt(field, values) : validateYupSchema(values, schema); promise.then(() => { resolve({}); }, err => { resolve(yupToFormErrors(err)); }); }); }, [props.validationSchema]); const runSingleFieldLevelValidation = React.useCallback((field, value) => { return new Promise(resolve => resolve(fields.current[field].validate(value))).then(x => x, e => e); }, [fields]); const runFieldLevelValidations = React.useCallback(values => { if (fields.current === null) { return Promise.resolve({}); } const fieldKeysWithValidation = Object.keys(fields.current).filter(f => fields.current !== null && fields.current[f] && fields.current[f].validate && isFunction(fields.current[f].validate)); const fieldValidations = fieldKeysWithValidation.length > 0 ? fieldKeysWithValidation.map(f => runSingleFieldLevelValidation(f, getIn(values, f))) : [Promise.resolve('DO_NOT_DELETE_YOU_WILL_BE_FIRED')]; return Promise.all(fieldValidations).then(fieldErrorsList => fieldErrorsList.reduce((prev, curr, index) => { if (curr === 'DO_NOT_DELETE_YOU_WILL_BE_FIRED') { return prev; } if (curr) { prev = setIn(prev, fieldKeysWithValidation[index], curr); } return prev; }, {})); }, [runSingleFieldLevelValidation, fields]); const validateForm = React.useCallback((values = state.values) => { if (props.validationSchema || props.validate || fields.current && Object.keys(fields.current).filter(key => !!fields.current[key].validate).length > 0) { dispatch({ type: 'SET_ISVALIDATING', payload: true }); return Promise.all([runFieldLevelValidations(values), props.validationSchema ? runValidationSchema(values) : {}, props.validate ? runValidateHandler(values) : {}]).then(([fieldErrors, schemaErrors, validateErrors]) => { const combinedErrors = deepmerge.all([fieldErrors, schemaErrors, validateErrors], { arrayMerge }); if (!isEqual(state.errors, combinedErrors)) { dispatch({ type: 'SET_ERRORS', payload: combinedErrors }); } dispatch({ type: 'SET_ISVALIDATING', payload: false }); return combinedErrors; }); } else { return Promise.resolve({}); } }, [props.validate, props.validationSchema, runFieldLevelValidations, runValidateHandler, runValidationSchema, state.errors, state.values, fields]); React.useEffect(() => { if (prevState.values !== state.values && !!validateOnChange && !state.isSubmitting && isMounted.current != null) { const [validate, cancel] = makeCancelable(validateForm()); validate.then(x => x).catch(x => x); return cancel; } return; }, [prevState.values, state.isSubmitting, state.values, validateForm, validateOnChange, isMounted]); React.useEffect(() => { if (prevState.touched !== state.touched && !!validateOnBlur && !state.isSubmitting && isMounted.current != null) { const [validate, cancel] = makeCancelable(validateForm()); validate.then(x => x).catch(x => x); return cancel; } return; }, [prevState.touched, state.isSubmitting, state.touched, validateForm, validateOnBlur, isMounted]); const resetForm = React.useCallback(nextState => { const values = nextState && nextState.values ? nextState.values : initialValues.current ? initialValues.current : props.initialValues; const errors = nextState && nextState.errors ? nextState.values : initialErrors.current ? initialErrors.current : props.initialErrors || {}; const touched = nextState && nextState.touched ? nextState.values : initialTouched.current ? initialTouched.current : props.initialTouched || {}; const status = nextState && nextState.status ? nextState.status : initialStatus.current ? initialStatus.current : props.initialStatus; initialValues.current = values; initialErrors.current = errors; initialTouched.current = touched; initialStatus.current = status; dispatch({ type: 'RESET_FORM', payload: { isSubmitting: !!nextState && !!nextState.isSubmitting, errors, touched, status, values, isValidating: !!nextState && !!nextState.isValidating, submitCount: !!nextState && !!nextState.submitCount && typeof nextState.submitCount === 'number' ? nextState.submitCount : 0 } }); }, [props.initialErrors, props.initialStatus, props.initialTouched, props.initialValues]); React.useEffect(() => { if (enableReinitialize && isMounted.current && !isEqual(initialValues.current, props.initialValues)) { resetForm(); } }, [enableReinitialize, props.initialValues, resetForm]); const validateField = React.useCallback(name => { if (fields.current !== null && fields.current[name] && fields.current[name].validate && isFunction(fields.current[name].validate)) { const value = getIn(state.values, name); const maybePromise = fields.current[name].validate(value); if (isPromise(maybePromise)) { dispatch({ type: 'SET_ISVALIDATING', payload: true }); return maybePromise.then(x => x, e => e).then(error => { dispatch({ type: 'SET_FIELD_ERROR', payload: { field: name, value: error } }); dispatch({ type: 'SET_ISVALIDATING', payload: false }); }); } else { dispatch({ type: 'SET_FIELD_ERROR', payload: { field: name, value: maybePromise } }); return Promise.resolve(maybePromise); } } else { return Promise.resolve(); } }, [state.values, fields]); const registerField = React.useCallback((name, { validate }) => { if (fields.current !== null) { fields.current[name] = { validate }; } }, [fields]); const unregisterField = React.useCallback(name => { if (fields.current !== null) { delete fields.current[name]; } }, [fields]); const handleBlur = React.useCallback(eventOrString => { if (isString(eventOrString)) { return event => executeBlur(event, eventOrString); } else { executeBlur(eventOrString); } function executeBlur(e, path) { if (e.persist) { e.persist(); } const { name, id, outerHTML } = e.target; const field = path ? path : name ? name : id; if (!field && "development" !== 'production') { warnAboutMissingIdentifier({ htmlContent: outerHTML, documentationAnchorLink: 'handleblur-e-any--void', handlerName: 'handleBlur' }); } dispatch({ type: 'SET_FIELD_TOUCHED', payload: { field, value: true } }); } }, []); const handleChange = React.useCallback(eventOrPath => { if (isString(eventOrPath)) { return event => executeChange(event, eventOrPath); } else { executeChange(eventOrPath); } function executeChange(eventOrTextValue, maybePath) { let field = maybePath; let val = eventOrTextValue; let parsed; if (!isString(eventOrTextValue)) { if (eventOrTextValue.persist) { eventOrTextValue.persist(); } const { type, name, id, value, checked, outerHTML } = eventOrTextValue.target; field = maybePath ? maybePath : name ? name : id; if (!field && "development" !== 'production') { warnAboutMissingIdentifier({ htmlContent: outerHTML, documentationAnchorLink: 'handlechange-e-reactchangeeventany--void', handlerName: 'handleChange' }); } val = /number|range/.test(type) ? (parsed = parseFloat(value), isNaN(parsed) ? '' : parsed) : /checkbox/.test(type) ? checked : value; } if (field) { dispatch({ type: 'SET_FIELD_VALUE', payload: { field, value: val } }); } } }, []); const setTouched = React.useCallback(touched => { dispatch({ type: 'SET_TOUCHED', payload: touched }); }, []); const setErrors = React.useCallback(errors => { dispatch({ type: 'SET_ERRORS', payload: errors }); }, []); const setValues = React.useCallback(values => { dispatch({ type: 'SET_VALUES', payload: values }); }, []); const setFieldError = React.useCallback((field, value) => { dispatch({ type: 'SET_FIELD_ERROR', payload: { field, value } }); }, []); const setFieldValue = React.useCallback((field, value) => { dispatch({ type: 'SET_FIELD_VALUE', payload: { field, value } }); }, []); const setFieldTouched = React.useCallback((field, touched = true) => { dispatch({ type: 'SET_FIELD_TOUCHED', payload: { field, value: touched } }); }, []); function setFormikState(stateOrCb) { if (isFunction(stateOrCb)) { dispatch({ type: 'SET_FORMIK_STATE', payload: stateOrCb(state) }); } else { dispatch({ type: 'SET_FORMIK_STATE', payload: stateOrCb }); } } const setStatus = React.useCallback(status => { dispatch({ type: 'SET_STATUS', payload: status }); }, []); const setSubmitting = React.useCallback(isSubmitting => { dispatch({ type: 'SET_ISSUBMITTING', payload: isSubmitting }); }, []); const imperativeMethods = { resetForm, validateForm, validateField, setErrors, setFieldError, setFieldTouched, setFieldValue, setStatus, setSubmitting, setTouched, setValues, setFormikState }; const executeSubmit = React.useCallback(() => { return onSubmit(state.values, imperativeMethods); }, [imperativeMethods, onSubmit, state.values]); const submitForm = React.useCallback(() => { dispatch({ type: 'SUBMIT_ATTEMPT' }); return validateForm().then(combinedErrors => { const isActuallyValid = Object.keys(combinedErrors).length === 0; if (isActuallyValid) { Promise.resolve(executeSubmit()).then(() => { if (isMounted.current) { dispatch({ type: 'SUBMIT_SUCCESS' }); } }).catch(_errors => { if (isMounted.current) { dispatch({ type: 'SUBMIT_FAILURE' }); } }); } else if (isMounted.current) { dispatch({ type: 'SUBMIT_FAILURE' }); } }); }, [executeSubmit, validateForm]); const handleSubmit = React.useCallback(e => { if (e && e.preventDefault && isFunction(e.preventDefault)) { e.preventDefault(); } if (e && e.stopPropagation && isFunction(e.stopPropagation)) { e.stopPropagation(); } if (typeof document !== 'undefined') { const activeElement = getActiveElement(); if (activeElement !== null && activeElement instanceof HTMLButtonElement) { !(activeElement.attributes && activeElement.attributes.getNamedItem('type')) ? invariant(false, 'You submitted a Formik form using a button with an unspecified `type` attribute. Most browsers default button elements to `type="submit"`. If this is not a submit button, please add `type="button"`.') : void 0; } } submitForm(); }, [submitForm]); const handleReset = React.useCallback(() => { if (props.onReset) { const maybePromisedOnReset = props.onReset(state.values, imperativeMethods); if (isPromise(maybePromisedOnReset)) { maybePromisedOnReset.then(resetForm); } else { resetForm(); } } else { resetForm(); } }, [imperativeMethods, props.onReset, resetForm, state.values]); const getFieldMeta = React.useCallback(name => { return { value: getIn(state.values, name), error: getIn(state.errors, name), touched: !!getIn(state.touched, name), initialValue: getIn(initialValues.current, name), initialTouched: !!getIn(initialTouched.current, name), initialError: getIn(initialErrors.current, name) }; }, [state.errors, state.touched, state.values]); const getFieldProps = React.useCallback((name, type) => { const field = { name, value: type && (type === 'radio' || type === 'checkbox') ? undefined : getIn(state.values, name), onChange: handleChange, onBlur: handleBlur }; return [field, getFieldMeta(name)]; }, [getFieldMeta, handleBlur, handleChange, state.values]); const dirty = React.useMemo(() => !isEqual(initialValues.current, state.values), [state.values]); const isValid = React.useMemo(() => typeof isInitialValid !== 'undefined' ? dirty ? state.errors && Object.keys(state.errors).length === 0 : isInitialValid !== false && isFunction(isInitialValid) ? isInitialValid(props) : isInitialValid : state.errors && Object.keys(state.errors).length === 0, [isInitialValid, dirty, state.errors, props]); const ctx = { ...state, initialValues: initialValues.current, initialErrors: initialErrors.current, initialTouched: initialTouched.current, initialStatus: initialStatus.current, handleBlur, handleChange, handleReset, handleSubmit, resetForm, setErrors, setFormikState, setFieldTouched, setFieldValue, setFieldError, setStatus, setSubmitting, setTouched, setValues, submitForm, validateForm, validateField, isValid, dirty, unregisterField, registerField, getFieldProps, validateOnBlur, validateOnChange }; return ctx; } function Formik(props) { const formikbag = useFormik(props); const { component, children, render } = props; return React.createElement(FormikProvider, { value: formikbag }, component ? React.createElement(component, formikbag) : render ? render(formikbag) : children ? isFunction(children) ? children(formikbag) : !isEmptyChildren(children) ? React.Children.only(children) : null : null); } function warnAboutMissingIdentifier({ htmlContent, documentationAnchorLink, handlerName }) { console.warn(`Warning: Formik called \`${handlerName}\`, but you forgot to pass an \`id\` or \`name\` attribute to your input: ${htmlContent} Formik cannot determine which value to update. For more info see https://github.com/jaredpalmer/formik#${documentationAnchorLink} `); } function yupToFormErrors(yupError) { let errors = {}; if (yupError.inner.length === 0) { return setIn(errors, yupError.path, yupError.message); } for (let err of yupError.inner) { if (!errors[err.path]) { errors = setIn(errors, err.path, err.message); } } return errors; } function validateYupSchema(values, schema, sync = false, context = {}) { let validateData = {}; for (let k in values) { if (values.hasOwnProperty(k)) { const key = String(k); validateData[key] = values[key] !== '' ? values[key] : undefined; } } return schema[sync ? 'validateSync' : 'validate'](validateData, { abortEarly: false, context: context }); } function arrayMerge(target, source, options) { const destination = target.slice(); source.forEach(function (e, i) { if (typeof destination[i] === 'undefined') { const cloneRequested = options.clone !== false; const shouldClone = cloneRequested && options.isMergeableObject(e); destination[i] = shouldClone ? deepmerge(Array.isArray(e) ? [] : {}, e, options) : e; } else if (options.isMergeableObject(e)) { destination[i] = deepmerge(target[i], e, options); } else if (target.indexOf(e) === -1) { destination.push(e); } }); return destination; } function useField(name, type) { const formik = useFormikContext(); { !formik ? invariant(false, 'useField() / <Field /> must be used underneath a <Formik> component or withFormik() higher order component') : void 0; } return formik.getFieldProps(name, type); } function Field({ validate, name, render, children, as: is = 'input', component, ...props }) { const { validate: _validate, validationSchema: _validationSchema, ...formik } = useFormikContext(); React.useEffect(() => { { !!render ? invariant(false, `<Field render> has been deprecated and will be removed in future versions of Formik. Please use a child callback function instead. To get rid of this warning, replace <Field name="${name}" render={({field, form}) => ...} /> with <Field name="${name}">{({field, form, meta}) => ...}</Field>`) : void 0; !!component ? invariant(false, '<Field component> has been deprecated and will be removed in future versions of Formik. Use <Field as> instead. Note that with the `as` prop, all props are passed directly through and not grouped in `field` object key.') : void 0; !!(is && children && isFunction(children)) ? invariant(false, 'You should not use <Field as> and <Field children> as a function in the same <Field> component; <Field as> will be ignored.') : void 0; !!(component && children && isFunction(children)) ? invariant(false, 'You should not use <Field component> and <Field children> as a function in the same <Field> component; <Field component> will be ignored.') : void 0; !!(render && children && !isEmptyChildren(children)) ? invariant(false, 'You should not use <Field render> and <Field children> in the same <Field> component; <Field children> will be ignored') : void 0; } }, []); React.useEffect(() => { formik.registerField(name, { validate: validate }); return () => { formik.unregisterField(name); }; }, [formik, name, validate]); const [field, meta] = formik.getFieldProps(name, props.type); const legacyBag = { field, form: formik }; if (render) { return render(legacyBag); } if (isFunction(children)) { return children({ ...legacyBag, meta }); } if (component) { if (typeof component === 'string') { const { innerRef, ...rest } = props; return React.createElement(component, { ref: innerRef, ...field, ...rest }, children); } return React.createElement(component, { field, form: formik, ...props }, children); } if (typeof is === 'string') { const { innerRef, ...rest } = props; return React.createElement(is, { ref: innerRef, ...field, ...rest }, children); } return React.createElement(is, { ...field, ...props }, children); } const FastField = Field; function Form(props) { const { handleReset, handleSubmit } = useFormikContext(); return React.createElement("form", Object.assign({ onSubmit: handleSubmit, onReset: handleReset }, props)); } Form.displayName = 'Form'; function withFormik({ mapPropsToValues = vanillaProps => { let val = {}; for (let k in vanillaProps) { if (vanillaProps.hasOwnProperty(k) && typeof vanillaProps[k] !== 'function') { val[k] = vanillaProps[k]; } } return val; }, ...config }) { return function createFormik(Component) { const componentDisplayName = Component.displayName || Component.name || Component.constructor && Component.constructor.name || 'Component'; class C extends React.Component { constructor() { super(...arguments); this.validate = values => { return config.validate(values, this.props); }; this.validationSchema = () => { return isFunction(config.validationSchema) ? config.validationSchema(this.props) : config.validationSchema; }; this.handleSubmit = (values, actions) => { return config.handleSubmit(values, { ...actions, props: this.props }); }; this.renderFormComponent = formikProps => { return React.createElement(Component, Object.assign({}, this.props, formikProps)); }; } render() { const { children, ...props } = this.props; return React.createElement(Formik, Object.assign({}, props, config, { validate: config.validate && this.validate, validationSchema: config.validationSchema && this.validationSchema, initialValues: mapPropsToValues(this.props), initialStatus: config.mapPropsToStatus && config.mapPropsToStatus(this.props), initialErrors: config.mapPropsToErrors && config.mapPropsToErrors(this.props), initialTouched: config.mapPropsToTouched && config.mapPropsToTouched(this.props), onSubmit: this.handleSubmit, render: this.renderFormComponent })); } } C.displayName = `WithFormik(${componentDisplayName})`; return hoistNonReactStatics(C, Component); }; } function connect(Comp) { const C = props => React.createElement(FormikConsumer, null, formik => React.createElement(Comp, Object.assign({}, props, { formik: formik }))); const componentDisplayName = Comp.displayName || Comp.name || Comp.constructor && Comp.constructor.name || 'Component'; C.WrappedComponent = Comp; C.displayName = `FormikConnect(${componentDisplayName})`; return hoistNonReactStatics(C, Comp); } const move = (array, from, to) => { const copy = [...(array || [])]; const value = copy[from]; copy.splice(from, 1); copy.splice(to, 0, value); return copy; }; const swap = (array, indexA, indexB) => { const copy = [...(array || [])]; const a = copy[indexA]; copy[indexA] = copy[indexB]; copy[indexB] = a; return copy; }; const insert = (array, index, value) => { const copy = [...(array || [])]; copy.splice(index, 0, value); return copy; }; const replace = (array, index, value) => { const copy = [...(array || [])]; copy[index] = value; return copy; }; class FieldArrayInner extends React.Component { constructor(props) { super(props); this.updateArrayField = (fn, alterTouched, alterErrors) => { const { name, validateOnChange, formik: { setFormikState, validateForm } } = this.props; setFormikState(prevState => { let updateErrors = typeof alterErrors === 'function' ? alterErrors : fn; let updateTouched = typeof alterTouched === 'function' ? alterTouched : fn; return { ...prevState, values: setIn(prevState.values, name, fn(getIn(prevState.values, name))), errors: alterErrors ? setIn(prevState.errors, name, updateErrors(getIn(prevState.errors, name))) : prevState.errors, touched: alterTouched ? setIn(prevState.touched, name, updateTouched(getIn(prevState.touched, name))) : prevState.touched }; }, () => { if (validateOnChange) { validateForm(); } }); }; this.push = value => this.updateArrayField(array => [...(array || []), cloneDeep(value)], false, false); this.handlePush = value => () => this.push(value); this.swap = (indexA, indexB) => this.updateArrayField(array => swap(array, indexA, indexB), true, true); this.handleSwap = (indexA, indexB) => () => this.swap(indexA, indexB); this.move = (from, to) => this.updateArrayField(array => move(array, from, to), true, true); this.handleMove = (from, to) => () => this.move(from, to); this.insert = (index, value) => this.updateArrayField(array => insert(array, index, value), array => insert(array, index, null), array => insert(array, index, null)); this.handleInsert = (index, value) => () => this.insert(index, value); this.replace = (index, value) => this.updateArrayField(array => replace(array, index, value), false, false); this.handleReplace = (index, value) => () => this.replace(index, value); this.unshift = value => { let length = -1; this.updateArrayField(array => { const arr = array ? [value, ...array] : [value]; if (length < 0) { length = arr.length; } return arr; }, array => { const arr = array ? [null, ...array] : [null]; if (length < 0) { length = arr.length; } return arr; }, array => { const arr = array ? [null, ...array] : [null]; if (length < 0) { length = arr.length; } return arr; }); return length; }; this.handleUnshift = value => () => this.unshift(value); this.handleRemove = index => () => this.remove(index); this.handlePop = () => () => this.pop(); this.remove = this.remove.bind(this); this.pop = this.pop.bind(this); } remove(index) { let result; this.updateArrayField(array => { const copy = array ? [...array] : []; if (!result) { result = copy[index]; } if (isFunction(copy.splice)) { copy.splice(index, 1); } return copy; }, true, true); return result; } pop() { let result; this.updateArrayField(array => { const tmp = array; if (!result) { result = tmp && tmp.pop && tmp.pop(); } return tmp; }, true, true); return result; } render() { const arrayHelpers = { push: this.push, pop: this.pop, swap: this.swap, move: this.move, insert: this.insert, replace: this.replace, unshift: this.unshift, remove: this.remove, handlePush: this.handlePush, handlePop: this.handlePop, handleSwap: this.handleSwap, handleMove: this.handleMove, handleInsert: this.handleInsert, handleReplace: this.handleReplace, handleUnshift: this.handleUnshift, handleRemove: this.handleRemove }; const { component, render, children, name, formik: { validate: _validate, validationSchema: _validationSchema, ...restOfFormik } } = this.props; const props = { ...arrayHelpers, form: restOfFormik, name }; return component ? React.createElement(component, props) : render ? render(props) : children ? typeof children === 'function' ? children(props) : !isEmptyChildren(children) ? React.Children.only(children) : null : null; } } FieldArrayInner.defaultProps = { validateOnChange: true }; const FieldArray = /*#__PURE__*/ connect(FieldArrayInner); class ErrorMessageImpl extends React.Component { shouldComponentUpdate(props) { if (getIn(this.props.formik.errors, this.props.name) !== getIn(props.formik.errors, this.props.name) || getIn(this.props.formik.touched, this.props.name) !== getIn(props.formik.touched, this.props.name) || Object.keys(this.props).length !== Object.keys(props).length) { return true; } else { return false; } } render() { let { component, formik, render, children, name, ...rest } = this.props; const touch = getIn(formik.touched, name); const error = getIn(formik.errors, name); return !!touch && !!error ? render ? isFunction(render) ? render(error) : null : children ? isFunction(children) ? children(error) : null : component ? React.createElement(component, rest, error) : error : null; } } const ErrorMessage = /*#__PURE__*/ connect(ErrorMessageImpl); exports.ErrorMessage = ErrorMessage; exports.FastField = FastField; exports.Field = Field; exports.FieldArray = FieldArray; exports.Form = Form; exports.Formik = Formik; exports.FormikConsumer = FormikConsumer; exports.FormikProvider = FormikProvider; exports.connect = connect; exports.getActiveElement = getActiveElement; exports.getIn = getIn; exports.insert = insert; exports.isEmptyChildren = isEmptyChildren; exports.isFunction = isFunction; exports.isInputEvent = isInputEvent; exports.isInteger = isInteger; exports.isNaN = isNaN$1; exports.isObject = isObject; exports.isPromise = isPromise; exports.isString = isString; exports.makeCancelable = makeCancelable; exports.move = move; exports.replace = replace; exports.setIn = setIn; exports.setNestedObjectValues = setNestedObjectValues; exports.swap = swap; exports.useField = useField; exports.useFormik = useFormik; exports.useFormikContext = useFormikContext; exports.validateYupSchema = validateYupSchema; exports.withFormik = withFormik; exports.yupToFormErrors = yupToFormErrors; //# sourceMappingURL=formik.cjs.development.js.map