-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
126 lines (111 loc) · 4.4 KB
/
index.js
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const { useEffect, useState } = require("react");
/**
* @typedef {Object<string, any>} FormData
*/
/**
* @typedef {Object} UseFormProps
* @property {HTMLFormElement | HTMLElement | Element} [form]
* @property {boolean} [legacyListeners]
*/
/**
* @param {UseFormProps} props
* @returns {FormData}
*/
module.exports = function useFormData(props) {
if (typeof window !== "undefined") {
const form = props?.form || document.querySelector("form");
const [formData, setFormData] = useState({});
const [inputs, setInputs] = useState([]);
const observeCallback = (mutations) => {
for (const mutation of mutations) {
if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
updateInputs();
break;
}
}
}
const observer = new MutationObserver(observeCallback);
useEffect(() => {
updateInputs();
}, [])
useEffect(() => {
if (form) {
updateInputs();
if (!props?.legacyListeners && observer) {
observer.observe(form, { childList: true, subtree: true })
} else {
document.body.addEventListener("DOMNodeInserted", updateInputs);
document.body.addEventListener("DOMNodeRemoved", updateInputs);
}
}
return (() => {
if (!props?.legacyListeners && observer) {
observer.disconnect();
}
else {
document.body.removeEventListener("DOMNodeInserted", updateInputs);
document.body.removeEventListener("DOMNodeRemoved", updateInputs);
}
});
}, [form])
useEffect(() => {
addEventListeners();
updateFormData();
return () => {
removeEventListeners();
}
}, [inputs]);
const updateInputs = () => {
let inputElements = Array.from(form?.querySelectorAll("input,textarea") || []);
inputElements = inputElements.filter(e => {
if (e instanceof HTMLTextAreaElement) {
return true;
} else if (e instanceof HTMLInputElement) {
return e.type != "file" && e.type != "submit" && e.type != "reset" && e.type != "button" && e.type != "image";
}
});
setInputs(inputElements);
}
const updateFormData = () => {
const newFormData = {};
inputs?.forEach(input => {
if (input instanceof HTMLInputElement) {
if (input.type != "radio") {
newFormData[input.name] = getValue(input);
} else if (!newFormData[input.name] && input.type == "radio") {
newFormData[input.name] = getValue(inputs.find(i => i instanceof HTMLInputElement && i.type == "radio" && i.name == input.name && i.checked));
}
} else if (input instanceof HTMLTextAreaElement) {
newFormData[input.name] = getValue(input);
}
});
setFormData(newFormData);
}
const updateSingleData = (e) => {
const inputElement = e.target;
setFormData((prevData) => ({ ...prevData, [inputElement.name]: getValue(inputElement) }));
}
const addEventListeners = () => {
inputs?.forEach(input => input.addEventListener("input", updateSingleData));
inputs?.forEach(input => input.addEventListener("change", updateSingleData));
}
const removeEventListeners = () => {
inputs?.forEach(input => input.removeEventListener("input", updateSingleData));
inputs?.forEach(input => input.removeEventListener("change", updateSingleData));
}
const getValue = (element) => {
if (!element) {
return undefined;
}
if (element instanceof HTMLInputElement && element.type == "checkbox") {
return element.checked;
} else if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
return element.value;
}
}
return formData;
}
else {
return null
}
}