formik
Version:
Forms in React, without tears
1,208 lines (1,078 loc) • 36.1 kB
JavaScript
'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