( props: FormValidationProps<T>, state: FormValidationState, ref: RefObject<ValidatableElement | null> | undefined )
| 26 | } |
| 27 | |
| 28 | export function useFormValidation<T>( |
| 29 | props: FormValidationProps<T>, |
| 30 | state: FormValidationState, |
| 31 | ref: RefObject<ValidatableElement | null> | undefined |
| 32 | ): void { |
| 33 | let {validationBehavior, focus} = props; |
| 34 | |
| 35 | // This is a useLayoutEffect so that it runs before the useEffect in useFormValidationState, which commits the validation change. |
| 36 | useLayoutEffect(() => { |
| 37 | if ( |
| 38 | validationBehavior === 'native' && |
| 39 | ref?.current && |
| 40 | 'setCustomValidity' in ref.current && |
| 41 | !ref.current.disabled |
| 42 | ) { |
| 43 | let errorMessage = state.realtimeValidation.isInvalid |
| 44 | ? state.realtimeValidation.validationErrors.join(' ') || 'Invalid value.' |
| 45 | : ''; |
| 46 | ref.current.setCustomValidity(errorMessage); |
| 47 | |
| 48 | // Prevent default tooltip for validation message. |
| 49 | // https://bugzilla.mozilla.org/show_bug.cgi?id=605277 |
| 50 | if (!ref.current.hasAttribute('title')) { |
| 51 | ref.current.title = ''; |
| 52 | } |
| 53 | |
| 54 | if (!state.realtimeValidation.isInvalid) { |
| 55 | state.updateValidation(getNativeValidity(ref.current)); |
| 56 | } |
| 57 | } |
| 58 | }); |
| 59 | |
| 60 | let isIgnoredReset = useRef(false); |
| 61 | let onReset = useEffectEvent(() => { |
| 62 | if (!isIgnoredReset.current) { |
| 63 | state.resetValidation(); |
| 64 | } |
| 65 | }); |
| 66 | |
| 67 | let onInvalid = useEffectEvent((e: Event) => { |
| 68 | // Only commit validation if we are not already displaying one. |
| 69 | // This avoids clearing server errors that the user didn't actually fix. |
| 70 | if (!state.displayValidation.isInvalid) { |
| 71 | state.commitValidation(); |
| 72 | } |
| 73 | |
| 74 | // Auto focus the first invalid input in a form, unless the error already had its default prevented. |
| 75 | let form = ref?.current?.form; |
| 76 | if (!e.defaultPrevented && ref && form && getFirstInvalidInput(form) === ref.current) { |
| 77 | if (focus) { |
| 78 | focus(); |
| 79 | } else { |
| 80 | ref.current?.focus(); |
| 81 | } |
| 82 | |
| 83 | // Always show focus ring. |
| 84 | setInteractionModality('keyboard'); |
| 85 | } |
no test coverage detected