All files / libs/ext/formik/src/lib/hooks/use-formik-field-adapter useFormikFieldAdapter.ts

100% Statements 58/58
50% Branches 3/6
100% Functions 1/1
100% Lines 58/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 591x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x  
import { useField, type FieldHookConfig, type FieldInputProps } from 'formik';
import { noop } from 'lodash-es';
import { useCallback, useMemo } from 'react';
 
import { type Merge } from '@amalia/ext/typescript';
 
import { type InputType } from '../../types/input-type';
 
export type UseFormikFieldAdapterOptions<TValue = unknown, TType extends InputType = 'text'> = {
  name: FieldHookConfig<TValue>['name'];
  type?: TType;
  validate?: FieldHookConfig<TValue>['validate'];
  transformFrom?: (value: TValue) => TValue;
  transformTo?: (value: TValue) => TValue;
};
 
export type UseFormikFieldAdapterValue<TValue = unknown, TType extends InputType = 'text'> = Merge<
  FieldInputProps<TValue>,
  {
    onChange: (value: TType extends 'checkbox' ? boolean : TValue) => void;
    onBlur?: (event: unknown) => void;
    error?: string;
  }
>;
 
export const useFormikFieldAdapter = <TValue = unknown, TType extends InputType = 'text'>({
  name,
  type = 'text' as TType,
  validate = undefined,
  transformFrom,
  transformTo,
}: UseFormikFieldAdapterOptions<TValue, TType>): UseFormikFieldAdapterValue<TValue, TType> => {
  const [{ onBlur, value, ...inputProps }, { touched, error }, { setValue }] = useField<TValue>({
    name,
    type,
    validate,
  });
 
  const handleChange: UseFormikFieldAdapterValue<TValue, typeof type>['onChange'] = useCallback(
    (value) => {
      const transformedValue = transformTo ? transformTo(value as TValue) : value;
      setValue(transformedValue as Parameters<typeof setValue>[0], true).catch(noop);
    },
    [setValue, transformTo],
  );
 
  // Bind onBlur to the field name.
  // When called with a string, Formik returns a new onBlur function bound to the parameter.
  const handleBlur = useMemo(() => onBlur(name), [onBlur, name]);
 
  return {
    ...inputProps,
    value: transformFrom ? transformFrom(value) : value,
    onChange: handleChange,
    onBlur: handleBlur,
    error: touched ? error : undefined,
  };
};