rfhook 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -21
- package/dist/index.cjs +57 -4
- package/dist/index.js +57 -4
- package/dist/useForm.hook.d.ts +49 -6
- package/package.json +1 -1
- package/src/useForm.hook.ts +94 -8
package/README.md
CHANGED
|
@@ -4,12 +4,13 @@ A lightweight React hook for handling form submissions with advanced form data p
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- :rocket: **Simple API** - Just one hook to handle all your form needs
|
|
8
|
+
- :dart: **TypeScript Support** - Fully typed with generic support
|
|
9
|
+
- :wrench: **Nested Objects** - Parse nested form data with dot notation (`user.name`)
|
|
10
|
+
- :clipboard: **Array Support** - Handle arrays with indexed notation (`items[0]`)
|
|
11
|
+
- :floppy_disk: **Automatic Prevention** - Prevents default form submission behavior by default
|
|
12
|
+
- :money_with_wings: **Lightweight** - Zero dependencies (except React)
|
|
13
|
+
- :memo: **Framework Agnostic** - Works with any form structure
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -37,19 +38,23 @@ interface FormData {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
function LoginForm() {
|
|
40
|
-
const { ref,
|
|
41
|
-
|
|
41
|
+
const { ref, onSubmit } = useForm<FormData>({
|
|
42
|
+
submit: (data) => {
|
|
42
43
|
console.log(data); // { email: "user@example.com", password: "secret" }
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
|
|
46
47
|
return (
|
|
47
|
-
<form ref={ref} onSubmit={
|
|
48
|
+
<form ref={ref} onSubmit={onSubmit}>
|
|
48
49
|
<input name="email" type="email" />
|
|
49
50
|
<input name="password" type="password" />
|
|
50
51
|
<button type="submit">Login</button>
|
|
51
52
|
</form>
|
|
52
53
|
);
|
|
54
|
+
}
|
|
55
|
+
<button type="submit">Login</button>
|
|
56
|
+
</form>
|
|
57
|
+
);
|
|
53
58
|
}
|
|
54
59
|
```
|
|
55
60
|
|
|
@@ -73,8 +78,8 @@ interface UserForm {
|
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
function UserForm() {
|
|
76
|
-
const { ref,
|
|
77
|
-
|
|
81
|
+
const { ref, onSubmit } = useForm<UserForm>({
|
|
82
|
+
submit: (data) => {
|
|
78
83
|
console.log(data);
|
|
79
84
|
// {
|
|
80
85
|
// user: {
|
|
@@ -91,7 +96,7 @@ function UserForm() {
|
|
|
91
96
|
});
|
|
92
97
|
|
|
93
98
|
return (
|
|
94
|
-
<form ref={ref} onSubmit={
|
|
99
|
+
<form ref={ref} onSubmit={onSubmit}>
|
|
95
100
|
<input name="user.profile.name" placeholder="Name" />
|
|
96
101
|
<input name="user.profile.age" type="number" placeholder="Age" />
|
|
97
102
|
<select name="user.preferences.theme">
|
|
@@ -117,8 +122,8 @@ interface TodoForm {
|
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
function TodoForm() {
|
|
120
|
-
const { ref,
|
|
121
|
-
|
|
125
|
+
const { ref, onSubmit } = useForm<TodoForm>({
|
|
126
|
+
submit: (data) => {
|
|
122
127
|
console.log(data);
|
|
123
128
|
// {
|
|
124
129
|
// todos: [
|
|
@@ -130,7 +135,7 @@ function TodoForm() {
|
|
|
130
135
|
});
|
|
131
136
|
|
|
132
137
|
return (
|
|
133
|
-
<form ref={ref} onSubmit={
|
|
138
|
+
<form ref={ref} onSubmit={onSubmit}>
|
|
134
139
|
<input name="todos[0].title" placeholder="First todo" />
|
|
135
140
|
<input name="todos[0].completed" type="checkbox" />
|
|
136
141
|
|
|
@@ -149,12 +154,59 @@ function TodoForm() {
|
|
|
149
154
|
|
|
150
155
|
#### Parameters
|
|
151
156
|
|
|
152
|
-
- `options.
|
|
157
|
+
- `options.submit: (data: T) => void` - Callback function called when form is submitted with parsed form data
|
|
153
158
|
|
|
154
159
|
#### Returns
|
|
155
160
|
|
|
156
|
-
- `ref: RefObject<HTMLFormElement>` - React ref to attach to your form element
|
|
157
|
-
- `
|
|
161
|
+
- `ref: React.RefObject<HTMLFormElement>` - React ref to attach to your form element
|
|
162
|
+
- `onSubmit: (event: React.FormEvent<HTMLFormElement>) => void` - Form submission handler that prevents default behavior and calls submit with parsed data
|
|
163
|
+
- `reset: () => void` - Resets the form to its initial state
|
|
164
|
+
- `getFormData: () => T | null` - Gets current form data without triggering submission (returns null if form ref is not available)
|
|
165
|
+
- `setValue: (name: string, value: string) => void` - Sets the value of a specific form field by name
|
|
166
|
+
|
|
167
|
+
### Additional Usage Examples
|
|
168
|
+
|
|
169
|
+
#### Using Form Utilities
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
function MyForm() {
|
|
173
|
+
const form = useForm<FormData>({
|
|
174
|
+
submit: (data) => console.log('Submitted:', data)
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const handleReset = () => {
|
|
178
|
+
form.reset(); // Reset form to initial state
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const handlePreview = () => {
|
|
182
|
+
const currentData = form.getFormData();
|
|
183
|
+
if (currentData) {
|
|
184
|
+
console.log('Current form data:', currentData);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const handlePrefill = () => {
|
|
189
|
+
form.setValue('email', 'user@example.com');
|
|
190
|
+
form.setValue('name', 'John Doe');
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<>
|
|
195
|
+
<form ref={form.ref} onSubmit={form.onSubmit}>
|
|
196
|
+
<input name="name" placeholder="Name" />
|
|
197
|
+
<input name="email" type="email" placeholder="Email" />
|
|
198
|
+
<button type="submit">Submit</button>
|
|
199
|
+
</form>
|
|
200
|
+
|
|
201
|
+
<div>
|
|
202
|
+
<button onClick={handleReset}>Reset Form</button>
|
|
203
|
+
<button onClick={handlePreview}>Preview Data</button>
|
|
204
|
+
<button onClick={handlePrefill}>Prefill Form</button>
|
|
205
|
+
</div>
|
|
206
|
+
</>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
```
|
|
158
210
|
|
|
159
211
|
### Form Data Parsing Rules
|
|
160
212
|
|
|
@@ -182,8 +234,8 @@ interface ContactData {
|
|
|
182
234
|
}
|
|
183
235
|
|
|
184
236
|
function ContactForm() {
|
|
185
|
-
const { ref,
|
|
186
|
-
|
|
237
|
+
const { ref, onSubmit } = useForm<ContactData>({
|
|
238
|
+
submit: async (data) => {
|
|
187
239
|
try {
|
|
188
240
|
const response = await fetch('/api/contact', {
|
|
189
241
|
method: 'POST',
|
|
@@ -201,7 +253,7 @@ function ContactForm() {
|
|
|
201
253
|
});
|
|
202
254
|
|
|
203
255
|
return (
|
|
204
|
-
<form ref={ref} onSubmit={
|
|
256
|
+
<form ref={ref} onSubmit={onSubmit}>
|
|
205
257
|
<input name="name" placeholder="Your Name" required />
|
|
206
258
|
<input name="email" type="email" placeholder="Your Email" required />
|
|
207
259
|
<textarea name="message" placeholder="Your Message" required />
|
package/dist/index.cjs
CHANGED
|
@@ -49,17 +49,70 @@ function parseFormData(formData) {
|
|
|
49
49
|
return result;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* A React hook for handling form state and submission
|
|
54
|
+
*
|
|
55
|
+
* @template T - The expected shape of the parsed form data
|
|
56
|
+
* @param options - Configuration options for the form
|
|
57
|
+
* @returns Object containing form ref, handlers, and utility functions
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* interface LoginData {
|
|
62
|
+
* email: string;
|
|
63
|
+
* password: string;
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* const form = useForm<LoginData>({
|
|
67
|
+
* submit: (data) => console.log(data.email, data.password)
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* return (
|
|
71
|
+
* <form ref={form.ref} onSubmit={form.onSubmit}>
|
|
72
|
+
* <input name="email" type="email" />
|
|
73
|
+
* <input name="password" type="password" />
|
|
74
|
+
* <button type="submit">Login</button>
|
|
75
|
+
* </form>
|
|
76
|
+
* );
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
function useForm({ submit }) {
|
|
53
80
|
const ref = react.useRef(null);
|
|
54
|
-
const
|
|
81
|
+
const onSubmit = (event) => {
|
|
55
82
|
event.preventDefault();
|
|
56
83
|
if (!ref.current)
|
|
57
84
|
return;
|
|
58
85
|
const formData = new FormData(ref.current);
|
|
59
86
|
const data = parseFormData(formData);
|
|
60
|
-
|
|
87
|
+
submit(data);
|
|
88
|
+
};
|
|
89
|
+
const reset = () => {
|
|
90
|
+
if (!ref.current)
|
|
91
|
+
return;
|
|
92
|
+
ref.current.reset();
|
|
93
|
+
};
|
|
94
|
+
const getFormData = () => {
|
|
95
|
+
if (!ref.current)
|
|
96
|
+
return null;
|
|
97
|
+
const formData = new FormData(ref.current);
|
|
98
|
+
const data = parseFormData(formData);
|
|
99
|
+
return data;
|
|
100
|
+
};
|
|
101
|
+
const setValue = (name, value) => {
|
|
102
|
+
if (!ref.current)
|
|
103
|
+
return;
|
|
104
|
+
const element = ref.current.elements.namedItem(name);
|
|
105
|
+
if (element && 'value' in element) {
|
|
106
|
+
element.value = value;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
ref,
|
|
111
|
+
onSubmit,
|
|
112
|
+
reset,
|
|
113
|
+
getFormData,
|
|
114
|
+
setValue
|
|
61
115
|
};
|
|
62
|
-
return { ref, submit };
|
|
63
116
|
}
|
|
64
117
|
|
|
65
118
|
exports.useForm = useForm;
|
package/dist/index.js
CHANGED
|
@@ -47,17 +47,70 @@ function parseFormData(formData) {
|
|
|
47
47
|
return result;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
/**
|
|
51
|
+
* A React hook for handling form state and submission
|
|
52
|
+
*
|
|
53
|
+
* @template T - The expected shape of the parsed form data
|
|
54
|
+
* @param options - Configuration options for the form
|
|
55
|
+
* @returns Object containing form ref, handlers, and utility functions
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* interface LoginData {
|
|
60
|
+
* email: string;
|
|
61
|
+
* password: string;
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* const form = useForm<LoginData>({
|
|
65
|
+
* submit: (data) => console.log(data.email, data.password)
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* return (
|
|
69
|
+
* <form ref={form.ref} onSubmit={form.onSubmit}>
|
|
70
|
+
* <input name="email" type="email" />
|
|
71
|
+
* <input name="password" type="password" />
|
|
72
|
+
* <button type="submit">Login</button>
|
|
73
|
+
* </form>
|
|
74
|
+
* );
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
function useForm({ submit }) {
|
|
51
78
|
const ref = useRef(null);
|
|
52
|
-
const
|
|
79
|
+
const onSubmit = (event) => {
|
|
53
80
|
event.preventDefault();
|
|
54
81
|
if (!ref.current)
|
|
55
82
|
return;
|
|
56
83
|
const formData = new FormData(ref.current);
|
|
57
84
|
const data = parseFormData(formData);
|
|
58
|
-
|
|
85
|
+
submit(data);
|
|
86
|
+
};
|
|
87
|
+
const reset = () => {
|
|
88
|
+
if (!ref.current)
|
|
89
|
+
return;
|
|
90
|
+
ref.current.reset();
|
|
91
|
+
};
|
|
92
|
+
const getFormData = () => {
|
|
93
|
+
if (!ref.current)
|
|
94
|
+
return null;
|
|
95
|
+
const formData = new FormData(ref.current);
|
|
96
|
+
const data = parseFormData(formData);
|
|
97
|
+
return data;
|
|
98
|
+
};
|
|
99
|
+
const setValue = (name, value) => {
|
|
100
|
+
if (!ref.current)
|
|
101
|
+
return;
|
|
102
|
+
const element = ref.current.elements.namedItem(name);
|
|
103
|
+
if (element && 'value' in element) {
|
|
104
|
+
element.value = value;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
ref,
|
|
109
|
+
onSubmit,
|
|
110
|
+
reset,
|
|
111
|
+
getFormData,
|
|
112
|
+
setValue
|
|
59
113
|
};
|
|
60
|
-
return { ref, submit };
|
|
61
114
|
}
|
|
62
115
|
|
|
63
116
|
export { useForm };
|
package/dist/useForm.hook.d.ts
CHANGED
|
@@ -1,8 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for the useForm hook
|
|
3
|
+
*/
|
|
4
|
+
interface UseFormOptions<T> {
|
|
5
|
+
/** Callback function called when form is submitted with parsed form data */
|
|
6
|
+
submit: (data: T) => void;
|
|
3
7
|
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Return type of the useForm hook
|
|
10
|
+
*/
|
|
11
|
+
interface UseFormReturn<T> {
|
|
12
|
+
/** React ref to be attached to the form element */
|
|
13
|
+
ref: React.RefObject<HTMLFormElement | null>;
|
|
14
|
+
/** Form submission handler - prevents default and calls submit with parsed data */
|
|
15
|
+
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
16
|
+
/** Resets the form to its initial state */
|
|
17
|
+
reset: () => void;
|
|
18
|
+
/** Gets current form data without triggering submission */
|
|
19
|
+
getFormData: () => T | null;
|
|
20
|
+
/** Sets the value of a specific form field by name */
|
|
21
|
+
setValue: (name: string, value: string) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A React hook for handling form state and submission
|
|
25
|
+
*
|
|
26
|
+
* @template T - The expected shape of the parsed form data
|
|
27
|
+
* @param options - Configuration options for the form
|
|
28
|
+
* @returns Object containing form ref, handlers, and utility functions
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* interface LoginData {
|
|
33
|
+
* email: string;
|
|
34
|
+
* password: string;
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* const form = useForm<LoginData>({
|
|
38
|
+
* submit: (data) => console.log(data.email, data.password)
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* return (
|
|
42
|
+
* <form ref={form.ref} onSubmit={form.onSubmit}>
|
|
43
|
+
* <input name="email" type="email" />
|
|
44
|
+
* <input name="password" type="password" />
|
|
45
|
+
* <button type="submit">Login</button>
|
|
46
|
+
* </form>
|
|
47
|
+
* );
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function useForm<T = Record<string, unknown>>({ submit }: UseFormOptions<T>): UseFormReturn<T>;
|
|
8
51
|
export {};
|
package/package.json
CHANGED
package/src/useForm.hook.ts
CHANGED
|
@@ -2,24 +2,110 @@ import { useRef } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { parseFormData } from './utils/parseFormData';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the useForm hook
|
|
7
|
+
*/
|
|
8
|
+
interface UseFormOptions<T> {
|
|
9
|
+
/** Callback function called when form is submitted with parsed form data */
|
|
10
|
+
submit: (data: T) => void;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Form element types that can have their values set programmatically
|
|
15
|
+
*/
|
|
16
|
+
type FormElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Return type of the useForm hook
|
|
20
|
+
*/
|
|
21
|
+
interface UseFormReturn<T> {
|
|
22
|
+
/** React ref to be attached to the form element */
|
|
23
|
+
ref: React.RefObject<HTMLFormElement | null>;
|
|
24
|
+
/** Form submission handler - prevents default and calls submit with parsed data */
|
|
25
|
+
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
26
|
+
/** Resets the form to its initial state */
|
|
27
|
+
reset: () => void;
|
|
28
|
+
/** Gets current form data without triggering submission */
|
|
29
|
+
getFormData: () => T | null;
|
|
30
|
+
/** Sets the value of a specific form field by name */
|
|
31
|
+
setValue: (name: string, value: string) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A React hook for handling form state and submission
|
|
36
|
+
*
|
|
37
|
+
* @template T - The expected shape of the parsed form data
|
|
38
|
+
* @param options - Configuration options for the form
|
|
39
|
+
* @returns Object containing form ref, handlers, and utility functions
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* interface LoginData {
|
|
44
|
+
* email: string;
|
|
45
|
+
* password: string;
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* const form = useForm<LoginData>({
|
|
49
|
+
* submit: (data) => console.log(data.email, data.password)
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* return (
|
|
53
|
+
* <form ref={form.ref} onSubmit={form.onSubmit}>
|
|
54
|
+
* <input name="email" type="email" />
|
|
55
|
+
* <input name="password" type="password" />
|
|
56
|
+
* <button type="submit">Login</button>
|
|
57
|
+
* </form>
|
|
58
|
+
* );
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function useForm<T = Record<string, unknown>>(
|
|
62
|
+
{ submit }: UseFormOptions<T>
|
|
63
|
+
): UseFormReturn<T> {
|
|
10
64
|
const ref = useRef<HTMLFormElement>(null);
|
|
11
65
|
|
|
12
|
-
const
|
|
66
|
+
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
|
13
67
|
event.preventDefault();
|
|
14
68
|
|
|
15
|
-
if (!ref.current) return
|
|
69
|
+
if (!ref.current) return;
|
|
16
70
|
|
|
17
71
|
const formData = new FormData(ref.current);
|
|
18
72
|
|
|
19
|
-
const data
|
|
73
|
+
const data = parseFormData(formData) as T;
|
|
74
|
+
|
|
75
|
+
submit(data);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const reset = () => {
|
|
79
|
+
if (!ref.current) return;
|
|
80
|
+
|
|
81
|
+
ref.current.reset();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const getFormData = (): T | null => {
|
|
85
|
+
if (!ref.current) return null;
|
|
86
|
+
|
|
87
|
+
const formData = new FormData(ref.current);
|
|
88
|
+
|
|
89
|
+
const data = parseFormData(formData) as T;
|
|
90
|
+
|
|
91
|
+
return data;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const setValue = (name: string, value: string) => {
|
|
95
|
+
if (!ref.current) return;
|
|
96
|
+
|
|
97
|
+
const element = ref.current.elements.namedItem(name) as FormElement | null;
|
|
20
98
|
|
|
21
|
-
|
|
99
|
+
if (element && 'value' in element) {
|
|
100
|
+
element.value = value;
|
|
22
101
|
}
|
|
102
|
+
};
|
|
23
103
|
|
|
24
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
ref,
|
|
106
|
+
onSubmit,
|
|
107
|
+
reset,
|
|
108
|
+
getFormData,
|
|
109
|
+
setValue
|
|
110
|
+
};
|
|
25
111
|
}
|