UNPKG

68.3 kBJavaScriptView Raw
1import { Children, createContext, useContext, useRef, useEffect, useReducer, useCallback, useMemo, useImperativeHandle, createElement, useLayoutEffect, forwardRef, Component } from 'react';
2import isEqual from 'react-fast-compare';
3import deepmerge from 'deepmerge';
4import isPlainObject from 'lodash-es/isPlainObject';
5import clone from 'lodash-es/clone';
6import toPath from 'lodash-es/toPath';
7import invariant from 'tiny-warning';
8import hoistNonReactStatics from 'hoist-non-react-statics';
9import cloneDeep from 'lodash-es/cloneDeep';
10
11function _extends() {
12 _extends = Object.assign || function (target) {
13 for (var i = 1; i < arguments.length; i++) {
14 var source = arguments[i];
15
16 for (var key in source) {
17 if (Object.prototype.hasOwnProperty.call(source, key)) {
18 target[key] = source[key];
19 }
20 }
21 }
22
23 return target;
24 };
25
26 return _extends.apply(this, arguments);
27}
28
29function _inheritsLoose(subClass, superClass) {
30 subClass.prototype = Object.create(superClass.prototype);
31 subClass.prototype.constructor = subClass;
32 subClass.__proto__ = superClass;
33}
34
35function _objectWithoutPropertiesLoose(source, excluded) {
36 if (source == null) return {};
37 var target = {};
38 var sourceKeys = Object.keys(source);
39 var key, i;
40
41 for (i = 0; i < sourceKeys.length; i++) {
42 key = sourceKeys[i];
43 if (excluded.indexOf(key) >= 0) continue;
44 target[key] = source[key];
45 }
46
47 return target;
48}
49
50function _assertThisInitialized(self) {
51 if (self === void 0) {
52 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
53 }
54
55 return self;
56}
57
58/** @private is the value an empty array? */
59
60var isEmptyArray = function isEmptyArray(value) {
61 return Array.isArray(value) && value.length === 0;
62};
63/** @private is the given object a Function? */
64
65var isFunction = function isFunction(obj) {
66 return typeof obj === 'function';
67};
68/** @private is the given object an Object? */
69
70var isObject = function isObject(obj) {
71 return obj !== null && typeof obj === 'object';
72};
73/** @private is the given object an integer? */
74
75var isInteger = function isInteger(obj) {
76 return String(Math.floor(Number(obj))) === obj;
77};
78/** @private is the given object a string? */
79
80var isString = function isString(obj) {
81 return Object.prototype.toString.call(obj) === '[object String]';
82};
83/** @private is the given object a NaN? */
84// eslint-disable-next-line no-self-compare
85
86var isNaN$1 = function isNaN(obj) {
87 return obj !== obj;
88};
89/** @private Does a React component have exactly 0 children? */
90
91var isEmptyChildren = function isEmptyChildren(children) {
92 return Children.count(children) === 0;
93};
94/** @private is the given object/value a promise? */
95
96var isPromise = function isPromise(value) {
97 return isObject(value) && isFunction(value.then);
98};
99/** @private is the given object/value a type of synthetic event? */
100
101var isInputEvent = function isInputEvent(value) {
102 return value && isObject(value) && isObject(value.target);
103};
104/**
105 * Same as document.activeElement but wraps in a try-catch block. In IE it is
106 * not safe to call document.activeElement if there is nothing focused.
107 *
108 * The activeElement will be null only if the document or document body is not
109 * yet defined.
110 *
111 * @param {?Document} doc Defaults to current document.
112 * @return {Element | null}
113 * @see https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getActiveElement.js
114 */
115
116function getActiveElement(doc) {
117 doc = doc || (typeof document !== 'undefined' ? document : undefined);
118
119 if (typeof doc === 'undefined') {
120 return null;
121 }
122
123 try {
124 return doc.activeElement || doc.body;
125 } catch (e) {
126 return doc.body;
127 }
128}
129/**
130 * Deeply get a value from an object via its path.
131 */
132
133function getIn(obj, key, def, p) {
134 if (p === void 0) {
135 p = 0;
136 }
137
138 var path = toPath(key);
139
140 while (obj && p < path.length) {
141 obj = obj[path[p++]];
142 }
143
144 return obj === undefined ? def : obj;
145}
146/**
147 * Deeply set a value from in object via it's path. If the value at `path`
148 * has changed, return a shallow copy of obj with `value` set at `path`.
149 * If `value` has not changed, return the original `obj`.
150 *
151 * Existing objects / arrays along `path` are also shallow copied. Sibling
152 * objects along path retain the same internal js reference. Since new
153 * objects / arrays are only created along `path`, we can test if anything
154 * changed in a nested structure by comparing the object's reference in
155 * the old and new object, similar to how russian doll cache invalidation
156 * works.
157 *
158 * In earlier versions of this function, which used cloneDeep, there were
159 * issues whereby settings a nested value would mutate the parent
160 * instead of creating a new object. `clone` avoids that bug making a
161 * shallow copy of the objects along the update path
162 * so no object is mutated in place.
163 *
164 * Before changing this function, please read through the following
165 * discussions.
166 *
167 * @see https://github.com/developit/linkstate
168 * @see https://github.com/jaredpalmer/formik/pull/123
169 */
170
171function setIn(obj, path, value) {
172 var res = clone(obj); // this keeps inheritance when obj is a class
173
174 var resVal = res;
175 var i = 0;
176 var pathArray = toPath(path);
177
178 for (; i < pathArray.length - 1; i++) {
179 var currentPath = pathArray[i];
180 var currentObj = getIn(obj, pathArray.slice(0, i + 1));
181
182 if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {
183 resVal = resVal[currentPath] = clone(currentObj);
184 } else {
185 var nextPath = pathArray[i + 1];
186 resVal = resVal[currentPath] = isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};
187 }
188 } // Return original object if new value is the same as current
189
190
191 if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {
192 return obj;
193 }
194
195 if (value === undefined) {
196 delete resVal[pathArray[i]];
197 } else {
198 resVal[pathArray[i]] = value;
199 } // If the path array has a single element, the loop did not run.
200 // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.
201
202
203 if (i === 0 && value === undefined) {
204 delete res[pathArray[i]];
205 }
206
207 return res;
208}
209/**
210 * Recursively a set the same value for all keys and arrays nested object, cloning
211 * @param object
212 * @param value
213 * @param visited
214 * @param response
215 */
216
217function setNestedObjectValues(object, value, visited, response) {
218 if (visited === void 0) {
219 visited = new WeakMap();
220 }
221
222 if (response === void 0) {
223 response = {};
224 }
225
226 for (var _i = 0, _Object$keys = Object.keys(object); _i < _Object$keys.length; _i++) {
227 var k = _Object$keys[_i];
228 var val = object[k];
229
230 if (isObject(val)) {
231 if (!visited.get(val)) {
232 visited.set(val, true); // In order to keep array values consistent for both dot path and
233 // bracket syntax, we need to check if this is an array so that
234 // this will output { friends: [true] } and not { friends: { "0": true } }
235
236 response[k] = Array.isArray(val) ? [] : {};
237 setNestedObjectValues(val, value, visited, response[k]);
238 }
239 } else {
240 response[k] = value;
241 }
242 }
243
244 return response;
245}
246
247var FormikContext = /*#__PURE__*/createContext(undefined);
248FormikContext.displayName = 'FormikContext';
249var FormikProvider = FormikContext.Provider;
250var FormikConsumer = FormikContext.Consumer;
251function useFormikContext() {
252 var formik = useContext(FormikContext);
253 !!!formik ? process.env.NODE_ENV !== "production" ? invariant(false, "Formik context is undefined, please verify you are calling useFormikContext() as child of a <Formik> component.") : invariant(false) : void 0;
254 return formik;
255}
256
257function formikReducer(state, msg) {
258 switch (msg.type) {
259 case 'SET_VALUES':
260 return _extends({}, state, {
261 values: msg.payload
262 });
263
264 case 'SET_TOUCHED':
265 return _extends({}, state, {
266 touched: msg.payload
267 });
268
269 case 'SET_ERRORS':
270 if (isEqual(state.errors, msg.payload)) {
271 return state;
272 }
273
274 return _extends({}, state, {
275 errors: msg.payload
276 });
277
278 case 'SET_STATUS':
279 return _extends({}, state, {
280 status: msg.payload
281 });
282
283 case 'SET_ISSUBMITTING':
284 return _extends({}, state, {
285 isSubmitting: msg.payload
286 });
287
288 case 'SET_ISVALIDATING':
289 return _extends({}, state, {
290 isValidating: msg.payload
291 });
292
293 case 'SET_FIELD_VALUE':
294 return _extends({}, state, {
295 values: setIn(state.values, msg.payload.field, msg.payload.value)
296 });
297
298 case 'SET_FIELD_TOUCHED':
299 return _extends({}, state, {
300 touched: setIn(state.touched, msg.payload.field, msg.payload.value)
301 });
302
303 case 'SET_FIELD_ERROR':
304 return _extends({}, state, {
305 errors: setIn(state.errors, msg.payload.field, msg.payload.value)
306 });
307
308 case 'RESET_FORM':
309 return _extends({}, state, msg.payload);
310
311 case 'SET_FORMIK_STATE':
312 return msg.payload(state);
313
314 case 'SUBMIT_ATTEMPT':
315 return _extends({}, state, {
316 touched: setNestedObjectValues(state.values, true),
317 isSubmitting: true,
318 submitCount: state.submitCount + 1
319 });
320
321 case 'SUBMIT_FAILURE':
322 return _extends({}, state, {
323 isSubmitting: false
324 });
325
326 case 'SUBMIT_SUCCESS':
327 return _extends({}, state, {
328 isSubmitting: false
329 });
330
331 default:
332 return state;
333 }
334} // Initial empty states // objects
335
336
337var emptyErrors = {};
338var emptyTouched = {};
339function useFormik(_ref) {
340 var _ref$validateOnChange = _ref.validateOnChange,
341 validateOnChange = _ref$validateOnChange === void 0 ? true : _ref$validateOnChange,
342 _ref$validateOnBlur = _ref.validateOnBlur,
343 validateOnBlur = _ref$validateOnBlur === void 0 ? true : _ref$validateOnBlur,
344 _ref$validateOnMount = _ref.validateOnMount,
345 validateOnMount = _ref$validateOnMount === void 0 ? false : _ref$validateOnMount,
346 isInitialValid = _ref.isInitialValid,
347 _ref$enableReinitiali = _ref.enableReinitialize,
348 enableReinitialize = _ref$enableReinitiali === void 0 ? false : _ref$enableReinitiali,
349 onSubmit = _ref.onSubmit,
350 rest = _objectWithoutPropertiesLoose(_ref, ["validateOnChange", "validateOnBlur", "validateOnMount", "isInitialValid", "enableReinitialize", "onSubmit"]);
351
352 var props = _extends({
353 validateOnChange: validateOnChange,
354 validateOnBlur: validateOnBlur,
355 validateOnMount: validateOnMount,
356 onSubmit: onSubmit
357 }, rest);
358
359 var initialValues = useRef(props.initialValues);
360 var initialErrors = useRef(props.initialErrors || emptyErrors);
361 var initialTouched = useRef(props.initialTouched || emptyTouched);
362 var initialStatus = useRef(props.initialStatus);
363 var isMounted = useRef(false);
364 var fieldRegistry = useRef({});
365
366 if (process.env.NODE_ENV !== "production") {
367 // eslint-disable-next-line react-hooks/rules-of-hooks
368 useEffect(function () {
369 !(typeof isInitialValid === 'undefined') ? process.env.NODE_ENV !== "production" ? invariant(false, 'isInitialValid has been deprecated and will be removed in future versions of Formik. Please use initialErrors or validateOnMount instead.') : invariant(false) : void 0; // eslint-disable-next-line
370 }, []);
371 }
372
373 useEffect(function () {
374 isMounted.current = true;
375 return function () {
376 isMounted.current = false;
377 };
378 }, []);
379
380 var _React$useReducer = useReducer(formikReducer, {
381 values: props.initialValues,
382 errors: props.initialErrors || emptyErrors,
383 touched: props.initialTouched || emptyTouched,
384 status: props.initialStatus,
385 isSubmitting: false,
386 isValidating: false,
387 submitCount: 0
388 }),
389 state = _React$useReducer[0],
390 dispatch = _React$useReducer[1];
391
392 var runValidateHandler = useCallback(function (values, field) {
393 return new Promise(function (resolve, reject) {
394 var maybePromisedErrors = props.validate(values, field);
395
396 if (maybePromisedErrors == null) {
397 // use loose null check here on purpose
398 resolve(emptyErrors);
399 } else if (isPromise(maybePromisedErrors)) {
400 maybePromisedErrors.then(function (errors) {
401 resolve(errors || emptyErrors);
402 }, function (actualException) {
403 if (process.env.NODE_ENV !== 'production') {
404 console.warn("Warning: An unhandled error was caught during validation in <Formik validate />", actualException);
405 }
406
407 reject(actualException);
408 });
409 } else {
410 resolve(maybePromisedErrors);
411 }
412 });
413 }, [props.validate]);
414 /**
415 * Run validation against a Yup schema and optionally run a function if successful
416 */
417
418 var runValidationSchema = useCallback(function (values, field) {
419 var validationSchema = props.validationSchema;
420 var schema = isFunction(validationSchema) ? validationSchema(field) : validationSchema;
421 var promise = field && schema.validateAt ? schema.validateAt(field, values) : validateYupSchema(values, schema);
422 return new Promise(function (resolve, reject) {
423 promise.then(function () {
424 resolve(emptyErrors);
425 }, function (err) {
426 // Yup will throw a validation error if validation fails. We catch those and
427 // resolve them into Formik errors. We can sniff if something is a Yup error
428 // by checking error.name.
429 // @see https://github.com/jquense/yup#validationerrorerrors-string--arraystring-value-any-path-string
430 if (err.name === 'ValidationError') {
431 resolve(yupToFormErrors(err));
432 } else {
433 // We throw any other errors
434 if (process.env.NODE_ENV !== 'production') {
435 console.warn("Warning: An unhandled error was caught during validation in <Formik validationSchema />", err);
436 }
437
438 reject(err);
439 }
440 });
441 });
442 }, [props.validationSchema]);
443 var runSingleFieldLevelValidation = useCallback(function (field, value) {
444 return new Promise(function (resolve) {
445 return resolve(fieldRegistry.current[field].validate(value));
446 });
447 }, []);
448 var runFieldLevelValidations = useCallback(function (values) {
449 var fieldKeysWithValidation = Object.keys(fieldRegistry.current).filter(function (f) {
450 return isFunction(fieldRegistry.current[f].validate);
451 }); // Construct an array with all of the field validation functions
452
453 var fieldValidations = fieldKeysWithValidation.length > 0 ? fieldKeysWithValidation.map(function (f) {
454 return runSingleFieldLevelValidation(f, getIn(values, f));
455 }) : [Promise.resolve('DO_NOT_DELETE_YOU_WILL_BE_FIRED')]; // use special case ;)
456
457 return Promise.all(fieldValidations).then(function (fieldErrorsList) {
458 return fieldErrorsList.reduce(function (prev, curr, index) {
459 if (curr === 'DO_NOT_DELETE_YOU_WILL_BE_FIRED') {
460 return prev;
461 }
462
463 if (curr) {
464 prev = setIn(prev, fieldKeysWithValidation[index], curr);
465 }
466
467 return prev;
468 }, {});
469 });
470 }, [runSingleFieldLevelValidation]); // Run all validations and return the result
471
472 var runAllValidations = useCallback(function (values) {
473 return Promise.all([runFieldLevelValidations(values), props.validationSchema ? runValidationSchema(values) : {}, props.validate ? runValidateHandler(values) : {}]).then(function (_ref2) {
474 var fieldErrors = _ref2[0],
475 schemaErrors = _ref2[1],
476 validateErrors = _ref2[2];
477 var combinedErrors = deepmerge.all([fieldErrors, schemaErrors, validateErrors], {
478 arrayMerge: arrayMerge
479 });
480 return combinedErrors;
481 });
482 }, [props.validate, props.validationSchema, runFieldLevelValidations, runValidateHandler, runValidationSchema]); // Run all validations methods and update state accordingly
483
484 var validateFormWithHighPriority = useEventCallback(function (values) {
485 if (values === void 0) {
486 values = state.values;
487 }
488
489 dispatch({
490 type: 'SET_ISVALIDATING',
491 payload: true
492 });
493 return runAllValidations(values).then(function (combinedErrors) {
494 if (!!isMounted.current) {
495 dispatch({
496 type: 'SET_ISVALIDATING',
497 payload: false
498 });
499 dispatch({
500 type: 'SET_ERRORS',
501 payload: combinedErrors
502 });
503 }
504
505 return combinedErrors;
506 });
507 });
508 useEffect(function () {
509 if (validateOnMount && isMounted.current === true && isEqual(initialValues.current, props.initialValues)) {
510 validateFormWithHighPriority(initialValues.current);
511 }
512 }, [validateOnMount, validateFormWithHighPriority]);
513 var resetForm = useCallback(function (nextState) {
514 var values = nextState && nextState.values ? nextState.values : initialValues.current;
515 var errors = nextState && nextState.errors ? nextState.errors : initialErrors.current ? initialErrors.current : props.initialErrors || {};
516 var touched = nextState && nextState.touched ? nextState.touched : initialTouched.current ? initialTouched.current : props.initialTouched || {};
517 var status = nextState && nextState.status ? nextState.status : initialStatus.current ? initialStatus.current : props.initialStatus;
518 initialValues.current = values;
519 initialErrors.current = errors;
520 initialTouched.current = touched;
521 initialStatus.current = status;
522
523 var dispatchFn = function dispatchFn() {
524 dispatch({
525 type: 'RESET_FORM',
526 payload: {
527 isSubmitting: !!nextState && !!nextState.isSubmitting,
528 errors: errors,
529 touched: touched,
530 status: status,
531 values: values,
532 isValidating: !!nextState && !!nextState.isValidating,
533 submitCount: !!nextState && !!nextState.submitCount && typeof nextState.submitCount === 'number' ? nextState.submitCount : 0
534 }
535 });
536 };
537
538 if (props.onReset) {
539 var maybePromisedOnReset = props.onReset(state.values, imperativeMethods);
540
541 if (isPromise(maybePromisedOnReset)) {
542 maybePromisedOnReset.then(dispatchFn);
543 } else {
544 dispatchFn();
545 }
546 } else {
547 dispatchFn();
548 }
549 }, [props.initialErrors, props.initialStatus, props.initialTouched]);
550 useEffect(function () {
551 if (isMounted.current === true && !isEqual(initialValues.current, props.initialValues)) {
552 if (enableReinitialize) {
553 initialValues.current = props.initialValues;
554 resetForm();
555 }
556
557 if (validateOnMount) {
558 validateFormWithHighPriority(initialValues.current);
559 }
560 }
561 }, [enableReinitialize, props.initialValues, resetForm, validateOnMount, validateFormWithHighPriority]);
562 useEffect(function () {
563 if (enableReinitialize && isMounted.current === true && !isEqual(initialErrors.current, props.initialErrors)) {
564 initialErrors.current = props.initialErrors || emptyErrors;
565 dispatch({
566 type: 'SET_ERRORS',
567 payload: props.initialErrors || emptyErrors
568 });
569 }
570 }, [enableReinitialize, props.initialErrors]);
571 useEffect(function () {
572 if (enableReinitialize && isMounted.current === true && !isEqual(initialTouched.current, props.initialTouched)) {
573 initialTouched.current = props.initialTouched || emptyTouched;
574 dispatch({
575 type: 'SET_TOUCHED',
576 payload: props.initialTouched || emptyTouched
577 });
578 }
579 }, [enableReinitialize, props.initialTouched]);
580 useEffect(function () {
581 if (enableReinitialize && isMounted.current === true && !isEqual(initialStatus.current, props.initialStatus)) {
582 initialStatus.current = props.initialStatus;
583 dispatch({
584 type: 'SET_STATUS',
585 payload: props.initialStatus
586 });
587 }
588 }, [enableReinitialize, props.initialStatus, props.initialTouched]);
589 var validateField = useEventCallback(function (name) {
590 // This will efficiently validate a single field by avoiding state
591 // changes if the validation function is synchronous. It's different from
592 // what is called when using validateForm.
593 if (fieldRegistry.current[name] && isFunction(fieldRegistry.current[name].validate)) {
594 var value = getIn(state.values, name);
595 var maybePromise = fieldRegistry.current[name].validate(value);
596
597 if (isPromise(maybePromise)) {
598 // Only flip isValidating if the function is async.
599 dispatch({
600 type: 'SET_ISVALIDATING',
601 payload: true
602 });
603 return maybePromise.then(function (x) {
604 return x;
605 }).then(function (error) {
606 dispatch({
607 type: 'SET_FIELD_ERROR',
608 payload: {
609 field: name,
610 value: error
611 }
612 });
613 dispatch({
614 type: 'SET_ISVALIDATING',
615 payload: false
616 });
617 });
618 } else {
619 dispatch({
620 type: 'SET_FIELD_ERROR',
621 payload: {
622 field: name,
623 value: maybePromise
624 }
625 });
626 return Promise.resolve(maybePromise);
627 }
628 } else if (props.validationSchema) {
629 dispatch({
630 type: 'SET_ISVALIDATING',
631 payload: true
632 });
633 return runValidationSchema(state.values, name).then(function (x) {
634 return x;
635 }).then(function (error) {
636 dispatch({
637 type: 'SET_FIELD_ERROR',
638 payload: {
639 field: name,
640 value: error[name]
641 }
642 });
643 dispatch({
644 type: 'SET_ISVALIDATING',
645 payload: false
646 });
647 });
648 }
649
650 return Promise.resolve();
651 });
652 var registerField = useCallback(function (name, _ref3) {
653 var validate = _ref3.validate;
654 fieldRegistry.current[name] = {
655 validate: validate
656 };
657 }, []);
658 var unregisterField = useCallback(function (name) {
659 delete fieldRegistry.current[name];
660 }, []);
661 var setTouched = useEventCallback(function (touched, shouldValidate) {
662 dispatch({
663 type: 'SET_TOUCHED',
664 payload: touched
665 });
666 var willValidate = shouldValidate === undefined ? validateOnBlur : shouldValidate;
667 return willValidate ? validateFormWithHighPriority(state.values) : Promise.resolve();
668 });
669 var setErrors = useCallback(function (errors) {
670 dispatch({
671 type: 'SET_ERRORS',
672 payload: errors
673 });
674 }, []);
675 var setValues = useEventCallback(function (values, shouldValidate) {
676 var resolvedValues = isFunction(values) ? values(state.values) : values;
677 dispatch({
678 type: 'SET_VALUES',
679 payload: resolvedValues
680 });
681 var willValidate = shouldValidate === undefined ? validateOnChange : shouldValidate;
682 return willValidate ? validateFormWithHighPriority(resolvedValues) : Promise.resolve();
683 });
684 var setFieldError = useCallback(function (field, value) {
685 dispatch({
686 type: 'SET_FIELD_ERROR',
687 payload: {
688 field: field,
689 value: value
690 }
691 });
692 }, []);
693 var setFieldValue = useEventCallback(function (field, value, shouldValidate) {
694 dispatch({
695 type: 'SET_FIELD_VALUE',
696 payload: {
697 field: field,
698 value: value
699 }
700 });
701 var willValidate = shouldValidate === undefined ? validateOnChange : shouldValidate;
702 return willValidate ? validateFormWithHighPriority(setIn(state.values, field, value)) : Promise.resolve();
703 });
704 var executeChange = useCallback(function (eventOrTextValue, maybePath) {
705 // By default, assume that the first argument is a string. This allows us to use
706 // handleChange with React Native and React Native Web's onChangeText prop which
707 // provides just the value of the input.
708 var field = maybePath;
709 var val = eventOrTextValue;
710 var parsed; // If the first argument is not a string though, it has to be a synthetic React Event (or a fake one),
711 // so we handle like we would a normal HTML change event.
712
713 if (!isString(eventOrTextValue)) {
714 // If we can, persist the event
715 // @see https://reactjs.org/docs/events.html#event-pooling
716 if (eventOrTextValue.persist) {
717 eventOrTextValue.persist();
718 }
719
720 var target = eventOrTextValue.target ? eventOrTextValue.target : eventOrTextValue.currentTarget;
721 var type = target.type,
722 name = target.name,
723 id = target.id,
724 value = target.value,
725 checked = target.checked,
726 outerHTML = target.outerHTML,
727 options = target.options,
728 multiple = target.multiple;
729 field = maybePath ? maybePath : name ? name : id;
730
731 if (!field && process.env.NODE_ENV !== "production") {
732 warnAboutMissingIdentifier({
733 htmlContent: outerHTML,
734 documentationAnchorLink: 'handlechange-e-reactchangeeventany--void',
735 handlerName: 'handleChange'
736 });
737 }
738
739 val = /number|range/.test(type) ? (parsed = parseFloat(value), isNaN(parsed) ? '' : parsed) : /checkbox/.test(type) // checkboxes
740 ? getValueForCheckbox(getIn(state.values, field), checked, value) : options && multiple // <select multiple>
741 ? getSelectedValues(options) : value;
742 }
743
744 if (field) {
745 // Set form fields by name
746 setFieldValue(field, val);
747 }
748 }, [setFieldValue, state.values]);
749 var handleChange = useEventCallback(function (eventOrPath) {
750 if (isString(eventOrPath)) {
751 return function (event) {
752 return executeChange(event, eventOrPath);
753 };
754 } else {
755 executeChange(eventOrPath);
756 }
757 });
758 var setFieldTouched = useEventCallback(function (field, touched, shouldValidate) {
759 if (touched === void 0) {
760 touched = true;
761 }
762
763 dispatch({
764 type: 'SET_FIELD_TOUCHED',
765 payload: {
766 field: field,
767 value: touched
768 }
769 });
770 var willValidate = shouldValidate === undefined ? validateOnBlur : shouldValidate;
771 return willValidate ? validateFormWithHighPriority(state.values) : Promise.resolve();
772 });
773 var executeBlur = useCallback(function (e, path) {
774 if (e.persist) {
775 e.persist();
776 }
777
778 var _e$target = e.target,
779 name = _e$target.name,
780 id = _e$target.id,
781 outerHTML = _e$target.outerHTML;
782 var field = path ? path : name ? name : id;
783
784 if (!field && process.env.NODE_ENV !== "production") {
785 warnAboutMissingIdentifier({
786 htmlContent: outerHTML,
787 documentationAnchorLink: 'handleblur-e-any--void',
788 handlerName: 'handleBlur'
789 });
790 }
791
792 setFieldTouched(field, true);
793 }, [setFieldTouched]);
794 var handleBlur = useEventCallback(function (eventOrString) {
795 if (isString(eventOrString)) {
796 return function (event) {
797 return executeBlur(event, eventOrString);
798 };
799 } else {
800 executeBlur(eventOrString);
801 }
802 });
803 var setFormikState = useCallback(function (stateOrCb) {
804 if (isFunction(stateOrCb)) {
805 dispatch({
806 type: 'SET_FORMIK_STATE',
807 payload: stateOrCb
808 });
809 } else {
810 dispatch({
811 type: 'SET_FORMIK_STATE',
812 payload: function payload() {
813 return stateOrCb;
814 }
815 });
816 }
817 }, []);
818 var setStatus = useCallback(function (status) {
819 dispatch({
820 type: 'SET_STATUS',
821 payload: status
822 });
823 }, []);
824 var setSubmitting = useCallback(function (isSubmitting) {
825 dispatch({
826 type: 'SET_ISSUBMITTING',
827 payload: isSubmitting
828 });
829 }, []);
830 var submitForm = useEventCallback(function () {
831 dispatch({
832 type: 'SUBMIT_ATTEMPT'
833 });
834 return validateFormWithHighPriority().then(function (combinedErrors) {
835 // In case an error was thrown and passed to the resolved Promise,
836 // `combinedErrors` can be an instance of an Error. We need to check
837 // that and abort the submit.
838 // If we don't do that, calling `Object.keys(new Error())` yields an
839 // empty array, which causes the validation to pass and the form
840 // to be submitted.
841 var isInstanceOfError = combinedErrors instanceof Error;
842 var isActuallyValid = !isInstanceOfError && Object.keys(combinedErrors).length === 0;
843
844 if (isActuallyValid) {
845 // Proceed with submit...
846 //
847 // To respect sync submit fns, we can't simply wrap executeSubmit in a promise and
848 // _always_ dispatch SUBMIT_SUCCESS because isSubmitting would then always be false.
849 // This would be fine in simple cases, but make it impossible to disable submit
850 // buttons where people use callbacks or promises as side effects (which is basically
851 // all of v1 Formik code). Instead, recall that we are inside of a promise chain already,
852 // so we can try/catch executeSubmit(), if it returns undefined, then just bail.
853 // If there are errors, throw em. Otherwise, wrap executeSubmit in a promise and handle
854 // cleanup of isSubmitting on behalf of the consumer.
855 var promiseOrUndefined;
856
857 try {
858 promiseOrUndefined = executeSubmit(); // Bail if it's sync, consumer is responsible for cleaning up
859 // via setSubmitting(false)
860
861 if (promiseOrUndefined === undefined) {
862 return;
863 }
864 } catch (error) {
865 throw error;
866 }
867
868 return Promise.resolve(promiseOrUndefined).then(function (result) {
869 if (!!isMounted.current) {
870 dispatch({
871 type: 'SUBMIT_SUCCESS'
872 });
873 }
874
875 return result;
876 })["catch"](function (_errors) {
877 if (!!isMounted.current) {
878 dispatch({
879 type: 'SUBMIT_FAILURE'
880 }); // This is a legit error rejected by the onSubmit fn
881 // so we don't want to break the promise chain
882
883 throw _errors;
884 }
885 });
886 } else if (!!isMounted.current) {
887 // ^^^ Make sure Formik is still mounted before updating state
888 dispatch({
889 type: 'SUBMIT_FAILURE'
890 }); // throw combinedErrors;
891
892 if (isInstanceOfError) {
893 throw combinedErrors;
894 }
895 }
896
897 return;
898 });
899 });
900 var handleSubmit = useEventCallback(function (e) {
901 if (e && e.preventDefault && isFunction(e.preventDefault)) {
902 e.preventDefault();
903 }
904
905 if (e && e.stopPropagation && isFunction(e.stopPropagation)) {
906 e.stopPropagation();
907 } // Warn if form submission is triggered by a <button> without a
908 // specified `type` attribute during development. This mitigates
909 // a common gotcha in forms with both reset and submit buttons,
910 // where the dev forgets to add type="button" to the reset button.
911
912
913 if (process.env.NODE_ENV !== "production" && typeof document !== 'undefined') {
914 // Safely get the active element (works with IE)
915 var activeElement = getActiveElement();
916
917 if (activeElement !== null && activeElement instanceof HTMLButtonElement) {
918 !(activeElement.attributes && activeElement.attributes.getNamedItem('type')) ? process.env.NODE_ENV !== "production" ? 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"`.') : invariant(false) : void 0;
919 }
920 }
921
922 submitForm()["catch"](function (reason) {
923 console.warn("Warning: An unhandled error was caught from submitForm()", reason);
924 });
925 });
926 var imperativeMethods = {
927 resetForm: resetForm,
928 validateForm: validateFormWithHighPriority,
929 validateField: validateField,
930 setErrors: setErrors,
931 setFieldError: setFieldError,
932 setFieldTouched: setFieldTouched,
933 setFieldValue: setFieldValue,
934 setStatus: setStatus,
935 setSubmitting: setSubmitting,
936 setTouched: setTouched,
937 setValues: setValues,
938 setFormikState: setFormikState,
939 submitForm: submitForm
940 };
941 var executeSubmit = useEventCallback(function () {
942 return onSubmit(state.values, imperativeMethods);
943 });
944 var handleReset = useEventCallback(function (e) {
945 if (e && e.preventDefault && isFunction(e.preventDefault)) {
946 e.preventDefault();
947 }
948
949 if (e && e.stopPropagation && isFunction(e.stopPropagation)) {
950 e.stopPropagation();
951 }
952
953 resetForm();
954 });
955 var getFieldMeta = useCallback(function (name) {
956 return {
957 value: getIn(state.values, name),
958 error: getIn(state.errors, name),
959 touched: !!getIn(state.touched, name),
960 initialValue: getIn(initialValues.current, name),
961 initialTouched: !!getIn(initialTouched.current, name),
962 initialError: getIn(initialErrors.current, name)
963 };
964 }, [state.errors, state.touched, state.values]);
965 var getFieldHelpers = useCallback(function (name) {
966 return {
967 setValue: function setValue(value, shouldValidate) {
968 return setFieldValue(name, value, shouldValidate);
969 },
970 setTouched: function setTouched(value, shouldValidate) {
971 return setFieldTouched(name, value, shouldValidate);
972 },
973 setError: function setError(value) {
974 return setFieldError(name, value);
975 }
976 };
977 }, [setFieldValue, setFieldTouched, setFieldError]);
978 var getFieldProps = useCallback(function (nameOrOptions) {
979 var isAnObject = isObject(nameOrOptions);
980 var name = isAnObject ? nameOrOptions.name : nameOrOptions;
981 var valueState = getIn(state.values, name);
982 var field = {
983 name: name,
984 value: valueState,
985 onChange: handleChange,
986 onBlur: handleBlur
987 };
988
989 if (isAnObject) {
990 var type = nameOrOptions.type,
991 valueProp = nameOrOptions.value,
992 is = nameOrOptions.as,
993 multiple = nameOrOptions.multiple;
994
995 if (type === 'checkbox') {
996 if (valueProp === undefined) {
997 field.checked = !!valueState;
998 } else {
999 field.checked = !!(Array.isArray(valueState) && ~valueState.indexOf(valueProp));
1000 field.value = valueProp;
1001 }
1002 } else if (type === 'radio') {
1003 field.checked = valueState === valueProp;
1004 field.value = valueProp;
1005 } else if (is === 'select' && multiple) {
1006 field.value = field.value || [];
1007 field.multiple = true;
1008 }
1009 }
1010
1011 return field;
1012 }, [handleBlur, handleChange, state.values]);
1013 var dirty = useMemo(function () {
1014 return !isEqual(initialValues.current, state.values);
1015 }, [initialValues.current, state.values]);
1016 var isValid = useMemo(function () {
1017 return 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;
1018 }, [isInitialValid, dirty, state.errors, props]);
1019
1020 var ctx = _extends({}, state, {
1021 initialValues: initialValues.current,
1022 initialErrors: initialErrors.current,
1023 initialTouched: initialTouched.current,
1024 initialStatus: initialStatus.current,
1025 handleBlur: handleBlur,
1026 handleChange: handleChange,
1027 handleReset: handleReset,
1028 handleSubmit: handleSubmit,
1029 resetForm: resetForm,
1030 setErrors: setErrors,
1031 setFormikState: setFormikState,
1032 setFieldTouched: setFieldTouched,
1033 setFieldValue: setFieldValue,
1034 setFieldError: setFieldError,
1035 setStatus: setStatus,
1036 setSubmitting: setSubmitting,
1037 setTouched: setTouched,
1038 setValues: setValues,
1039 submitForm: submitForm,
1040 validateForm: validateFormWithHighPriority,
1041 validateField: validateField,
1042 isValid: isValid,
1043 dirty: dirty,
1044 unregisterField: unregisterField,
1045 registerField: registerField,
1046 getFieldProps: getFieldProps,
1047 getFieldMeta: getFieldMeta,
1048 getFieldHelpers: getFieldHelpers,
1049 validateOnBlur: validateOnBlur,
1050 validateOnChange: validateOnChange,
1051 validateOnMount: validateOnMount
1052 });
1053
1054 return ctx;
1055}
1056function Formik(props) {
1057 var formikbag = useFormik(props);
1058 var component = props.component,
1059 children = props.children,
1060 render = props.render,
1061 innerRef = props.innerRef; // This allows folks to pass a ref to <Formik />
1062
1063 useImperativeHandle(innerRef, function () {
1064 return formikbag;
1065 });
1066
1067 if (process.env.NODE_ENV !== "production") {
1068 // eslint-disable-next-line react-hooks/rules-of-hooks
1069 useEffect(function () {
1070 !!props.render ? process.env.NODE_ENV !== "production" ? invariant(false, "<Formik 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 <Formik render={(props) => ...} /> with <Formik>{(props) => ...}</Formik>") : invariant(false) : void 0; // eslint-disable-next-line
1071 }, []);
1072 }
1073
1074 return createElement(FormikProvider, {
1075 value: formikbag
1076 }, component ? createElement(component, formikbag) : render ? render(formikbag) : children // children come last, always called
1077 ? isFunction(children) ? children(formikbag) : !isEmptyChildren(children) ? Children.only(children) : null : null);
1078}
1079
1080function warnAboutMissingIdentifier(_ref4) {
1081 var htmlContent = _ref4.htmlContent,
1082 documentationAnchorLink = _ref4.documentationAnchorLink,
1083 handlerName = _ref4.handlerName;
1084 console.warn("Warning: Formik called `" + handlerName + "`, but you forgot to pass an `id` or `name` attribute to your input:\n " + htmlContent + "\n Formik cannot determine which value to update. For more info see https://formik.org/docs/api/formik#" + documentationAnchorLink + "\n ");
1085}
1086/**
1087 * Transform Yup ValidationError to a more usable object
1088 */
1089
1090
1091function yupToFormErrors(yupError) {
1092 var errors = {};
1093
1094 if (yupError.inner) {
1095 if (yupError.inner.length === 0) {
1096 return setIn(errors, yupError.path, yupError.message);
1097 }
1098
1099 for (var _iterator = yupError.inner, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
1100 var _ref5;
1101
1102 if (_isArray) {
1103 if (_i >= _iterator.length) break;
1104 _ref5 = _iterator[_i++];
1105 } else {
1106 _i = _iterator.next();
1107 if (_i.done) break;
1108 _ref5 = _i.value;
1109 }
1110
1111 var err = _ref5;
1112
1113 if (!getIn(errors, err.path)) {
1114 errors = setIn(errors, err.path, err.message);
1115 }
1116 }
1117 }
1118
1119 return errors;
1120}
1121/**
1122 * Validate a yup schema.
1123 */
1124
1125function validateYupSchema(values, schema, sync, context) {
1126 if (sync === void 0) {
1127 sync = false;
1128 }
1129
1130 if (context === void 0) {
1131 context = {};
1132 }
1133
1134 var validateData = prepareDataForValidation(values);
1135 return schema[sync ? 'validateSync' : 'validate'](validateData, {
1136 abortEarly: false,
1137 context: context
1138 });
1139}
1140/**
1141 * Recursively prepare values.
1142 */
1143
1144function prepareDataForValidation(values) {
1145 var data = Array.isArray(values) ? [] : {};
1146
1147 for (var k in values) {
1148 if (Object.prototype.hasOwnProperty.call(values, k)) {
1149 var key = String(k);
1150
1151 if (Array.isArray(values[key]) === true) {
1152 data[key] = values[key].map(function (value) {
1153 if (Array.isArray(value) === true || isPlainObject(value)) {
1154 return prepareDataForValidation(value);
1155 } else {
1156 return value !== '' ? value : undefined;
1157 }
1158 });
1159 } else if (isPlainObject(values[key])) {
1160 data[key] = prepareDataForValidation(values[key]);
1161 } else {
1162 data[key] = values[key] !== '' ? values[key] : undefined;
1163 }
1164 }
1165 }
1166
1167 return data;
1168}
1169/**
1170 * deepmerge array merging algorithm
1171 * https://github.com/KyleAMathews/deepmerge#combine-array
1172 */
1173
1174function arrayMerge(target, source, options) {
1175 var destination = target.slice();
1176 source.forEach(function merge(e, i) {
1177 if (typeof destination[i] === 'undefined') {
1178 var cloneRequested = options.clone !== false;
1179 var shouldClone = cloneRequested && options.isMergeableObject(e);
1180 destination[i] = shouldClone ? deepmerge(Array.isArray(e) ? [] : {}, e, options) : e;
1181 } else if (options.isMergeableObject(e)) {
1182 destination[i] = deepmerge(target[i], e, options);
1183 } else if (target.indexOf(e) === -1) {
1184 destination.push(e);
1185 }
1186 });
1187 return destination;
1188}
1189/** Return multi select values based on an array of options */
1190
1191
1192function getSelectedValues(options) {
1193 return Array.from(options).filter(function (el) {
1194 return el.selected;
1195 }).map(function (el) {
1196 return el.value;
1197 });
1198}
1199/** Return the next value for a checkbox */
1200
1201
1202function getValueForCheckbox(currentValue, checked, valueProp) {
1203 // If the current value was a boolean, return a boolean
1204 if (typeof currentValue === 'boolean') {
1205 return Boolean(checked);
1206 } // If the currentValue was not a boolean we want to return an array
1207
1208
1209 var currentArrayOfValues = [];
1210 var isValueInArray = false;
1211 var index = -1;
1212
1213 if (!Array.isArray(currentValue)) {
1214 // eslint-disable-next-line eqeqeq
1215 if (!valueProp || valueProp == 'true' || valueProp == 'false') {
1216 return Boolean(checked);
1217 }
1218 } else {
1219 // If the current value is already an array, use it
1220 currentArrayOfValues = currentValue;
1221 index = currentValue.indexOf(valueProp);
1222 isValueInArray = index >= 0;
1223 } // If the checkbox was checked and the value is not already present in the aray we want to add the new value to the array of values
1224
1225
1226 if (checked && valueProp && !isValueInArray) {
1227 return currentArrayOfValues.concat(valueProp);
1228 } // If the checkbox was unchecked and the value is not in the array, simply return the already existing array of values
1229
1230
1231 if (!isValueInArray) {
1232 return currentArrayOfValues;
1233 } // If the checkbox was unchecked and the value is in the array, remove the value and return the array
1234
1235
1236 return currentArrayOfValues.slice(0, index).concat(currentArrayOfValues.slice(index + 1));
1237} // React currently throws a warning when using useLayoutEffect on the server.
1238// To get around it, we can conditionally useEffect on the server (no-op) and
1239// useLayoutEffect in the browser.
1240// @see https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
1241
1242
1243var useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? useLayoutEffect : useEffect;
1244
1245function useEventCallback(fn) {
1246 var ref = useRef(fn); // we copy a ref to the callback scoped to the current state/props on each render
1247
1248 useIsomorphicLayoutEffect(function () {
1249 ref.current = fn;
1250 });
1251 return useCallback(function () {
1252 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1253 args[_key] = arguments[_key];
1254 }
1255
1256 return ref.current.apply(void 0, args);
1257 }, []);
1258}
1259
1260function useField(propsOrFieldName) {
1261 var formik = useFormikContext();
1262 var getFieldProps = formik.getFieldProps,
1263 getFieldMeta = formik.getFieldMeta,
1264 getFieldHelpers = formik.getFieldHelpers,
1265 registerField = formik.registerField,
1266 unregisterField = formik.unregisterField;
1267 var isAnObject = isObject(propsOrFieldName); // Normalize propsOrFieldName to FieldHookConfig<Val>
1268
1269 var props = isAnObject ? propsOrFieldName : {
1270 name: propsOrFieldName
1271 };
1272 var fieldName = props.name,
1273 validateFn = props.validate;
1274 useEffect(function () {
1275 if (fieldName) {
1276 registerField(fieldName, {
1277 validate: validateFn
1278 });
1279 }
1280
1281 return function () {
1282 if (fieldName) {
1283 unregisterField(fieldName);
1284 }
1285 };
1286 }, [registerField, unregisterField, fieldName, validateFn]);
1287
1288 if (process.env.NODE_ENV !== "production") {
1289 !formik ? process.env.NODE_ENV !== "production" ? invariant(false, 'useField() / <Field /> must be used underneath a <Formik> component or withFormik() higher order component') : invariant(false) : void 0;
1290 }
1291
1292 !fieldName ? process.env.NODE_ENV !== "production" ? invariant(false, 'Invalid field name. Either pass `useField` a string or an object containing a `name` key.') : invariant(false) : void 0;
1293 return [getFieldProps(props), getFieldMeta(fieldName), getFieldHelpers(fieldName)];
1294}
1295function Field(_ref) {
1296 var validate = _ref.validate,
1297 name = _ref.name,
1298 render = _ref.render,
1299 children = _ref.children,
1300 is = _ref.as,
1301 component = _ref.component,
1302 props = _objectWithoutPropertiesLoose(_ref, ["validate", "name", "render", "children", "as", "component"]);
1303
1304 var _useFormikContext = useFormikContext(),
1305 formik = _objectWithoutPropertiesLoose(_useFormikContext, ["validate", "validationSchema"]);
1306
1307 if (process.env.NODE_ENV !== "production") {
1308 // eslint-disable-next-line react-hooks/rules-of-hooks
1309 useEffect(function () {
1310 !!render ? process.env.NODE_ENV !== "production" ? 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>") : invariant(false) : void 0;
1311 !!(is && children && isFunction(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <Field as> and <Field children> as a function in the same <Field> component; <Field as> will be ignored.') : invariant(false) : void 0;
1312 !!(component && children && isFunction(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <Field component> and <Field children> as a function in the same <Field> component; <Field component> will be ignored.') : invariant(false) : void 0;
1313 !!(render && children && !isEmptyChildren(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <Field render> and <Field children> in the same <Field> component; <Field children> will be ignored') : invariant(false) : void 0; // eslint-disable-next-line
1314 }, []);
1315 } // Register field and field-level validation with parent <Formik>
1316
1317
1318 var registerField = formik.registerField,
1319 unregisterField = formik.unregisterField;
1320 useEffect(function () {
1321 registerField(name, {
1322 validate: validate
1323 });
1324 return function () {
1325 unregisterField(name);
1326 };
1327 }, [registerField, unregisterField, name, validate]);
1328 var field = formik.getFieldProps(_extends({
1329 name: name
1330 }, props));
1331 var meta = formik.getFieldMeta(name);
1332 var legacyBag = {
1333 field: field,
1334 form: formik
1335 };
1336
1337 if (render) {
1338 return render(_extends({}, legacyBag, {
1339 meta: meta
1340 }));
1341 }
1342
1343 if (isFunction(children)) {
1344 return children(_extends({}, legacyBag, {
1345 meta: meta
1346 }));
1347 }
1348
1349 if (component) {
1350 // This behavior is backwards compat with earlier Formik 0.9 to 1.x
1351 if (typeof component === 'string') {
1352 var innerRef = props.innerRef,
1353 rest = _objectWithoutPropertiesLoose(props, ["innerRef"]);
1354
1355 return createElement(component, _extends({
1356 ref: innerRef
1357 }, field, rest), children);
1358 } // We don't pass `meta` for backwards compat
1359
1360
1361 return createElement(component, _extends({
1362 field: field,
1363 form: formik
1364 }, props), children);
1365 } // default to input here so we can check for both `as` and `children` above
1366
1367
1368 var asElement = is || 'input';
1369
1370 if (typeof asElement === 'string') {
1371 var _innerRef = props.innerRef,
1372 _rest = _objectWithoutPropertiesLoose(props, ["innerRef"]);
1373
1374 return createElement(asElement, _extends({
1375 ref: _innerRef
1376 }, field, _rest), children);
1377 }
1378
1379 return createElement(asElement, _extends({}, field, props), children);
1380}
1381
1382var Form = /*#__PURE__*/forwardRef(function (props, ref) {
1383 // iOS needs an "action" attribute for nice input: https://stackoverflow.com/a/39485162/406725
1384 // We default the action to "#" in case the preventDefault fails (just updates the URL hash)
1385 var action = props.action,
1386 rest = _objectWithoutPropertiesLoose(props, ["action"]);
1387
1388 var _action = action != null ? action : '#';
1389
1390 var _useFormikContext = useFormikContext(),
1391 handleReset = _useFormikContext.handleReset,
1392 handleSubmit = _useFormikContext.handleSubmit;
1393
1394 return createElement("form", Object.assign({
1395 onSubmit: handleSubmit,
1396 ref: ref,
1397 onReset: handleReset,
1398 action: _action
1399 }, rest));
1400});
1401Form.displayName = 'Form';
1402
1403/**
1404 * A public higher-order component to access the imperative API
1405 */
1406
1407function withFormik(_ref) {
1408 var _ref$mapPropsToValues = _ref.mapPropsToValues,
1409 mapPropsToValues = _ref$mapPropsToValues === void 0 ? function (vanillaProps) {
1410 var val = {};
1411
1412 for (var k in vanillaProps) {
1413 if (vanillaProps.hasOwnProperty(k) && typeof vanillaProps[k] !== 'function') {
1414 // @todo TypeScript fix
1415 val[k] = vanillaProps[k];
1416 }
1417 }
1418
1419 return val;
1420 } : _ref$mapPropsToValues,
1421 config = _objectWithoutPropertiesLoose(_ref, ["mapPropsToValues"]);
1422
1423 return function createFormik(Component$1) {
1424 var componentDisplayName = Component$1.displayName || Component$1.name || Component$1.constructor && Component$1.constructor.name || 'Component';
1425 /**
1426 * We need to use closures here for to provide the wrapped component's props to
1427 * the respective withFormik config methods.
1428 */
1429
1430 var C = /*#__PURE__*/function (_React$Component) {
1431 _inheritsLoose(C, _React$Component);
1432
1433 function C() {
1434 var _this;
1435
1436 _this = _React$Component.apply(this, arguments) || this;
1437
1438 _this.validate = function (values) {
1439 return config.validate(values, _this.props);
1440 };
1441
1442 _this.validationSchema = function () {
1443 return isFunction(config.validationSchema) ? config.validationSchema(_this.props) : config.validationSchema;
1444 };
1445
1446 _this.handleSubmit = function (values, actions) {
1447 return config.handleSubmit(values, _extends({}, actions, {
1448 props: _this.props
1449 }));
1450 };
1451 /**
1452 * Just avoiding a render callback for perf here
1453 */
1454
1455
1456 _this.renderFormComponent = function (formikProps) {
1457 return createElement(Component$1, Object.assign({}, _this.props, formikProps));
1458 };
1459
1460 return _this;
1461 }
1462
1463 var _proto = C.prototype;
1464
1465 _proto.render = function render() {
1466 var _this$props = this.props,
1467 props = _objectWithoutPropertiesLoose(_this$props, ["children"]);
1468
1469 return createElement(Formik, Object.assign({}, props, config, {
1470 validate: config.validate && this.validate,
1471 validationSchema: config.validationSchema && this.validationSchema,
1472 initialValues: mapPropsToValues(this.props),
1473 initialStatus: config.mapPropsToStatus && config.mapPropsToStatus(this.props),
1474 initialErrors: config.mapPropsToErrors && config.mapPropsToErrors(this.props),
1475 initialTouched: config.mapPropsToTouched && config.mapPropsToTouched(this.props),
1476 onSubmit: this.handleSubmit,
1477 children: this.renderFormComponent
1478 }));
1479 };
1480
1481 return C;
1482 }(Component);
1483
1484 C.displayName = "WithFormik(" + componentDisplayName + ")";
1485 return hoistNonReactStatics(C, Component$1 // cast type to ComponentClass (even if SFC)
1486 );
1487 };
1488}
1489
1490/**
1491 * Connect any component to Formik context, and inject as a prop called `formik`;
1492 * @param Comp React Component
1493 */
1494
1495function connect(Comp) {
1496 var C = function C(props) {
1497 return createElement(FormikConsumer, null, function (formik) {
1498 !!!formik ? process.env.NODE_ENV !== "production" ? invariant(false, "Formik context is undefined, please verify you are rendering <Form>, <Field>, <FastField>, <FieldArray>, or your custom context-using component as a child of a <Formik> component. Component name: " + Comp.name) : invariant(false) : void 0;
1499 return createElement(Comp, Object.assign({}, props, {
1500 formik: formik
1501 }));
1502 });
1503 };
1504
1505 var componentDisplayName = Comp.displayName || Comp.name || Comp.constructor && Comp.constructor.name || 'Component'; // Assign Comp to C.WrappedComponent so we can access the inner component in tests
1506 // For example, <Field.WrappedComponent /> gets us <FieldInner/>
1507
1508 C.WrappedComponent = Comp;
1509 C.displayName = "FormikConnect(" + componentDisplayName + ")";
1510 return hoistNonReactStatics(C, Comp // cast type to ComponentClass (even if SFC)
1511 );
1512}
1513
1514/**
1515 * Some array helpers!
1516 */
1517
1518var move = function move(array, from, to) {
1519 var copy = copyArrayLike(array);
1520 var value = copy[from];
1521 copy.splice(from, 1);
1522 copy.splice(to, 0, value);
1523 return copy;
1524};
1525var swap = function swap(arrayLike, indexA, indexB) {
1526 var copy = copyArrayLike(arrayLike);
1527 var a = copy[indexA];
1528 copy[indexA] = copy[indexB];
1529 copy[indexB] = a;
1530 return copy;
1531};
1532var insert = function insert(arrayLike, index, value) {
1533 var copy = copyArrayLike(arrayLike);
1534 copy.splice(index, 0, value);
1535 return copy;
1536};
1537var replace = function replace(arrayLike, index, value) {
1538 var copy = copyArrayLike(arrayLike);
1539 copy[index] = value;
1540 return copy;
1541};
1542
1543var copyArrayLike = function copyArrayLike(arrayLike) {
1544 if (!arrayLike) {
1545 return [];
1546 } else if (Array.isArray(arrayLike)) {
1547 return [].concat(arrayLike);
1548 } else {
1549 var maxIndex = Object.keys(arrayLike).map(function (key) {
1550 return parseInt(key);
1551 }).reduce(function (max, el) {
1552 return el > max ? el : max;
1553 }, 0);
1554 return Array.from(_extends({}, arrayLike, {
1555 length: maxIndex + 1
1556 }));
1557 }
1558};
1559
1560var FieldArrayInner = /*#__PURE__*/function (_React$Component) {
1561 _inheritsLoose(FieldArrayInner, _React$Component);
1562
1563 function FieldArrayInner(props) {
1564 var _this;
1565
1566 _this = _React$Component.call(this, props) || this;
1567
1568 _this.updateArrayField = function (fn, alterTouched, alterErrors) {
1569 var _this$props = _this.props,
1570 name = _this$props.name,
1571 setFormikState = _this$props.formik.setFormikState;
1572 setFormikState(function (prevState) {
1573 var updateErrors = typeof alterErrors === 'function' ? alterErrors : fn;
1574 var updateTouched = typeof alterTouched === 'function' ? alterTouched : fn; // values fn should be executed before updateErrors and updateTouched,
1575 // otherwise it causes an error with unshift.
1576
1577 var values = setIn(prevState.values, name, fn(getIn(prevState.values, name)));
1578 var fieldError = alterErrors ? updateErrors(getIn(prevState.errors, name)) : undefined;
1579 var fieldTouched = alterTouched ? updateTouched(getIn(prevState.touched, name)) : undefined;
1580
1581 if (isEmptyArray(fieldError)) {
1582 fieldError = undefined;
1583 }
1584
1585 if (isEmptyArray(fieldTouched)) {
1586 fieldTouched = undefined;
1587 }
1588
1589 return _extends({}, prevState, {
1590 values: values,
1591 errors: alterErrors ? setIn(prevState.errors, name, fieldError) : prevState.errors,
1592 touched: alterTouched ? setIn(prevState.touched, name, fieldTouched) : prevState.touched
1593 });
1594 });
1595 };
1596
1597 _this.push = function (value) {
1598 return _this.updateArrayField(function (arrayLike) {
1599 return [].concat(copyArrayLike(arrayLike), [cloneDeep(value)]);
1600 }, false, false);
1601 };
1602
1603 _this.handlePush = function (value) {
1604 return function () {
1605 return _this.push(value);
1606 };
1607 };
1608
1609 _this.swap = function (indexA, indexB) {
1610 return _this.updateArrayField(function (array) {
1611 return swap(array, indexA, indexB);
1612 }, true, true);
1613 };
1614
1615 _this.handleSwap = function (indexA, indexB) {
1616 return function () {
1617 return _this.swap(indexA, indexB);
1618 };
1619 };
1620
1621 _this.move = function (from, to) {
1622 return _this.updateArrayField(function (array) {
1623 return move(array, from, to);
1624 }, true, true);
1625 };
1626
1627 _this.handleMove = function (from, to) {
1628 return function () {
1629 return _this.move(from, to);
1630 };
1631 };
1632
1633 _this.insert = function (index, value) {
1634 return _this.updateArrayField(function (array) {
1635 return insert(array, index, value);
1636 }, function (array) {
1637 return insert(array, index, null);
1638 }, function (array) {
1639 return insert(array, index, null);
1640 });
1641 };
1642
1643 _this.handleInsert = function (index, value) {
1644 return function () {
1645 return _this.insert(index, value);
1646 };
1647 };
1648
1649 _this.replace = function (index, value) {
1650 return _this.updateArrayField(function (array) {
1651 return replace(array, index, value);
1652 }, false, false);
1653 };
1654
1655 _this.handleReplace = function (index, value) {
1656 return function () {
1657 return _this.replace(index, value);
1658 };
1659 };
1660
1661 _this.unshift = function (value) {
1662 var length = -1;
1663
1664 _this.updateArrayField(function (array) {
1665 var arr = array ? [value].concat(array) : [value];
1666
1667 if (length < 0) {
1668 length = arr.length;
1669 }
1670
1671 return arr;
1672 }, function (array) {
1673 var arr = array ? [null].concat(array) : [null];
1674
1675 if (length < 0) {
1676 length = arr.length;
1677 }
1678
1679 return arr;
1680 }, function (array) {
1681 var arr = array ? [null].concat(array) : [null];
1682
1683 if (length < 0) {
1684 length = arr.length;
1685 }
1686
1687 return arr;
1688 });
1689
1690 return length;
1691 };
1692
1693 _this.handleUnshift = function (value) {
1694 return function () {
1695 return _this.unshift(value);
1696 };
1697 };
1698
1699 _this.handleRemove = function (index) {
1700 return function () {
1701 return _this.remove(index);
1702 };
1703 };
1704
1705 _this.handlePop = function () {
1706 return function () {
1707 return _this.pop();
1708 };
1709 }; // We need TypeScript generics on these, so we'll bind them in the constructor
1710 // @todo Fix TS 3.2.1
1711
1712
1713 _this.remove = _this.remove.bind(_assertThisInitialized(_this));
1714 _this.pop = _this.pop.bind(_assertThisInitialized(_this));
1715 return _this;
1716 }
1717
1718 var _proto = FieldArrayInner.prototype;
1719
1720 _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
1721 if (this.props.validateOnChange && this.props.formik.validateOnChange && !isEqual(getIn(prevProps.formik.values, prevProps.name), getIn(this.props.formik.values, this.props.name))) {
1722 this.props.formik.validateForm(this.props.formik.values);
1723 }
1724 };
1725
1726 _proto.remove = function remove(index) {
1727 // We need to make sure we also remove relevant pieces of `touched` and `errors`
1728 var result;
1729 this.updateArrayField( // so this gets call 3 times
1730 function (array) {
1731 var copy = array ? copyArrayLike(array) : [];
1732
1733 if (!result) {
1734 result = copy[index];
1735 }
1736
1737 if (isFunction(copy.splice)) {
1738 copy.splice(index, 1);
1739 }
1740
1741 return copy;
1742 }, true, true);
1743 return result;
1744 };
1745
1746 _proto.pop = function pop() {
1747 // Remove relevant pieces of `touched` and `errors` too!
1748 var result;
1749 this.updateArrayField( // so this gets call 3 times
1750 function (array) {
1751 var tmp = array;
1752
1753 if (!result) {
1754 result = tmp && tmp.pop && tmp.pop();
1755 }
1756
1757 return tmp;
1758 }, true, true);
1759 return result;
1760 };
1761
1762 _proto.render = function render() {
1763 var arrayHelpers = {
1764 push: this.push,
1765 pop: this.pop,
1766 swap: this.swap,
1767 move: this.move,
1768 insert: this.insert,
1769 replace: this.replace,
1770 unshift: this.unshift,
1771 remove: this.remove,
1772 handlePush: this.handlePush,
1773 handlePop: this.handlePop,
1774 handleSwap: this.handleSwap,
1775 handleMove: this.handleMove,
1776 handleInsert: this.handleInsert,
1777 handleReplace: this.handleReplace,
1778 handleUnshift: this.handleUnshift,
1779 handleRemove: this.handleRemove
1780 };
1781
1782 var _this$props2 = this.props,
1783 component = _this$props2.component,
1784 render = _this$props2.render,
1785 children = _this$props2.children,
1786 name = _this$props2.name,
1787 _this$props2$formik = _this$props2.formik,
1788 restOfFormik = _objectWithoutPropertiesLoose(_this$props2$formik, ["validate", "validationSchema"]);
1789
1790 var props = _extends({}, arrayHelpers, {
1791 form: restOfFormik,
1792 name: name
1793 });
1794
1795 return component ? createElement(component, props) : render ? render(props) : children // children come last, always called
1796 ? typeof children === 'function' ? children(props) : !isEmptyChildren(children) ? Children.only(children) : null : null;
1797 };
1798
1799 return FieldArrayInner;
1800}(Component);
1801
1802FieldArrayInner.defaultProps = {
1803 validateOnChange: true
1804};
1805var FieldArray = /*#__PURE__*/connect(FieldArrayInner);
1806
1807var ErrorMessageImpl = /*#__PURE__*/function (_React$Component) {
1808 _inheritsLoose(ErrorMessageImpl, _React$Component);
1809
1810 function ErrorMessageImpl() {
1811 return _React$Component.apply(this, arguments) || this;
1812 }
1813
1814 var _proto = ErrorMessageImpl.prototype;
1815
1816 _proto.shouldComponentUpdate = function shouldComponentUpdate(props) {
1817 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) {
1818 return true;
1819 } else {
1820 return false;
1821 }
1822 };
1823
1824 _proto.render = function render() {
1825 var _this$props = this.props,
1826 component = _this$props.component,
1827 formik = _this$props.formik,
1828 render = _this$props.render,
1829 children = _this$props.children,
1830 name = _this$props.name,
1831 rest = _objectWithoutPropertiesLoose(_this$props, ["component", "formik", "render", "children", "name"]);
1832
1833 var touch = getIn(formik.touched, name);
1834 var error = getIn(formik.errors, name);
1835 return !!touch && !!error ? render ? isFunction(render) ? render(error) : null : children ? isFunction(children) ? children(error) : null : component ? createElement(component, rest, error) : error : null;
1836 };
1837
1838 return ErrorMessageImpl;
1839}(Component);
1840
1841var ErrorMessage = /*#__PURE__*/connect(ErrorMessageImpl);
1842
1843/**
1844 * Custom Field component for quickly hooking into Formik
1845 * context and wiring up forms.
1846 */
1847
1848var FastFieldInner = /*#__PURE__*/function (_React$Component) {
1849 _inheritsLoose(FastFieldInner, _React$Component);
1850
1851 function FastFieldInner(props) {
1852 var _this;
1853
1854 _this = _React$Component.call(this, props) || this;
1855 var render = props.render,
1856 children = props.children,
1857 component = props.component,
1858 is = props.as,
1859 name = props.name;
1860 !!render ? process.env.NODE_ENV !== "production" ? invariant(false, "<FastField render> has been deprecated. Please use a child callback function instead: <FastField name={" + name + "}>{props => ...}</FastField> instead.") : invariant(false) : void 0;
1861 !!(component && render) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <FastField component> and <FastField render> in the same <FastField> component; <FastField component> will be ignored') : invariant(false) : void 0;
1862 !!(is && children && isFunction(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <FastField as> and <FastField children> as a function in the same <FastField> component; <FastField as> will be ignored.') : invariant(false) : void 0;
1863 !!(component && children && isFunction(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <FastField component> and <FastField children> as a function in the same <FastField> component; <FastField component> will be ignored.') : invariant(false) : void 0;
1864 !!(render && children && !isEmptyChildren(children)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'You should not use <FastField render> and <FastField children> in the same <FastField> component; <FastField children> will be ignored') : invariant(false) : void 0;
1865 return _this;
1866 }
1867
1868 var _proto = FastFieldInner.prototype;
1869
1870 _proto.shouldComponentUpdate = function shouldComponentUpdate(props) {
1871 if (this.props.shouldUpdate) {
1872 return this.props.shouldUpdate(props, this.props);
1873 } else if (props.name !== this.props.name || getIn(props.formik.values, this.props.name) !== getIn(this.props.formik.values, this.props.name) || getIn(props.formik.errors, this.props.name) !== getIn(this.props.formik.errors, this.props.name) || getIn(props.formik.touched, this.props.name) !== getIn(this.props.formik.touched, this.props.name) || Object.keys(this.props).length !== Object.keys(props).length || props.formik.isSubmitting !== this.props.formik.isSubmitting) {
1874 return true;
1875 } else {
1876 return false;
1877 }
1878 };
1879
1880 _proto.componentDidMount = function componentDidMount() {
1881 // Register the Field with the parent Formik. Parent will cycle through
1882 // registered Field's validate fns right prior to submit
1883 this.props.formik.registerField(this.props.name, {
1884 validate: this.props.validate
1885 });
1886 };
1887
1888 _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
1889 if (this.props.name !== prevProps.name) {
1890 this.props.formik.unregisterField(prevProps.name);
1891 this.props.formik.registerField(this.props.name, {
1892 validate: this.props.validate
1893 });
1894 }
1895
1896 if (this.props.validate !== prevProps.validate) {
1897 this.props.formik.registerField(this.props.name, {
1898 validate: this.props.validate
1899 });
1900 }
1901 };
1902
1903 _proto.componentWillUnmount = function componentWillUnmount() {
1904 this.props.formik.unregisterField(this.props.name);
1905 };
1906
1907 _proto.render = function render() {
1908 var _this$props = this.props,
1909 name = _this$props.name,
1910 render = _this$props.render,
1911 is = _this$props.as,
1912 children = _this$props.children,
1913 component = _this$props.component,
1914 formik = _this$props.formik,
1915 props = _objectWithoutPropertiesLoose(_this$props, ["validate", "name", "render", "as", "children", "component", "shouldUpdate", "formik"]);
1916
1917 var restOfFormik = _objectWithoutPropertiesLoose(formik, ["validate", "validationSchema"]);
1918
1919 var field = formik.getFieldProps(_extends({
1920 name: name
1921 }, props));
1922 var meta = {
1923 value: getIn(formik.values, name),
1924 error: getIn(formik.errors, name),
1925 touched: !!getIn(formik.touched, name),
1926 initialValue: getIn(formik.initialValues, name),
1927 initialTouched: !!getIn(formik.initialTouched, name),
1928 initialError: getIn(formik.initialErrors, name)
1929 };
1930 var bag = {
1931 field: field,
1932 meta: meta,
1933 form: restOfFormik
1934 };
1935
1936 if (render) {
1937 return render(bag);
1938 }
1939
1940 if (isFunction(children)) {
1941 return children(bag);
1942 }
1943
1944 if (component) {
1945 // This behavior is backwards compat with earlier Formik 0.9 to 1.x
1946 if (typeof component === 'string') {
1947 var innerRef = props.innerRef,
1948 rest = _objectWithoutPropertiesLoose(props, ["innerRef"]);
1949
1950 return createElement(component, _extends({
1951 ref: innerRef
1952 }, field, rest), children);
1953 } // We don't pass `meta` for backwards compat
1954
1955
1956 return createElement(component, _extends({
1957 field: field,
1958 form: formik
1959 }, props), children);
1960 } // default to input here so we can check for both `as` and `children` above
1961
1962
1963 var asElement = is || 'input';
1964
1965 if (typeof asElement === 'string') {
1966 var _innerRef = props.innerRef,
1967 _rest = _objectWithoutPropertiesLoose(props, ["innerRef"]);
1968
1969 return createElement(asElement, _extends({
1970 ref: _innerRef
1971 }, field, _rest), children);
1972 }
1973
1974 return createElement(asElement, _extends({}, field, props), children);
1975 };
1976
1977 return FastFieldInner;
1978}(Component);
1979
1980var FastField = /*#__PURE__*/connect(FastFieldInner);
1981
1982export { ErrorMessage, FastField, Field, FieldArray, Form, Formik, FormikConsumer, FormikContext, FormikProvider, connect, getActiveElement, getIn, insert, isEmptyArray, isEmptyChildren, isFunction, isInputEvent, isInteger, isNaN$1 as isNaN, isObject, isPromise, isString, move, prepareDataForValidation, replace, setIn, setNestedObjectValues, swap, useField, useFormik, useFormikContext, validateYupSchema, withFormik, yupToFormErrors };
1983//# sourceMappingURL=formik.esm.js.map