(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('final-form')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'final-form'], factory) : (global = global || self, factory(global['react-final-form'] = {}, global.React, global.FinalForm)); }(this, (function (exports, React, finalForm) { 'use strict'; var React__default = 'default' in React ? React['default'] : React; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function renderComponent(props, lazyProps, name) { var render = props.render, children = props.children, component = props.component, rest = _objectWithoutPropertiesLoose(props, ["render", "children", "component"]); if (component) { return React.createElement(component, Object.assign(lazyProps, rest, { children: children, render: render })); } if (render) { return render(children === undefined ? Object.assign(lazyProps, rest) : // inject children back in Object.assign(lazyProps, rest, { children: children })); } if (typeof children !== 'function') { throw new Error("Must specify either a render prop, a render function as children, or a component prop to " + name); } return children(Object.assign(lazyProps, rest)); } function useWhenValueChanges(value, callback, isEqual) { if (isEqual === void 0) { isEqual = function isEqual(a, b) { return a === b; }; } var previous = React__default.useRef(value); React__default.useEffect(function () { if (!isEqual(value, previous.current)) { callback(); previous.current = value; } }); } /** * A simple hook to create a constant value that lives for * the lifetime of the component. * * Plagiarized from https://github.com/Andarist/use-constant * * Do NOT reuse this code unless you know what you're doing. * Use Andarist's hook; it's more fault tolerant to things like * falsy values. * * @param {Function} init - A function to generate the value */ function useConstant(init) { var ref = React__default.useRef(); if (!ref.current) { ref.current = init(); } return ref.current; } var shallowEqual = function shallowEqual(a, b) { if (a === b) { return true; } if (typeof a !== 'object' || !a || typeof b !== 'object' || !b) { return false; } var keysA = Object.keys(a); var keysB = Object.keys(b); if (keysA.length !== keysB.length) { return false; } var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(b); for (var idx = 0; idx < keysA.length; idx++) { var key = keysA[idx]; if (!bHasOwnProperty(key) || a[key] !== b[key]) { return false; } } return true; }; var isSyntheticEvent = function isSyntheticEvent(candidate) { return !!(candidate && typeof candidate.stopPropagation === 'function'); }; var ReactFinalFormContext = React.createContext(); function useLatest(value) { var ref = React__default.useRef(value); React__default.useEffect(function () { ref.current = value; }); return ref; } var version = "6.3.3"; var addLazyState = function addLazyState(dest, state, keys) { keys.forEach(function (key) { Object.defineProperty(dest, key, { get: function get() { return state[key]; }, enumerable: true }); }); }; var addLazyFormState = function addLazyFormState(dest, state) { return addLazyState(dest, state, ['active', 'dirty', 'dirtyFields', 'dirtySinceLastSubmit', 'error', 'errors', 'hasSubmitErrors', 'hasValidationErrors', 'initialValues', 'invalid', 'modified', 'pristine', 'submitError', 'submitErrors', 'submitFailed', 'submitSucceeded', 'submitting', 'touched', 'valid', 'validating', 'values', 'visited']); }; var addLazyFieldMetaState = function addLazyFieldMetaState(dest, state) { return addLazyState(dest, state, ['active', 'data', 'dirty', 'dirtySinceLastSubmit', 'error', 'initial', 'invalid', 'length', 'modified', 'pristine', 'submitError', 'submitFailed', 'submitSucceeded', 'submitting', 'touched', 'valid', 'validating', 'visited']); }; var versions = { 'final-form': finalForm.version, 'react-final-form': version }; var all = finalForm.formSubscriptionItems.reduce(function (result, key) { result[key] = true; return result; }, {}); function ReactFinalForm(_ref) { var debug = _ref.debug, decorators = _ref.decorators, destroyOnUnregister = _ref.destroyOnUnregister, alternateFormApi = _ref.form, initialValues = _ref.initialValues, initialValuesEqual = _ref.initialValuesEqual, keepDirtyOnReinitialize = _ref.keepDirtyOnReinitialize, mutators = _ref.mutators, onSubmit = _ref.onSubmit, _ref$subscription = _ref.subscription, subscription = _ref$subscription === void 0 ? all : _ref$subscription, validate = _ref.validate, validateOnBlur = _ref.validateOnBlur, rest = _objectWithoutPropertiesLoose(_ref, ["debug", "decorators", "destroyOnUnregister", "form", "initialValues", "initialValuesEqual", "keepDirtyOnReinitialize", "mutators", "onSubmit", "subscription", "validate", "validateOnBlur"]); var config = { debug: debug, destroyOnUnregister: destroyOnUnregister, initialValues: initialValues, keepDirtyOnReinitialize: keepDirtyOnReinitialize, mutators: mutators, onSubmit: onSubmit, validate: validate, validateOnBlur: validateOnBlur }; var form = useConstant(function () { var f = alternateFormApi || finalForm.createForm(config); // pause validation until children register all fields on first render (unpaused in useEffect() below) f.pauseValidation(); return f; }); // synchronously register and unregister to query form state for our subscription on first render var _React$useState = React.useState(function () { var initialState = {}; form.subscribe(function (state) { initialState = state; }, subscription)(); return initialState; }), state = _React$useState[0], setState = _React$useState[1]; // save a copy of state that can break through the closure // on the shallowEqual() line below. var stateRef = useLatest(state); React.useEffect(function () { // We have rendered, so all fields are now registered, so we can unpause validation form.isValidationPaused() && form.resumeValidation(); var unsubscriptions = [form.subscribe(function (s) { if (!shallowEqual(s, stateRef.current)) { setState(s); } }, subscription)].concat(decorators ? decorators.map(function (decorator) { return (// this noop ternary is to appease the flow gods // istanbul ignore next decorator(form) ); }) : []); return function () { form.pauseValidation(); // pause validation so we don't revalidate on every field deregistration unsubscriptions.reverse().forEach(function (unsubscribe) { return unsubscribe(); }); // don't need to resume validation here; either unmounting, or will re-run this hook with new deps }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [decorators]); // warn about decorator changes // istanbul ignore next { // You're never supposed to use hooks inside a conditional, but in this // case we can be certain that you're not going to be changing your // NODE_ENV between renders, so this is safe. // eslint-disable-next-line react-hooks/rules-of-hooks useWhenValueChanges(decorators, function () { console.error('Form decorators should not change from one render to the next as new values will be ignored'); }, shallowEqual); } // allow updatable config useWhenValueChanges(debug, function () { form.setConfig('debug', debug); }); useWhenValueChanges(destroyOnUnregister, function () { form.destroyOnUnregister = !!destroyOnUnregister; }); useWhenValueChanges(initialValues, function () { form.setConfig('initialValues', initialValues); }, initialValuesEqual || shallowEqual); useWhenValueChanges(keepDirtyOnReinitialize, function () { form.setConfig('keepDirtyOnReinitialize', keepDirtyOnReinitialize); }); useWhenValueChanges(mutators, function () { form.setConfig('mutators', mutators); }); useWhenValueChanges(onSubmit, function () { form.setConfig('onSubmit', onSubmit); }); useWhenValueChanges(validate, function () { form.setConfig('validate', validate); }); useWhenValueChanges(validateOnBlur, function () { form.setConfig('validateOnBlur', validateOnBlur); }); var handleSubmit = function handleSubmit(event) { if (event) { // sometimes not true, e.g. React Native if (typeof event.preventDefault === 'function') { event.preventDefault(); } if (typeof event.stopPropagation === 'function') { // prevent any outer forms from receiving the event too event.stopPropagation(); } } return form.submit(); }; var renderProps = { form: _extends({}, form, { reset: function reset(eventOrValues) { if (isSyntheticEvent(eventOrValues)) { // it's a React SyntheticEvent, call reset with no arguments form.reset(); } else { form.reset(eventOrValues); } } }), handleSubmit: handleSubmit }; addLazyFormState(renderProps, state); return React.createElement(ReactFinalFormContext.Provider, { value: form }, renderComponent(_extends({}, rest, { __versions: versions }), renderProps, 'ReactFinalForm')); } function useForm(componentName) { var form = React.useContext(ReactFinalFormContext); if (!form) { throw new Error((componentName || 'useForm') + " must be used inside of a