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;