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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | import { memo, useCallback, useRef, useState } from 'react'; import { AutoCompleteInput, type AutoCompleteInputProps, type AutoCompleteOption, } from '@allshares/studio-design-system'; import { useFormikFieldAdapter, type FormikFieldProps } from '@amalia/ext/formik'; import { type Merge } from '@amalia/ext/typescript'; type AutoCompleteInputFormikValue = Omit< AutoCompleteInputProps, 'inputValue' | 'onChangeInputValue' | 'onClickOption' > & { value?: string; onChange?: (value: string) => void; }; /** * AutoCompleteInput props adapted for Formik. * * Replaces the dual-state API (inputValue + onClickOption) with a single Formik-managed * `value` (the selected option value). The input text is handled internally. */ export type FormikAutoCompleteInputProps = Merge< FormikFieldProps<AutoCompleteInputFormikValue>, { /** Called when the input text changes (useful for async search/filtering). */ onSearch?: (search: string) => void; /** Called when an option is selected (for side effects beyond Formik). */ onSelectOption?: (option: AutoCompleteOption) => void; } >; export const FormikAutoCompleteInput = memo(function FormikAutoCompleteInput({ validate, onSearch, onSelectOption, ...props }: FormikAutoCompleteInputProps) { const { onBlur, onChange, value, ...formikFieldProps } = useFormikFieldAdapter<AutoCompleteInputFormikValue['value']>( { ...props, validate, }, ); const [inputValue, setInputValue] = useState(value || ''); // Option selection triggers an immediate blur in the design-system input. // Keep track of that case so Formik can process the new value before marking the field as touched. const shouldDeferBlurRef = useRef(false); const handleChangeInputValue = useCallback( (text: string) => { setInputValue(text); onSearch?.(text); }, [onSearch], ); const handleClickOption = useCallback( (option: AutoCompleteOption) => { // The next blur comes from selecting an option, not from the user leaving the field manually. shouldDeferBlurRef.current = true; onChange(option.value); setInputValue(option.value); onSelectOption?.(option); }, [onChange, onSelectOption], ); const handleBlur = useCallback( (event: unknown) => { if (!shouldDeferBlurRef.current) { onBlur?.(event); return; } shouldDeferBlurRef.current = false; // Defer Formik's blur handling to the next tick so validation sees the selected value // instead of the previous empty one. setTimeout(() => { onBlur?.(event); }, 0); }, [onBlur], ); return ( <AutoCompleteInput {...props} {...formikFieldProps} inputValue={inputValue} onBlur={handleBlur} onChangeInputValue={handleChangeInputValue} onClickOption={handleClickOption} /> ); }); |