import type { FormikConfig } from 'formik'; import { Formik } from 'formik'; import { set } from 'lodash'; import React from 'react'; import { traverseObject } from '../../utils'; /** * This component wraps the component, applying fixes and spinnaker opinions * Use this component like you would use the component */ function SpinFormikImpl(props: FormikConfig, ref?: React.MutableRefObject>) { const defaultRef = React.useRef>(); const formikRef = ref || defaultRef; const [refSaved, setRefSaved] = React.useState(false); const [ready, setReady] = React.useState(false); const defaultIsInitialValid = () => formikRef.current && Object.keys(formikRef.current.state.errors).length === 0; // When a form is reloaded with existing data, we usually want to show validation errors immediately. // When the form is first rendered, mark all fields in initialValues as "touched". // Then run initial validation. React.useEffect(() => { if (refSaved) { const formik = formikRef.current; const initialTouched = {}; traverseObject(props.initialValues, (path: string) => set(initialTouched, path, true), true); formik.setTouched(initialTouched); formik.getFormikActions().validateForm(); setReady(true); } }, [refSaved]); function saveRef(formik: Formik) { formikRef.current = formik; if (!refSaved) { // Trigger another render setRefSaved(true); } } return ( ref={saveRef} {...props} isInitialValid={props.isInitialValid || defaultIsInitialValid} render={(renderProps) => ready && props.render && props.render(renderProps)} /> ); } export const SpinFormik = (React.forwardRef(SpinFormikImpl) as any) as typeof Formik;