-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseScrollToErrorOnSubmit.ts
More file actions
54 lines (45 loc) · 1.98 KB
/
Copy pathuseScrollToErrorOnSubmit.ts
File metadata and controls
54 lines (45 loc) · 1.98 KB
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
import { useEffect, useMemo } from 'react';
import { useRemixFormContext } from 'remix-hook-form';
import { type ScrollToErrorOptions, scrollToFirstError } from '../../utils/scrollToError';
export interface UseScrollToErrorOnSubmitOptions extends ScrollToErrorOptions {
delay?: number;
enabled?: boolean;
scrollOnServerErrors?: boolean;
scrollOnMount?: boolean;
}
export const useScrollToErrorOnSubmit = (options: UseScrollToErrorOnSubmitOptions = {}) => {
const { formState } = useRemixFormContext();
const { delay = 100, enabled = true, scrollOnServerErrors = true, scrollOnMount = true, ...scrollOptions } = options;
// Memoize scroll options to prevent unnecessary re-renders
const memoizedScrollOptions = useMemo(() => scrollOptions, [
scrollOptions.behavior,
scrollOptions.block,
scrollOptions.inline,
scrollOptions.offset,
scrollOptions.shouldFocus,
scrollOptions.retryAttempts,
]);
// Handle form submission errors
useEffect(() => {
if (!enabled) return;
const hasErrors = Object.keys(formState.errors).length > 0;
// Scroll after submission attempt when errors exist
if (!formState.isSubmitting && hasErrors) {
const timeoutId = setTimeout(() => {
scrollToFirstError(formState.errors, memoizedScrollOptions);
}, delay);
return () => clearTimeout(timeoutId);
}
}, [formState.errors, formState.isSubmitting, enabled, delay, memoizedScrollOptions]);
// Handle server-side validation errors on mount (Remix SSR)
useEffect(() => {
if (!(enabled && scrollOnMount) || !scrollOnServerErrors) return;
const hasErrors = Object.keys(formState.errors).length > 0;
if (hasErrors && !formState.isSubmitting) {
const timeoutId = setTimeout(() => {
scrollToFirstError(formState.errors, memoizedScrollOptions);
}, delay);
return () => clearTimeout(timeoutId);
}
}, [enabled, scrollOnMount, scrollOnServerErrors, formState.errors, formState.isSubmitting, delay, memoizedScrollOptions]);
};