-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseScrollToErrorOnSubmit.ts
More file actions
83 lines (72 loc) · 2.59 KB
/
useScrollToErrorOnSubmit.ts
File metadata and controls
83 lines (72 loc) · 2.59 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
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
import { useEffect, useMemo } from 'react';
import type { FieldValues } from 'react-hook-form';
import { useRemixFormContext } from 'remix-hook-form';
import type { UseRemixFormReturn } from 'remix-hook-form';
import { type ScrollToErrorOptions, scrollToFirstError } from '../../utils/scrollToError';
export interface UseScrollToErrorOnSubmitOptions extends ScrollToErrorOptions {
delay?: number;
enabled?: boolean;
scrollOnServerErrors?: boolean;
scrollOnMount?: boolean;
methods?: UseRemixFormReturn<FieldValues>; // Optional methods parameter
}
export const useScrollToErrorOnSubmit = (options: UseScrollToErrorOnSubmitOptions = {}) => {
// Use provided methods or fall back to context
const contextMethods = useRemixFormContext();
const {
methods,
delay = 100,
enabled = true,
scrollOnServerErrors = true,
scrollOnMount = true,
...scrollOptions
} = options;
const formMethods = methods || contextMethods;
const { formState } = formMethods;
// Memoize scroll options to prevent unnecessary re-renders
const { behavior, block, inline, offset, shouldFocus, retryAttempts, selectors } = scrollOptions;
// biome-ignore lint: Compare `selectors` by value via join to avoid unstable array identity.
const memoizedScrollOptions = useMemo(
() => ({
behavior,
block,
inline,
offset,
shouldFocus,
retryAttempts,
selectors,
}),
[behavior, block, inline, offset, shouldFocus, retryAttempts, selectors?.join(',')],
);
// 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,
]);
};