@samline/forms 1.0.3 → 2.1.0
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 +87 -199
- package/dist/browser/global.d.ts +152 -0
- package/dist/browser/global.global.js +788 -474
- package/dist/browser/global.global.js.map +1 -1
- package/dist/index.cjs +763 -470
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -3
- package/dist/index.d.ts +141 -3
- package/dist/index.js +970 -13
- package/dist/index.js.map +1 -1
- package/package.json +8 -43
- package/dist/chunk-4NEGCRY2.js +0 -125
- package/dist/chunk-4NEGCRY2.js.map +0 -1
- package/dist/chunk-PCKGH2WA.js +0 -11
- package/dist/chunk-PCKGH2WA.js.map +0 -1
- package/dist/chunk-WM2CL7IO.js +0 -576
- package/dist/chunk-WM2CL7IO.js.map +0 -1
- package/dist/core/index.cjs +0 -154
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -11
- package/dist/core/index.d.ts +0 -11
- package/dist/core/index.js +0 -13
- package/dist/core/index.js.map +0 -1
- package/dist/react/index.cjs +0 -734
- package/dist/react/index.cjs.map +0 -1
- package/dist/react/index.d.cts +0 -10
- package/dist/react/index.d.ts +0 -10
- package/dist/react/index.js +0 -43
- package/dist/react/index.js.map +0 -1
- package/dist/svelte/index.cjs +0 -764
- package/dist/svelte/index.cjs.map +0 -1
- package/dist/svelte/index.d.cts +0 -20
- package/dist/svelte/index.d.ts +0 -20
- package/dist/svelte/index.js +0 -72
- package/dist/svelte/index.js.map +0 -1
- package/dist/types-jYB7Wp7C.d.cts +0 -95
- package/dist/types-jYB7Wp7C.d.ts +0 -95
- package/dist/vanilla/index.cjs +0 -705
- package/dist/vanilla/index.cjs.map +0 -1
- package/dist/vanilla/index.d.cts +0 -7
- package/dist/vanilla/index.d.ts +0 -7
- package/dist/vanilla/index.js +0 -12
- package/dist/vanilla/index.js.map +0 -1
- package/dist/vue/index.cjs +0 -741
- package/dist/vue/index.cjs.map +0 -1
- package/dist/vue/index.d.cts +0 -13
- package/dist/vue/index.d.ts +0 -13
- package/dist/vue/index.js +0 -56
- package/dist/vue/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,12 +17,19 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var src_exports = {};
|
|
22
32
|
__export(src_exports, {
|
|
23
|
-
createEmptyFormState: () => createEmptyFormState,
|
|
24
33
|
createFormController: () => createFormController,
|
|
25
34
|
form: () => form,
|
|
26
35
|
parseFormData: () => parseFormData,
|
|
@@ -29,6 +38,353 @@ __export(src_exports, {
|
|
|
29
38
|
});
|
|
30
39
|
module.exports = __toCommonJS(src_exports);
|
|
31
40
|
|
|
41
|
+
// src/api/append.ts
|
|
42
|
+
var createAppend = (state2, helpers) => ({ tag, content, class: className, atStart = false }) => {
|
|
43
|
+
if (!state2.element) return null;
|
|
44
|
+
helpers.clearFieldCache();
|
|
45
|
+
if (className) {
|
|
46
|
+
const classSelector = className.trim().split(/\s+/)[0];
|
|
47
|
+
const existing = classSelector ? state2.element.querySelector(`.${classSelector}`) : null;
|
|
48
|
+
existing?.remove();
|
|
49
|
+
}
|
|
50
|
+
const node = document.createElement(tag);
|
|
51
|
+
if (className) node.className = className;
|
|
52
|
+
node.innerHTML = content;
|
|
53
|
+
if (atStart && state2.element.firstChild) {
|
|
54
|
+
state2.element.insertBefore(node, state2.element.firstChild);
|
|
55
|
+
} else {
|
|
56
|
+
state2.element.appendChild(node);
|
|
57
|
+
}
|
|
58
|
+
return node;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/api/auto-submit.ts
|
|
62
|
+
var createAutoSubmit = (state2, helpers) => (next = true) => {
|
|
63
|
+
state2.autoSubmitEnabled = next !== false;
|
|
64
|
+
state2.autoSubmitDebounce = typeof next === "object" && next ? next.debounce ?? 0 : 0;
|
|
65
|
+
helpers.notifySubscribers();
|
|
66
|
+
return state2.api;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// src/api/clear-errors.ts
|
|
70
|
+
var createClearErrors = (state2, helpers) => (fields) => {
|
|
71
|
+
if (!fields) {
|
|
72
|
+
state2.manualErrors = {};
|
|
73
|
+
helpers.syncVisualState();
|
|
74
|
+
helpers.notifySubscribers();
|
|
75
|
+
return state2.api;
|
|
76
|
+
}
|
|
77
|
+
for (const field of fields) {
|
|
78
|
+
delete state2.manualErrors[field];
|
|
79
|
+
}
|
|
80
|
+
helpers.syncVisualState(fields);
|
|
81
|
+
helpers.notifySubscribers();
|
|
82
|
+
return state2.api;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/core/format-helpers.ts
|
|
86
|
+
var FORMATTER_RAW_ATTRIBUTE = "data-formatter-raw-for";
|
|
87
|
+
var cssEscape = (value) => {
|
|
88
|
+
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
89
|
+
return CSS.escape(value);
|
|
90
|
+
}
|
|
91
|
+
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
|
|
92
|
+
};
|
|
93
|
+
var findRawMirror = (form2, fieldName) => {
|
|
94
|
+
const byAttr = form2.querySelector(
|
|
95
|
+
`[${FORMATTER_RAW_ATTRIBUTE}="${cssEscape(fieldName)}"]`
|
|
96
|
+
);
|
|
97
|
+
if (byAttr) return byAttr;
|
|
98
|
+
const byName = form2.querySelector(
|
|
99
|
+
`[name="${cssEscape(`${fieldName}_raw`)}"]`
|
|
100
|
+
);
|
|
101
|
+
if (byName) return byName;
|
|
102
|
+
const byNameOld = form2.querySelector(
|
|
103
|
+
`[name="${cssEscape(`${fieldName}Raw`)}"]`
|
|
104
|
+
);
|
|
105
|
+
if (byNameOld) return byNameOld;
|
|
106
|
+
return null;
|
|
107
|
+
};
|
|
108
|
+
var ensureRawMirror = (form2, fieldName) => {
|
|
109
|
+
const existing = findRawMirror(form2, fieldName);
|
|
110
|
+
if (existing) return existing;
|
|
111
|
+
const input = document.createElement("input");
|
|
112
|
+
input.type = "hidden";
|
|
113
|
+
input.name = `${fieldName}_raw`;
|
|
114
|
+
input.setAttribute("aria-hidden", "true");
|
|
115
|
+
input.tabIndex = -1;
|
|
116
|
+
input.setAttribute(FORMATTER_RAW_ATTRIBUTE, fieldName);
|
|
117
|
+
form2.appendChild(input);
|
|
118
|
+
return input;
|
|
119
|
+
};
|
|
120
|
+
var applyFormattedValue = (visible, mirror, formatted, raw) => {
|
|
121
|
+
const rawInput = visible.value;
|
|
122
|
+
const caret = clamp(
|
|
123
|
+
visible.selectionStart ?? rawInput.length,
|
|
124
|
+
0,
|
|
125
|
+
rawInput.length
|
|
126
|
+
);
|
|
127
|
+
if (rawInput === formatted) {
|
|
128
|
+
if (mirror && mirror.value !== raw) mirror.value = raw;
|
|
129
|
+
return caret;
|
|
130
|
+
}
|
|
131
|
+
visible.value = formatted;
|
|
132
|
+
if (mirror) mirror.value = raw;
|
|
133
|
+
const newCaret = computeCursorPosition(caret, rawInput, formatted);
|
|
134
|
+
restoreCursor(visible, newCaret);
|
|
135
|
+
return newCaret;
|
|
136
|
+
};
|
|
137
|
+
var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
138
|
+
var computeCursorPosition = (caretPos, rawInput, newValue) => {
|
|
139
|
+
if (newValue.length === 0) return 0;
|
|
140
|
+
if (caretPos >= rawInput.length) return newValue.length;
|
|
141
|
+
const targetNonFormat = countNonFormat(rawInput.slice(0, caretPos));
|
|
142
|
+
if (targetNonFormat === 0) {
|
|
143
|
+
let i = 0;
|
|
144
|
+
while (i < newValue.length && isFormatChar(newValue[i])) i += 1;
|
|
145
|
+
return i;
|
|
146
|
+
}
|
|
147
|
+
let seen = 0;
|
|
148
|
+
for (let i = 0; i < newValue.length; i += 1) {
|
|
149
|
+
if (!isFormatChar(newValue[i])) {
|
|
150
|
+
seen += 1;
|
|
151
|
+
if (seen === targetNonFormat) {
|
|
152
|
+
return Math.min(i + 1, newValue.length);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return newValue.length;
|
|
157
|
+
};
|
|
158
|
+
var countNonFormat = (value) => {
|
|
159
|
+
let count = 0;
|
|
160
|
+
for (const char of value) {
|
|
161
|
+
if (!isFormatChar(char)) count += 1;
|
|
162
|
+
}
|
|
163
|
+
return count;
|
|
164
|
+
};
|
|
165
|
+
var isFormatChar = (char) => {
|
|
166
|
+
if (!char) return false;
|
|
167
|
+
if (char >= "0" && char <= "9") return false;
|
|
168
|
+
if (char >= "a" && char <= "z" || char >= "A" && char <= "Z") return false;
|
|
169
|
+
return true;
|
|
170
|
+
};
|
|
171
|
+
var restoreCursor = (field, position) => {
|
|
172
|
+
const max = field.value.length;
|
|
173
|
+
const safe = clamp(position, 0, max);
|
|
174
|
+
const apply = () => {
|
|
175
|
+
try {
|
|
176
|
+
field.setSelectionRange(safe, safe);
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
if (typeof navigator !== "undefined" && /Android/i.test(navigator.userAgent)) {
|
|
181
|
+
if (typeof requestAnimationFrame === "function") {
|
|
182
|
+
requestAnimationFrame(apply);
|
|
183
|
+
} else {
|
|
184
|
+
setTimeout(apply, 1);
|
|
185
|
+
}
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
apply();
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// src/core/formatter-loader.ts
|
|
192
|
+
var state = null;
|
|
193
|
+
var MISSING_MESSAGE = "[samline/forms] The `format()` and `formatAll()` methods require the @samline/formatter package. Install it with: npm i @samline/formatter (or pnpm/bun/yarn equivalent).";
|
|
194
|
+
var warned = false;
|
|
195
|
+
var warnOnce = () => {
|
|
196
|
+
if (warned) return;
|
|
197
|
+
warned = true;
|
|
198
|
+
console.error(MISSING_MESSAGE);
|
|
199
|
+
};
|
|
200
|
+
var loadFormatter = () => {
|
|
201
|
+
if (state && state.status === "resolved") {
|
|
202
|
+
if (!state.module) warnOnce();
|
|
203
|
+
return Promise.resolve(state.module);
|
|
204
|
+
}
|
|
205
|
+
if (state && state.status === "pending") {
|
|
206
|
+
return state.promise;
|
|
207
|
+
}
|
|
208
|
+
const promise = (async () => {
|
|
209
|
+
try {
|
|
210
|
+
const mod = await import(
|
|
211
|
+
/* @vite-ignore */
|
|
212
|
+
"@samline/formatter"
|
|
213
|
+
);
|
|
214
|
+
state = { status: "resolved", module: mod };
|
|
215
|
+
return mod;
|
|
216
|
+
} catch {
|
|
217
|
+
warnOnce();
|
|
218
|
+
state = { status: "resolved", module: null };
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
})();
|
|
222
|
+
state = { status: "pending", promise };
|
|
223
|
+
return promise;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/api/format.ts
|
|
227
|
+
var registry = /* @__PURE__ */ new WeakMap();
|
|
228
|
+
var getRegistry = (state2) => {
|
|
229
|
+
let bucket = registry.get(state2);
|
|
230
|
+
if (!bucket) {
|
|
231
|
+
bucket = /* @__PURE__ */ new Map();
|
|
232
|
+
registry.set(state2, bucket);
|
|
233
|
+
}
|
|
234
|
+
return bucket;
|
|
235
|
+
};
|
|
236
|
+
var resolveFieldNames = (config) => Array.isArray(config.field) ? config.field : [config.field];
|
|
237
|
+
var addListener = (state2, target, type, handler) => {
|
|
238
|
+
target.addEventListener(type, handler);
|
|
239
|
+
state2.listeners.push({ element: target, type, handler });
|
|
240
|
+
};
|
|
241
|
+
var buildHandler = (field, mirror, formatFn, formatType, formatOptions, mirrorFieldName) => {
|
|
242
|
+
const handler = (event) => {
|
|
243
|
+
if (!field.isConnected) return;
|
|
244
|
+
if (event.target !== field) return;
|
|
245
|
+
const rawInput = event.target.value;
|
|
246
|
+
const { formatted, raw } = formatFn(rawInput, formatType, formatOptions);
|
|
247
|
+
if (!formatted && !raw) {
|
|
248
|
+
field.value = "";
|
|
249
|
+
if (mirror && mirror.value !== "") mirror.value = "";
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
applyFormattedValue(field, mirror, formatted, raw);
|
|
253
|
+
void mirrorFieldName;
|
|
254
|
+
};
|
|
255
|
+
return handler;
|
|
256
|
+
};
|
|
257
|
+
var applyFormat = async (state2, helpers, config) => {
|
|
258
|
+
if (!state2.element || !state2.api) return;
|
|
259
|
+
const formatter = await loadFormatter();
|
|
260
|
+
if (!formatter) return;
|
|
261
|
+
const formatType = config.type;
|
|
262
|
+
const formatOptions = config.options;
|
|
263
|
+
const fieldNames = resolveFieldNames(config);
|
|
264
|
+
const bucket = getRegistry(state2);
|
|
265
|
+
for (const fieldName of fieldNames) {
|
|
266
|
+
const fields = helpers.getFieldsByName(fieldName);
|
|
267
|
+
if (fields.length === 0) continue;
|
|
268
|
+
const writable = fields.filter(
|
|
269
|
+
(f) => f instanceof HTMLInputElement && f.type !== "checkbox" && f.type !== "radio" && f.type !== "file" && f.type !== "submit" && f.type !== "button" || f instanceof HTMLTextAreaElement
|
|
270
|
+
);
|
|
271
|
+
if (writable.length === 0) continue;
|
|
272
|
+
for (const field of writable) {
|
|
273
|
+
const existing = bucket.get(fieldName);
|
|
274
|
+
const mirrorName = config.rawField ?? `${fieldName}_raw`;
|
|
275
|
+
let mirror = findRawMirror(state2.element, fieldName) ?? null;
|
|
276
|
+
const mirrorIsOwned = !mirror;
|
|
277
|
+
if (!mirror) mirror = ensureRawMirror(state2.element, fieldName);
|
|
278
|
+
if (mirror && mirror.name !== mirrorName) mirror.name = mirrorName;
|
|
279
|
+
const trackerMirrorName = mirror?.name ?? mirrorName;
|
|
280
|
+
if (existing) {
|
|
281
|
+
existing.mirrorName = trackerMirrorName;
|
|
282
|
+
existing.mirrorIsOwned = mirrorIsOwned;
|
|
283
|
+
state2.formattedFields.set(fieldName, {
|
|
284
|
+
config,
|
|
285
|
+
mirrorName: trackerMirrorName,
|
|
286
|
+
mirrorIsOwned
|
|
287
|
+
});
|
|
288
|
+
const current = field.value;
|
|
289
|
+
if (current !== "") {
|
|
290
|
+
const { formatted, raw } = formatter.format(current, formatType, formatOptions);
|
|
291
|
+
applyFormattedValue(field, mirror, formatted, raw);
|
|
292
|
+
}
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const handler = buildHandler(
|
|
296
|
+
field,
|
|
297
|
+
mirror,
|
|
298
|
+
formatter.format,
|
|
299
|
+
formatType,
|
|
300
|
+
formatOptions,
|
|
301
|
+
trackerMirrorName
|
|
302
|
+
);
|
|
303
|
+
addListener(state2, state2.element, "input", handler);
|
|
304
|
+
bucket.set(fieldName, {
|
|
305
|
+
fields: /* @__PURE__ */ new Set([field]),
|
|
306
|
+
mirrorName: trackerMirrorName,
|
|
307
|
+
handler,
|
|
308
|
+
mirrorIsOwned
|
|
309
|
+
});
|
|
310
|
+
state2.formattedFields.set(fieldName, {
|
|
311
|
+
config,
|
|
312
|
+
mirrorName: trackerMirrorName,
|
|
313
|
+
mirrorIsOwned
|
|
314
|
+
});
|
|
315
|
+
const initial = field.value;
|
|
316
|
+
if (initial !== "") {
|
|
317
|
+
const { formatted, raw } = formatter.format(initial, formatType, formatOptions);
|
|
318
|
+
applyFormattedValue(field, mirror, formatted, raw);
|
|
319
|
+
} else if (mirrorIsOwned && mirror && mirror.value !== "") {
|
|
320
|
+
mirror.value = "";
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
var createFormat = (state2, helpers) => (config) => {
|
|
326
|
+
if (state2.isDestroyed) return state2.api;
|
|
327
|
+
if (!state2.element) return state2.api;
|
|
328
|
+
void applyFormat(state2, helpers, config);
|
|
329
|
+
return state2.api;
|
|
330
|
+
};
|
|
331
|
+
var createFormatAll = createFormat;
|
|
332
|
+
var cleanupFormatRegistry = (state2) => {
|
|
333
|
+
if (!state2.element) {
|
|
334
|
+
registry.delete(state2);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const bucket = registry.get(state2);
|
|
338
|
+
if (!bucket) {
|
|
339
|
+
state2.element.querySelectorAll(`[${FORMATTER_RAW_ATTRIBUTE}]`).forEach((node) => node.remove());
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
for (const [fieldName, entry] of bucket) {
|
|
343
|
+
state2.element.removeEventListener("input", entry.handler);
|
|
344
|
+
if (entry.mirrorIsOwned) {
|
|
345
|
+
const mirror = findRawMirror(state2.element, entry.mirrorName);
|
|
346
|
+
mirror?.remove();
|
|
347
|
+
}
|
|
348
|
+
bucket.delete(fieldName);
|
|
349
|
+
state2.formattedFields.delete(fieldName);
|
|
350
|
+
}
|
|
351
|
+
state2.element.querySelectorAll(`[${FORMATTER_RAW_ATTRIBUTE}]`).forEach((node) => node.remove());
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/api/destroy.ts
|
|
355
|
+
var createDestroy = (state2, _helpers) => () => {
|
|
356
|
+
if (state2.isDestroyed) return;
|
|
357
|
+
state2.isDestroyed = true;
|
|
358
|
+
for (const listener of state2.listeners) {
|
|
359
|
+
listener.element.removeEventListener(listener.type, listener.handler);
|
|
360
|
+
}
|
|
361
|
+
state2.listeners.length = 0;
|
|
362
|
+
if (state2.autoSubmitTimer) {
|
|
363
|
+
clearTimeout(state2.autoSubmitTimer);
|
|
364
|
+
state2.autoSubmitTimer = null;
|
|
365
|
+
}
|
|
366
|
+
state2.mutationObserver?.disconnect();
|
|
367
|
+
state2.mutationObserver = null;
|
|
368
|
+
state2.watchedFields.clear();
|
|
369
|
+
state2.subscribers.clear();
|
|
370
|
+
state2.submitHandlers.clear();
|
|
371
|
+
state2.fieldCache.clear();
|
|
372
|
+
state2.manualErrors = {};
|
|
373
|
+
state2.validationErrors = {};
|
|
374
|
+
cleanupFormatRegistry(state2);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// src/api/disable-auto-submit.ts
|
|
378
|
+
var createDisableAutoSubmit = (state2, helpers) => () => {
|
|
379
|
+
state2.autoSubmitEnabled = false;
|
|
380
|
+
if (state2.autoSubmitTimer) {
|
|
381
|
+
clearTimeout(state2.autoSubmitTimer);
|
|
382
|
+
state2.autoSubmitTimer = null;
|
|
383
|
+
}
|
|
384
|
+
helpers.notifySubscribers();
|
|
385
|
+
return state2.api;
|
|
386
|
+
};
|
|
387
|
+
|
|
32
388
|
// src/core/serialize.ts
|
|
33
389
|
var isEmptyFile = (value) => value instanceof File && value.size === 0 && value.name === "";
|
|
34
390
|
var appendValue = (data, key, value) => {
|
|
@@ -44,19 +400,30 @@ var appendValue = (data, key, value) => {
|
|
|
44
400
|
data[key] = [current, value];
|
|
45
401
|
};
|
|
46
402
|
var parseFormData = (formElement) => {
|
|
47
|
-
const
|
|
403
|
+
const raw = new FormData(formElement);
|
|
48
404
|
const formData = new FormData();
|
|
49
405
|
const data = {};
|
|
50
|
-
|
|
51
|
-
if (isEmptyFile(value))
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
406
|
+
raw.forEach((value, key) => {
|
|
407
|
+
if (isEmptyFile(value)) return;
|
|
54
408
|
formData.append(key, value);
|
|
55
409
|
appendValue(data, key, value);
|
|
56
410
|
});
|
|
57
411
|
return { data, formData };
|
|
58
412
|
};
|
|
59
413
|
|
|
414
|
+
// src/api/get-data.ts
|
|
415
|
+
var createGetData = (_state, _helpers) => () => {
|
|
416
|
+
if (!_state.element) return { data: {}, formData: new FormData() };
|
|
417
|
+
return parseFormData(_state.element);
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/api/get-field.ts
|
|
421
|
+
var createGetField = (state2, helpers) => (name) => {
|
|
422
|
+
const fields = helpers.getFieldsByName(name);
|
|
423
|
+
if (fields.length === 0) return null;
|
|
424
|
+
return fields.length === 1 ? fields[0] : fields;
|
|
425
|
+
};
|
|
426
|
+
|
|
60
427
|
// src/core/state.ts
|
|
61
428
|
var createEmptyFormState = () => ({
|
|
62
429
|
values: {},
|
|
@@ -67,98 +434,47 @@ var createEmptyFormState = () => ({
|
|
|
67
434
|
autoSubmit: false,
|
|
68
435
|
submitCount: 0
|
|
69
436
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return { value: rule.value, message: rule.message };
|
|
78
|
-
}
|
|
79
|
-
return { value: rule, message: void 0 };
|
|
80
|
-
};
|
|
81
|
-
var hasValue = (value) => {
|
|
82
|
-
if (Array.isArray(value)) {
|
|
83
|
-
return value.length > 0;
|
|
84
|
-
}
|
|
85
|
-
return typeof value === "string" ? value.trim().length > 0 : value !== void 0;
|
|
86
|
-
};
|
|
87
|
-
var getValueLength = (value) => {
|
|
88
|
-
if (Array.isArray(value)) {
|
|
89
|
-
return value.length;
|
|
90
|
-
}
|
|
91
|
-
if (typeof value === "string") {
|
|
92
|
-
return value.length;
|
|
93
|
-
}
|
|
94
|
-
return 0;
|
|
95
|
-
};
|
|
96
|
-
var toPatternTarget = (value) => {
|
|
97
|
-
if (typeof value === "string") {
|
|
98
|
-
return value;
|
|
99
|
-
}
|
|
100
|
-
if (Array.isArray(value)) {
|
|
101
|
-
return value.map((entry) => typeof entry === "string" ? entry : entry.name).join(",");
|
|
102
|
-
}
|
|
103
|
-
return "";
|
|
104
|
-
};
|
|
105
|
-
var validateFieldValue = (field, value, rules, values) => {
|
|
106
|
-
const errors = [];
|
|
107
|
-
const context = { field, value, values };
|
|
108
|
-
const required = resolveRule(rules.required);
|
|
109
|
-
const minLength = resolveRule(rules.minLength);
|
|
110
|
-
const maxLength = resolveRule(rules.maxLength);
|
|
111
|
-
const pattern = resolveRule(rules.pattern);
|
|
112
|
-
if (required.value && !hasValue(value)) {
|
|
113
|
-
errors.push(required.message ?? "This field is required.");
|
|
114
|
-
}
|
|
115
|
-
if (minLength.value !== void 0 && getValueLength(value) < minLength.value) {
|
|
116
|
-
errors.push(minLength.message ?? `Minimum length is ${minLength.value}.`);
|
|
117
|
-
}
|
|
118
|
-
if (maxLength.value !== void 0 && getValueLength(value) > maxLength.value) {
|
|
119
|
-
errors.push(maxLength.message ?? `Maximum length is ${maxLength.value}.`);
|
|
120
|
-
}
|
|
121
|
-
if (pattern.value && hasValue(value) && !pattern.value.test(toPatternTarget(value))) {
|
|
122
|
-
errors.push(pattern.message ?? "Value does not match the required pattern.");
|
|
123
|
-
}
|
|
124
|
-
const customValidators = rules.validate ? Array.isArray(rules.validate) ? rules.validate : [rules.validate] : [];
|
|
125
|
-
for (const validator of customValidators) {
|
|
126
|
-
const result = validator(context);
|
|
127
|
-
if (typeof result === "string" && result.length > 0) {
|
|
128
|
-
errors.push(result);
|
|
129
|
-
}
|
|
130
|
-
if (result === false) {
|
|
131
|
-
errors.push("Validation failed.");
|
|
132
|
-
}
|
|
437
|
+
var cloneErrors = (errors) => Object.fromEntries(
|
|
438
|
+
Object.entries(errors).map(([field, messages]) => [field, [...messages]])
|
|
439
|
+
);
|
|
440
|
+
var mergeErrors = (left, right) => {
|
|
441
|
+
const merged = { ...left };
|
|
442
|
+
for (const [field, messages] of Object.entries(right)) {
|
|
443
|
+
merged[field] = merged[field] ? [...merged[field], ...messages] : [...messages];
|
|
133
444
|
}
|
|
134
|
-
return
|
|
445
|
+
return merged;
|
|
135
446
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
447
|
+
|
|
448
|
+
// src/api/get-state.ts
|
|
449
|
+
var createGetState = (state2, helpers) => () => {
|
|
450
|
+
const values = helpers.getValues();
|
|
451
|
+
const errors = cloneErrors(helpers.getMergedErrors());
|
|
452
|
+
const filledFields = helpers.getTrackedFieldNames().filter((name) => {
|
|
453
|
+
const value = values[name];
|
|
454
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
455
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
456
|
+
return value !== void 0;
|
|
457
|
+
});
|
|
144
458
|
return {
|
|
459
|
+
...createEmptyFormState(),
|
|
460
|
+
values,
|
|
461
|
+
errors,
|
|
462
|
+
filledFields,
|
|
145
463
|
isValid: Object.keys(errors).length === 0,
|
|
146
|
-
|
|
464
|
+
isValidated: state2.isValidated,
|
|
465
|
+
autoSubmit: state2.autoSubmitEnabled,
|
|
466
|
+
submitCount: state2.submitCount
|
|
147
467
|
};
|
|
148
468
|
};
|
|
149
469
|
|
|
150
|
-
// src/
|
|
470
|
+
// src/core/dom.ts
|
|
151
471
|
var isFormFieldElement = (value) => value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
|
|
152
472
|
var resolveFormElement = (target) => {
|
|
153
|
-
if (!target)
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
if (target instanceof HTMLFormElement) {
|
|
157
|
-
return target;
|
|
158
|
-
}
|
|
473
|
+
if (!target) return null;
|
|
474
|
+
if (target instanceof HTMLFormElement) return target;
|
|
159
475
|
if (typeof target === "string") {
|
|
160
|
-
const
|
|
161
|
-
return
|
|
476
|
+
const node = document.getElementById(target);
|
|
477
|
+
return node instanceof HTMLFormElement ? node : null;
|
|
162
478
|
}
|
|
163
479
|
if ("current" in target) {
|
|
164
480
|
return target.current instanceof HTMLFormElement ? target.current : null;
|
|
@@ -169,14 +485,11 @@ var getNamedFields = (form2) => Array.from(form2.querySelectorAll("input[name],
|
|
|
169
485
|
isFormFieldElement
|
|
170
486
|
);
|
|
171
487
|
var queryNamedFields = (form2, name) => getNamedFields(form2).filter((field) => field.name === name);
|
|
488
|
+
var isFieldElement = (value) => isFormFieldElement(value);
|
|
172
489
|
var isFieldFilled = (field) => {
|
|
173
490
|
if (field instanceof HTMLInputElement) {
|
|
174
|
-
if (field.type === "checkbox" || field.type === "radio")
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
if (field.type === "file") {
|
|
178
|
-
return Boolean(field.files && field.files.length > 0);
|
|
179
|
-
}
|
|
491
|
+
if (field.type === "checkbox" || field.type === "radio") return field.checked;
|
|
492
|
+
if (field.type === "file") return Boolean(field.files && field.files.length > 0);
|
|
180
493
|
return field.value.trim() !== "";
|
|
181
494
|
}
|
|
182
495
|
return field.value !== "";
|
|
@@ -184,35 +497,35 @@ var isFieldFilled = (field) => {
|
|
|
184
497
|
var applyBooleanAttribute = (field, attribute, enabled) => {
|
|
185
498
|
if (enabled) {
|
|
186
499
|
field.setAttribute(attribute, "");
|
|
187
|
-
|
|
500
|
+
} else {
|
|
501
|
+
field.removeAttribute(attribute);
|
|
188
502
|
}
|
|
189
|
-
field.removeAttribute(attribute);
|
|
190
503
|
};
|
|
191
504
|
var readFieldValue = (fields) => {
|
|
192
|
-
if (fields.length === 0)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
505
|
+
if (fields.length === 0) return void 0;
|
|
506
|
+
const first = fields[0];
|
|
507
|
+
if (!first) return void 0;
|
|
508
|
+
if (first instanceof HTMLSelectElement || first instanceof HTMLTextAreaElement) {
|
|
509
|
+
return first.value;
|
|
510
|
+
}
|
|
511
|
+
if (first instanceof HTMLInputElement) {
|
|
512
|
+
if (first.type === "radio") {
|
|
513
|
+
const checked = fields.find(
|
|
514
|
+
(f) => f instanceof HTMLInputElement && f.checked
|
|
515
|
+
);
|
|
516
|
+
return checked?.value ?? "";
|
|
517
|
+
}
|
|
518
|
+
if (first.type === "checkbox") {
|
|
519
|
+
const values = fields.filter(
|
|
520
|
+
(f) => f instanceof HTMLInputElement && f.checked
|
|
521
|
+
).map((f) => f.value);
|
|
522
|
+
return values.length > 1 ? values : values[0] ?? "";
|
|
523
|
+
}
|
|
524
|
+
if (first.type === "file") {
|
|
525
|
+
return first.files ? Array.from(first.files) : [];
|
|
526
|
+
}
|
|
214
527
|
}
|
|
215
|
-
return
|
|
528
|
+
return first.value;
|
|
216
529
|
};
|
|
217
530
|
var writeFieldValue = (fields, value) => {
|
|
218
531
|
const normalizedArray = Array.isArray(value) ? value.map((item) => String(item)) : null;
|
|
@@ -228,9 +541,7 @@ var writeFieldValue = (fields, value) => {
|
|
|
228
541
|
continue;
|
|
229
542
|
}
|
|
230
543
|
if (field.type === "file") {
|
|
231
|
-
if (Array.isArray(value) && value.length === 0)
|
|
232
|
-
field.value = "";
|
|
233
|
-
}
|
|
544
|
+
if (Array.isArray(value) && value.length === 0) field.value = "";
|
|
234
545
|
continue;
|
|
235
546
|
}
|
|
236
547
|
field.value = normalizedValue;
|
|
@@ -241,9 +552,7 @@ var writeFieldValue = (fields, value) => {
|
|
|
241
552
|
};
|
|
242
553
|
var clearAttributes = (form2, attributes) => {
|
|
243
554
|
for (const attribute of attributes) {
|
|
244
|
-
form2.querySelectorAll(`[${attribute}]`).forEach((
|
|
245
|
-
element.removeAttribute(attribute);
|
|
246
|
-
});
|
|
555
|
+
form2.querySelectorAll(`[${attribute}]`).forEach((node) => node.removeAttribute(attribute));
|
|
247
556
|
}
|
|
248
557
|
};
|
|
249
558
|
var submitForm = (form2) => {
|
|
@@ -261,26 +570,205 @@ var submitForm = (form2) => {
|
|
|
261
570
|
form2.submit();
|
|
262
571
|
};
|
|
263
572
|
|
|
264
|
-
// src/
|
|
573
|
+
// src/api/get-value.ts
|
|
574
|
+
var createGetValue = (state2, helpers) => (name) => readFieldValue(helpers.getFieldsByName(name));
|
|
575
|
+
|
|
576
|
+
// src/api/observe.ts
|
|
577
|
+
var createObserve = (state2, helpers) => (field, callback) => {
|
|
578
|
+
const callbacks = state2.watchedFields.get(field) ?? /* @__PURE__ */ new Set();
|
|
579
|
+
callbacks.add(callback);
|
|
580
|
+
state2.watchedFields.set(field, callbacks);
|
|
581
|
+
if (state2.element) {
|
|
582
|
+
callback(state2.api.getValue(field), state2.api.getField(field), state2.element, state2.api.getState());
|
|
583
|
+
}
|
|
584
|
+
return () => {
|
|
585
|
+
const current = state2.watchedFields.get(field);
|
|
586
|
+
current?.delete(callback);
|
|
587
|
+
if (current && current.size === 0) {
|
|
588
|
+
state2.watchedFields.delete(field);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// src/api/on-submit.ts
|
|
594
|
+
var createOnSubmit = (state2, _helpers) => (callback, preventDefault = true) => {
|
|
595
|
+
state2.submitHandlers.add({ callback, preventDefault });
|
|
596
|
+
return state2.api;
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
// src/api/prefill.ts
|
|
600
|
+
var createPrefill = (state2, _helpers) => (fieldName) => {
|
|
601
|
+
if (!state2.element) return state2.api;
|
|
602
|
+
const params = new URLSearchParams(window.location.search);
|
|
603
|
+
params.forEach((value, key) => {
|
|
604
|
+
if (fieldName && fieldName !== key) return;
|
|
605
|
+
state2.api.setValue(key, value);
|
|
606
|
+
});
|
|
607
|
+
return state2.api;
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// src/api/reset.ts
|
|
611
|
+
var createReset = (state2, helpers) => () => {
|
|
612
|
+
if (!state2.element) return state2.api;
|
|
613
|
+
state2.element.reset();
|
|
614
|
+
state2.manualErrors = {};
|
|
615
|
+
state2.validationErrors = {};
|
|
616
|
+
clearAttributes(state2.element, [state2.attributes.error, state2.attributes.filled]);
|
|
617
|
+
if (state2.isValidated) helpers.syncVisualState();
|
|
618
|
+
helpers.notifySubscribers();
|
|
619
|
+
return state2.api;
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
// src/api/validate.ts
|
|
623
|
+
var createValidate = (state2, helpers) => (fields) => {
|
|
624
|
+
state2.isValidated = true;
|
|
625
|
+
helpers.syncVisualState(fields);
|
|
626
|
+
return helpers.validateNames(fields);
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
// src/api/revalidate.ts
|
|
630
|
+
var createRevalidate = createValidate;
|
|
631
|
+
|
|
632
|
+
// src/api/set-errors.ts
|
|
633
|
+
var createSetErrors = (state2, helpers) => (fields) => {
|
|
634
|
+
if (Array.isArray(fields)) {
|
|
635
|
+
state2.manualErrors = {
|
|
636
|
+
...state2.manualErrors,
|
|
637
|
+
...Object.fromEntries(fields.map((field) => [field, ["Invalid value."]]))
|
|
638
|
+
};
|
|
639
|
+
} else {
|
|
640
|
+
state2.manualErrors = {
|
|
641
|
+
...state2.manualErrors,
|
|
642
|
+
...cloneErrors(fields)
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
helpers.syncVisualState(Array.isArray(fields) ? fields : Object.keys(fields));
|
|
646
|
+
helpers.notifySubscribers();
|
|
647
|
+
return state2.api;
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
// src/api/set-value.ts
|
|
651
|
+
var createSetValue = (state2, helpers) => (name, value) => {
|
|
652
|
+
const fields = helpers.getFieldsByName(name);
|
|
653
|
+
if (fields.length === 0) return state2.api;
|
|
654
|
+
writeFieldValue(fields, value);
|
|
655
|
+
const firstField = fields[0];
|
|
656
|
+
if (!firstField) return state2.api;
|
|
657
|
+
const eventType = firstField instanceof HTMLSelectElement || firstField instanceof HTMLInputElement && (firstField.type === "checkbox" || firstField.type === "radio") ? "change" : "input";
|
|
658
|
+
firstField.dispatchEvent(new Event(eventType, { bubbles: true }));
|
|
659
|
+
return state2.api;
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/api/subscribe.ts
|
|
663
|
+
var createSubscribe = (state2, _helpers) => (listener) => {
|
|
664
|
+
state2.subscribers.add(listener);
|
|
665
|
+
listener(state2.api.getState());
|
|
666
|
+
return () => {
|
|
667
|
+
state2.subscribers.delete(listener);
|
|
668
|
+
};
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
// src/api/unwatch.ts
|
|
672
|
+
var createUnwatch = (state2, _helpers) => (field, callback) => {
|
|
673
|
+
if (!field) {
|
|
674
|
+
state2.watchedFields.clear();
|
|
675
|
+
return state2.api;
|
|
676
|
+
}
|
|
677
|
+
if (!callback) {
|
|
678
|
+
state2.watchedFields.delete(field);
|
|
679
|
+
return state2.api;
|
|
680
|
+
}
|
|
681
|
+
const callbacks = state2.watchedFields.get(field);
|
|
682
|
+
callbacks?.delete(callback);
|
|
683
|
+
if (callbacks && callbacks.size === 0) {
|
|
684
|
+
state2.watchedFields.delete(field);
|
|
685
|
+
}
|
|
686
|
+
return state2.api;
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// src/api/watch.ts
|
|
690
|
+
var createWatch = (state2, helpers) => (field, callback) => {
|
|
691
|
+
const observe = createObserve(state2, helpers);
|
|
692
|
+
observe(field, callback);
|
|
693
|
+
return state2.api;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// src/core/validation.ts
|
|
697
|
+
var resolveRule = (rule) => {
|
|
698
|
+
if (rule === void 0) {
|
|
699
|
+
return { value: void 0, message: void 0 };
|
|
700
|
+
}
|
|
701
|
+
if (typeof rule === "object" && rule !== null && "value" in rule) {
|
|
702
|
+
return { value: rule.value, message: rule.message };
|
|
703
|
+
}
|
|
704
|
+
return { value: rule, message: void 0 };
|
|
705
|
+
};
|
|
706
|
+
var hasValue = (value) => {
|
|
707
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
708
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
709
|
+
return value !== void 0;
|
|
710
|
+
};
|
|
711
|
+
var getValueLength = (value) => {
|
|
712
|
+
if (Array.isArray(value)) return value.length;
|
|
713
|
+
if (typeof value === "string") return value.length;
|
|
714
|
+
return 0;
|
|
715
|
+
};
|
|
716
|
+
var toPatternTarget = (value) => {
|
|
717
|
+
if (typeof value === "string") return value;
|
|
718
|
+
if (Array.isArray(value)) {
|
|
719
|
+
return value.map((entry) => typeof entry === "string" ? entry : entry.name).join(",");
|
|
720
|
+
}
|
|
721
|
+
return "";
|
|
722
|
+
};
|
|
723
|
+
var validateFieldValue = (field, value, rules, values) => {
|
|
724
|
+
const errors = [];
|
|
725
|
+
const context = { field, value, values };
|
|
726
|
+
const required = resolveRule(rules.required);
|
|
727
|
+
const minLength = resolveRule(rules.minLength);
|
|
728
|
+
const maxLength = resolveRule(rules.maxLength);
|
|
729
|
+
const pattern = resolveRule(rules.pattern);
|
|
730
|
+
if (required.value && !hasValue(value)) {
|
|
731
|
+
errors.push(required.message ?? "This field is required.");
|
|
732
|
+
}
|
|
733
|
+
if (minLength.value !== void 0 && getValueLength(value) < minLength.value) {
|
|
734
|
+
errors.push(minLength.message ?? `Minimum length is ${minLength.value}.`);
|
|
735
|
+
}
|
|
736
|
+
if (maxLength.value !== void 0 && getValueLength(value) > maxLength.value) {
|
|
737
|
+
errors.push(maxLength.message ?? `Maximum length is ${maxLength.value}.`);
|
|
738
|
+
}
|
|
739
|
+
if (pattern.value && hasValue(value) && !pattern.value.test(toPatternTarget(value))) {
|
|
740
|
+
errors.push(pattern.message ?? "Value does not match the required pattern.");
|
|
741
|
+
}
|
|
742
|
+
const custom = rules.validate ? Array.isArray(rules.validate) ? rules.validate : [rules.validate] : [];
|
|
743
|
+
for (const validator of custom) {
|
|
744
|
+
const result = validator(context);
|
|
745
|
+
if (typeof result === "string" && result.length > 0) errors.push(result);
|
|
746
|
+
if (result === false) errors.push("Validation failed.");
|
|
747
|
+
}
|
|
748
|
+
return errors;
|
|
749
|
+
};
|
|
750
|
+
var validateValues = (values, schema) => {
|
|
751
|
+
const errors = {};
|
|
752
|
+
for (const [field, rules] of Object.entries(schema)) {
|
|
753
|
+
const messages = validateFieldValue(field, values[field], rules, values);
|
|
754
|
+
if (messages.length > 0) errors[field] = messages;
|
|
755
|
+
}
|
|
756
|
+
return {
|
|
757
|
+
isValid: Object.keys(errors).length === 0,
|
|
758
|
+
errors
|
|
759
|
+
};
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// src/core/controller.ts
|
|
265
763
|
var DEFAULT_ATTRIBUTES = {
|
|
266
764
|
filled: "css-filled",
|
|
267
765
|
error: "css-error"
|
|
268
766
|
};
|
|
269
767
|
var DEFAULT_OPTIONS = {
|
|
270
768
|
autoValidate: true,
|
|
271
|
-
|
|
272
|
-
|
|
769
|
+
clearErrorsOnSubmit: true,
|
|
770
|
+
clearManualErrorsOnChange: true
|
|
273
771
|
};
|
|
274
|
-
var mergeErrors = (left, right) => {
|
|
275
|
-
const merged = { ...left };
|
|
276
|
-
for (const [field, messages] of Object.entries(right)) {
|
|
277
|
-
merged[field] = merged[field] ? [...merged[field], ...messages] : [...messages];
|
|
278
|
-
}
|
|
279
|
-
return merged;
|
|
280
|
-
};
|
|
281
|
-
var cloneErrors = (errors) => Object.fromEntries(
|
|
282
|
-
Object.entries(errors).map(([field, messages]) => [field, [...messages]])
|
|
283
|
-
);
|
|
284
772
|
var createFormController = (target, options = {}) => {
|
|
285
773
|
const element = resolveFormElement(target);
|
|
286
774
|
const attributes = { ...DEFAULT_ATTRIBUTES, ...options.attributes };
|
|
@@ -289,47 +777,49 @@ var createFormController = (target, options = {}) => {
|
|
|
289
777
|
...options,
|
|
290
778
|
attributes
|
|
291
779
|
};
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
780
|
+
const state2 = {
|
|
781
|
+
element,
|
|
782
|
+
options: normalizedOptions,
|
|
783
|
+
attributes,
|
|
784
|
+
validators: normalizedOptions.validators ?? {},
|
|
785
|
+
watchedFields: /* @__PURE__ */ new Map(),
|
|
786
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
787
|
+
submitHandlers: /* @__PURE__ */ new Set(),
|
|
788
|
+
fieldCache: /* @__PURE__ */ new Map(),
|
|
789
|
+
manualErrors: {},
|
|
790
|
+
validationErrors: {},
|
|
791
|
+
isValidated: Boolean(normalizedOptions.autoValidate),
|
|
792
|
+
autoSubmitEnabled: false,
|
|
793
|
+
autoSubmitDebounce: 0,
|
|
794
|
+
submitCount: 0,
|
|
795
|
+
autoSubmitTimer: null,
|
|
796
|
+
isDestroyed: false,
|
|
797
|
+
listeners: [],
|
|
798
|
+
mutationObserver: null,
|
|
799
|
+
formattedFields: /* @__PURE__ */ new Map(),
|
|
800
|
+
api: null
|
|
310
801
|
};
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
802
|
+
const notifySubscribers = () => {
|
|
803
|
+
if (!state2.api) return;
|
|
804
|
+
const snapshot = state2.api.getState();
|
|
805
|
+
state2.subscribers.forEach((listener) => listener(snapshot));
|
|
314
806
|
};
|
|
315
|
-
const
|
|
316
|
-
|
|
807
|
+
const addListener2 = (node, type, handler) => {
|
|
808
|
+
node.addEventListener(type, handler);
|
|
809
|
+
state2.listeners.push({ element: node, type, handler });
|
|
317
810
|
};
|
|
811
|
+
const clearFieldCache = () => state2.fieldCache.clear();
|
|
318
812
|
const getFieldsByName = (name) => {
|
|
319
|
-
if (!element)
|
|
320
|
-
|
|
813
|
+
if (!state2.element) return [];
|
|
814
|
+
if (!state2.fieldCache.has(name)) {
|
|
815
|
+
state2.fieldCache.set(name, queryNamedFields(state2.element, name));
|
|
321
816
|
}
|
|
322
|
-
|
|
323
|
-
fieldCache.set(name, queryNamedFields(element, name));
|
|
324
|
-
}
|
|
325
|
-
return fieldCache.get(name) ?? [];
|
|
817
|
+
return state2.fieldCache.get(name) ?? [];
|
|
326
818
|
};
|
|
327
819
|
const getTrackedFieldNames = () => {
|
|
328
|
-
if (!element)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const names = new Set(Object.keys(validators));
|
|
332
|
-
for (const field of getNamedFields(element)) {
|
|
820
|
+
if (!state2.element) return Object.keys(state2.validators);
|
|
821
|
+
const names = new Set(Object.keys(state2.validators));
|
|
822
|
+
for (const field of getNamedFields(state2.element)) {
|
|
333
823
|
names.add(field.name);
|
|
334
824
|
}
|
|
335
825
|
return Array.from(names);
|
|
@@ -337,15 +827,13 @@ var createFormController = (target, options = {}) => {
|
|
|
337
827
|
const getValues = () => {
|
|
338
828
|
const values = {};
|
|
339
829
|
for (const name of getTrackedFieldNames()) {
|
|
340
|
-
values[name] =
|
|
830
|
+
values[name] = readFieldValue(getFieldsByName(name));
|
|
341
831
|
}
|
|
342
832
|
return values;
|
|
343
833
|
};
|
|
344
|
-
const getMergedErrors = () => mergeErrors(validationErrors, manualErrors);
|
|
834
|
+
const getMergedErrors = () => mergeErrors(state2.validationErrors, state2.manualErrors);
|
|
345
835
|
const syncVisualState = (names) => {
|
|
346
|
-
if (!element)
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
836
|
+
if (!state2.element) return;
|
|
349
837
|
const targetNames = names ?? getTrackedFieldNames();
|
|
350
838
|
const errors = getMergedErrors();
|
|
351
839
|
for (const name of targetNames) {
|
|
@@ -357,24 +845,23 @@ var createFormController = (target, options = {}) => {
|
|
|
357
845
|
}
|
|
358
846
|
}
|
|
359
847
|
};
|
|
848
|
+
void readFieldValue;
|
|
849
|
+
void writeFieldValue;
|
|
360
850
|
const validateNames = (names) => {
|
|
361
|
-
const targetNames = names ?? Object.keys(validators);
|
|
851
|
+
const targetNames = names ?? Object.keys(state2.validators);
|
|
362
852
|
const values = getValues();
|
|
363
|
-
const nextValidationErrors = names ? cloneErrors(validationErrors) : {};
|
|
853
|
+
const nextValidationErrors = names ? cloneErrors(state2.validationErrors) : {};
|
|
364
854
|
for (const name of targetNames) {
|
|
365
|
-
const rules = validators[name];
|
|
855
|
+
const rules = state2.validators[name];
|
|
366
856
|
if (!rules) {
|
|
367
857
|
delete nextValidationErrors[name];
|
|
368
858
|
continue;
|
|
369
859
|
}
|
|
370
|
-
const
|
|
371
|
-
if (
|
|
372
|
-
|
|
373
|
-
} else {
|
|
374
|
-
delete nextValidationErrors[name];
|
|
375
|
-
}
|
|
860
|
+
const messages = validateFieldValue(name, values[name], rules, values);
|
|
861
|
+
if (messages.length > 0) nextValidationErrors[name] = messages;
|
|
862
|
+
else delete nextValidationErrors[name];
|
|
376
863
|
}
|
|
377
|
-
validationErrors = nextValidationErrors;
|
|
864
|
+
state2.validationErrors = nextValidationErrors;
|
|
378
865
|
syncVisualState(names);
|
|
379
866
|
return {
|
|
380
867
|
isValid: Object.keys(getMergedErrors()).length === 0,
|
|
@@ -382,45 +869,49 @@ var createFormController = (target, options = {}) => {
|
|
|
382
869
|
};
|
|
383
870
|
};
|
|
384
871
|
const emitFieldWatchers = (name) => {
|
|
385
|
-
if (!element)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const value = api.getValue(name);
|
|
393
|
-
const state = api.getState();
|
|
394
|
-
callbacks.forEach((callback) => callback(value, element, state));
|
|
872
|
+
if (!state2.element || !state2.api) return;
|
|
873
|
+
const callbacks = state2.watchedFields.get(name);
|
|
874
|
+
if (!callbacks || callbacks.size === 0) return;
|
|
875
|
+
const value = state2.api.getValue(name);
|
|
876
|
+
const fieldElement = state2.api.getField(name);
|
|
877
|
+
const snapshot = state2.api.getState();
|
|
878
|
+
callbacks.forEach((callback) => callback(value, fieldElement, state2.element, snapshot));
|
|
395
879
|
};
|
|
396
880
|
const scheduleAutoSubmit = () => {
|
|
397
|
-
if (!element || !autoSubmitEnabled)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
autoSubmitTimer = setTimeout(() => submitForm(element), autoSubmitDebounce);
|
|
881
|
+
if (!state2.element || !state2.autoSubmitEnabled) return;
|
|
882
|
+
if (state2.autoSubmitTimer) clearTimeout(state2.autoSubmitTimer);
|
|
883
|
+
if (state2.autoSubmitDebounce > 0) {
|
|
884
|
+
state2.autoSubmitTimer = setTimeout(
|
|
885
|
+
() => submitForm(state2.element),
|
|
886
|
+
state2.autoSubmitDebounce
|
|
887
|
+
);
|
|
405
888
|
return;
|
|
406
889
|
}
|
|
407
|
-
submitForm(element);
|
|
890
|
+
submitForm(state2.element);
|
|
891
|
+
};
|
|
892
|
+
const helpers = {
|
|
893
|
+
notifySubscribers,
|
|
894
|
+
clearFieldCache,
|
|
895
|
+
getFieldsByName,
|
|
896
|
+
getTrackedFieldNames,
|
|
897
|
+
getValues,
|
|
898
|
+
getMergedErrors,
|
|
899
|
+
syncVisualState,
|
|
900
|
+
validateNames,
|
|
901
|
+
emitFieldWatchers,
|
|
902
|
+
scheduleAutoSubmit
|
|
408
903
|
};
|
|
409
904
|
const handleDelegatedEvent = (event) => {
|
|
410
905
|
const target2 = event.target;
|
|
411
|
-
if (!(target2 instanceof Element) || !isFieldElement(target2))
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
906
|
+
if (!(target2 instanceof Element) || !isFieldElement(target2)) return;
|
|
414
907
|
const name = target2.name;
|
|
415
|
-
if (!name)
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
908
|
+
if (!name) return;
|
|
418
909
|
clearFieldCache();
|
|
419
910
|
if (normalizedOptions.clearManualErrorsOnChange) {
|
|
420
|
-
delete manualErrors[name];
|
|
911
|
+
delete state2.manualErrors[name];
|
|
421
912
|
}
|
|
422
913
|
syncVisualState([name]);
|
|
423
|
-
if (isValidated && validators[name]) {
|
|
914
|
+
if (state2.isValidated && state2.validators[name]) {
|
|
424
915
|
validateNames([name]);
|
|
425
916
|
}
|
|
426
917
|
emitFieldWatchers(name);
|
|
@@ -428,295 +919,97 @@ var createFormController = (target, options = {}) => {
|
|
|
428
919
|
scheduleAutoSubmit();
|
|
429
920
|
};
|
|
430
921
|
const handleSubmitEvent = (event) => {
|
|
431
|
-
if (!element || isDestroyed)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
manualErrors = {};
|
|
436
|
-
}
|
|
437
|
-
const validation = api.validate();
|
|
438
|
-
const handlers = Array.from(submitHandlers);
|
|
922
|
+
if (!state2.element || state2.isDestroyed || !state2.api) return;
|
|
923
|
+
if (normalizedOptions.clearErrorsOnSubmit) state2.manualErrors = {};
|
|
924
|
+
const validation = state2.api.validate();
|
|
925
|
+
const handlers = Array.from(state2.submitHandlers);
|
|
439
926
|
const shouldPrevent = validation.isValid ? handlers.some((handler) => handler.preventDefault) : true;
|
|
440
|
-
if (shouldPrevent)
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
submitCount += 1;
|
|
927
|
+
if (shouldPrevent) event.preventDefault();
|
|
928
|
+
state2.submitCount += 1;
|
|
444
929
|
notifySubscribers();
|
|
445
|
-
if (!validation.isValid)
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
930
|
+
if (!validation.isValid) return;
|
|
931
|
+
const { data, formData } = state2.api.getData();
|
|
932
|
+
const snapshot = state2.api.getState();
|
|
933
|
+
handlers.forEach(
|
|
934
|
+
(handler) => handler.callback(state2.element, data, formData, snapshot)
|
|
935
|
+
);
|
|
451
936
|
};
|
|
452
937
|
const startMutationObserver = () => {
|
|
453
|
-
if (!element || typeof MutationObserver === "undefined")
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
mutationObserver = new MutationObserver(() => {
|
|
938
|
+
if (!state2.element || typeof MutationObserver === "undefined") return;
|
|
939
|
+
state2.mutationObserver = new MutationObserver(() => {
|
|
457
940
|
clearFieldCache();
|
|
458
|
-
if (isValidated) {
|
|
941
|
+
if (state2.isValidated) {
|
|
459
942
|
syncVisualState();
|
|
460
943
|
validateNames();
|
|
461
944
|
}
|
|
462
945
|
notifySubscribers();
|
|
463
946
|
});
|
|
464
|
-
mutationObserver.observe(element, {
|
|
947
|
+
state2.mutationObserver.observe(state2.element, {
|
|
465
948
|
childList: true,
|
|
466
949
|
subtree: true,
|
|
467
950
|
attributes: true,
|
|
468
951
|
attributeFilter: ["name", "type"]
|
|
469
952
|
});
|
|
470
953
|
};
|
|
471
|
-
const isFieldElement = (value) => value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
|
|
472
954
|
const api = {
|
|
473
|
-
element
|
|
474
|
-
|
|
475
|
-
options: normalizedOptions,
|
|
476
|
-
onSubmit(callback, preventDefault = true) {
|
|
477
|
-
submitHandlers.add({ callback, preventDefault });
|
|
478
|
-
return api;
|
|
955
|
+
get element() {
|
|
956
|
+
return state2.element;
|
|
479
957
|
},
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return api;
|
|
958
|
+
get f() {
|
|
959
|
+
return state2.element;
|
|
483
960
|
},
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
callbacks.add(callback);
|
|
487
|
-
watchedFields.set(field, callbacks);
|
|
488
|
-
if (element) {
|
|
489
|
-
callback(api.getValue(field), element, api.getState());
|
|
490
|
-
}
|
|
491
|
-
return () => {
|
|
492
|
-
const currentCallbacks = watchedFields.get(field);
|
|
493
|
-
currentCallbacks?.delete(callback);
|
|
494
|
-
if (currentCallbacks && currentCallbacks.size === 0) {
|
|
495
|
-
watchedFields.delete(field);
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
},
|
|
499
|
-
unwatch(field, callback) {
|
|
500
|
-
if (!field) {
|
|
501
|
-
watchedFields.clear();
|
|
502
|
-
return api;
|
|
503
|
-
}
|
|
504
|
-
if (!callback) {
|
|
505
|
-
watchedFields.delete(field);
|
|
506
|
-
return api;
|
|
507
|
-
}
|
|
508
|
-
const callbacks = watchedFields.get(field);
|
|
509
|
-
callbacks?.delete(callback);
|
|
510
|
-
if (callbacks && callbacks.size === 0) {
|
|
511
|
-
watchedFields.delete(field);
|
|
512
|
-
}
|
|
513
|
-
return api;
|
|
961
|
+
get options() {
|
|
962
|
+
return state2.options;
|
|
514
963
|
},
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return null;
|
|
538
|
-
}
|
|
539
|
-
clearFieldCache();
|
|
540
|
-
if (className) {
|
|
541
|
-
const classSelector = className.trim().split(/\s+/)[0];
|
|
542
|
-
element.querySelector(`.${classSelector}`)?.remove();
|
|
543
|
-
}
|
|
544
|
-
const node = document.createElement(tag);
|
|
545
|
-
if (className) {
|
|
546
|
-
node.className = className;
|
|
547
|
-
}
|
|
548
|
-
node.innerHTML = content;
|
|
549
|
-
if (atStart && element.firstChild) {
|
|
550
|
-
element.insertBefore(node, element.firstChild);
|
|
551
|
-
} else {
|
|
552
|
-
element.appendChild(node);
|
|
553
|
-
}
|
|
554
|
-
return node;
|
|
555
|
-
},
|
|
556
|
-
setErrors(fields) {
|
|
557
|
-
if (Array.isArray(fields)) {
|
|
558
|
-
manualErrors = {
|
|
559
|
-
...manualErrors,
|
|
560
|
-
...Object.fromEntries(fields.map((field) => [field, ["Invalid value."]]))
|
|
561
|
-
};
|
|
562
|
-
} else {
|
|
563
|
-
manualErrors = {
|
|
564
|
-
...manualErrors,
|
|
565
|
-
...cloneErrors(fields)
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
syncVisualState(Array.isArray(fields) ? fields : Object.keys(fields));
|
|
569
|
-
notifySubscribers();
|
|
570
|
-
return api;
|
|
571
|
-
},
|
|
572
|
-
clearErrors(fields) {
|
|
573
|
-
if (!fields) {
|
|
574
|
-
manualErrors = {};
|
|
575
|
-
syncVisualState();
|
|
576
|
-
notifySubscribers();
|
|
577
|
-
return api;
|
|
578
|
-
}
|
|
579
|
-
for (const field of fields) {
|
|
580
|
-
delete manualErrors[field];
|
|
581
|
-
}
|
|
582
|
-
syncVisualState(fields);
|
|
583
|
-
notifySubscribers();
|
|
584
|
-
return api;
|
|
585
|
-
},
|
|
586
|
-
setValue(name, value) {
|
|
587
|
-
const fields = getFieldsByName(name);
|
|
588
|
-
if (fields.length === 0) {
|
|
589
|
-
return api;
|
|
590
|
-
}
|
|
591
|
-
writeFieldValue(fields, value);
|
|
592
|
-
const firstField = fields[0];
|
|
593
|
-
if (!firstField) {
|
|
594
|
-
return api;
|
|
595
|
-
}
|
|
596
|
-
const eventType = firstField instanceof HTMLSelectElement || firstField instanceof HTMLInputElement && (firstField.type === "checkbox" || firstField.type === "radio") ? "change" : "input";
|
|
597
|
-
firstField.dispatchEvent(new Event(eventType, { bubbles: true }));
|
|
598
|
-
return api;
|
|
599
|
-
},
|
|
600
|
-
validate(fields) {
|
|
601
|
-
isValidated = true;
|
|
602
|
-
syncVisualState(fields);
|
|
603
|
-
return validateNames(fields);
|
|
604
|
-
},
|
|
605
|
-
revalidate(fields) {
|
|
606
|
-
return api.validate(fields);
|
|
607
|
-
},
|
|
608
|
-
reset() {
|
|
609
|
-
if (!element) {
|
|
610
|
-
return api;
|
|
611
|
-
}
|
|
612
|
-
element.reset();
|
|
613
|
-
manualErrors = {};
|
|
614
|
-
validationErrors = {};
|
|
615
|
-
clearAttributes(element, [attributes.error, attributes.filled]);
|
|
616
|
-
if (isValidated) {
|
|
617
|
-
syncVisualState();
|
|
618
|
-
}
|
|
619
|
-
notifySubscribers();
|
|
620
|
-
return api;
|
|
621
|
-
},
|
|
622
|
-
autoSubmit(nextOptions = true) {
|
|
623
|
-
autoSubmitEnabled = nextOptions !== false;
|
|
624
|
-
autoSubmitDebounce = typeof nextOptions === "object" && nextOptions ? nextOptions.debounce ?? 0 : 0;
|
|
625
|
-
notifySubscribers();
|
|
626
|
-
return api;
|
|
627
|
-
},
|
|
628
|
-
disableAutoSubmit() {
|
|
629
|
-
autoSubmitEnabled = false;
|
|
630
|
-
if (autoSubmitTimer) {
|
|
631
|
-
clearTimeout(autoSubmitTimer);
|
|
632
|
-
autoSubmitTimer = null;
|
|
633
|
-
}
|
|
634
|
-
notifySubscribers();
|
|
635
|
-
return api;
|
|
636
|
-
},
|
|
637
|
-
getValue(name) {
|
|
638
|
-
return readFieldValue(getFieldsByName(name));
|
|
639
|
-
},
|
|
640
|
-
getField(name) {
|
|
641
|
-
const fields = getFieldsByName(name);
|
|
642
|
-
if (fields.length === 0) {
|
|
643
|
-
return null;
|
|
644
|
-
}
|
|
645
|
-
const [firstField] = fields;
|
|
646
|
-
if (!firstField) {
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
return fields.length === 1 ? firstField : fields;
|
|
650
|
-
},
|
|
651
|
-
getData() {
|
|
652
|
-
if (!element) {
|
|
653
|
-
return { data: {}, formData: new FormData() };
|
|
654
|
-
}
|
|
655
|
-
return parseFormData(element);
|
|
656
|
-
},
|
|
657
|
-
getState() {
|
|
658
|
-
const values = getValues();
|
|
659
|
-
const errors = cloneErrors(getMergedErrors());
|
|
660
|
-
const filledFields = getTrackedFieldNames().filter((name) => {
|
|
661
|
-
const value = values[name];
|
|
662
|
-
return Array.isArray(value) ? value.length > 0 : typeof value === "string" ? value.trim().length > 0 : value !== void 0;
|
|
663
|
-
});
|
|
664
|
-
return {
|
|
665
|
-
...createEmptyFormState(),
|
|
666
|
-
values,
|
|
667
|
-
errors,
|
|
668
|
-
filledFields,
|
|
669
|
-
isValid: Object.keys(errors).length === 0,
|
|
670
|
-
isValidated,
|
|
671
|
-
autoSubmit: autoSubmitEnabled,
|
|
672
|
-
submitCount
|
|
673
|
-
};
|
|
674
|
-
},
|
|
675
|
-
destroy() {
|
|
676
|
-
if (isDestroyed) {
|
|
677
|
-
return;
|
|
678
|
-
}
|
|
679
|
-
isDestroyed = true;
|
|
680
|
-
for (const listener of listeners) {
|
|
681
|
-
listener.element.removeEventListener(listener.type, listener.handler);
|
|
682
|
-
}
|
|
683
|
-
listeners.length = 0;
|
|
684
|
-
if (autoSubmitTimer) {
|
|
685
|
-
clearTimeout(autoSubmitTimer);
|
|
686
|
-
autoSubmitTimer = null;
|
|
687
|
-
}
|
|
688
|
-
mutationObserver?.disconnect();
|
|
689
|
-
mutationObserver = null;
|
|
690
|
-
watchedFields.clear();
|
|
691
|
-
subscribers.clear();
|
|
692
|
-
submitHandlers.clear();
|
|
693
|
-
clearFieldCache();
|
|
694
|
-
manualErrors = {};
|
|
695
|
-
validationErrors = {};
|
|
696
|
-
}
|
|
964
|
+
onSubmit: createOnSubmit(state2, helpers),
|
|
965
|
+
watch: createWatch(state2, helpers),
|
|
966
|
+
observe: createObserve(state2, helpers),
|
|
967
|
+
unwatch: createUnwatch(state2, helpers),
|
|
968
|
+
subscribe: createSubscribe(state2, helpers),
|
|
969
|
+
prefill: createPrefill(state2, helpers),
|
|
970
|
+
append: createAppend(state2, helpers),
|
|
971
|
+
setErrors: createSetErrors(state2, helpers),
|
|
972
|
+
clearErrors: createClearErrors(state2, helpers),
|
|
973
|
+
setValue: createSetValue(state2, helpers),
|
|
974
|
+
getValue: createGetValue(state2, helpers),
|
|
975
|
+
getField: createGetField(state2, helpers),
|
|
976
|
+
validate: createValidate(state2, helpers),
|
|
977
|
+
revalidate: createRevalidate(state2, helpers),
|
|
978
|
+
reset: createReset(state2, helpers),
|
|
979
|
+
autoSubmit: createAutoSubmit(state2, helpers),
|
|
980
|
+
disableAutoSubmit: createDisableAutoSubmit(state2, helpers),
|
|
981
|
+
getData: createGetData(state2, helpers),
|
|
982
|
+
getState: createGetState(state2, helpers),
|
|
983
|
+
format: createFormat(state2, helpers),
|
|
984
|
+
formatAll: createFormatAll(state2, helpers),
|
|
985
|
+
destroy: createDestroy(state2, helpers)
|
|
697
986
|
};
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
987
|
+
state2.api = api;
|
|
988
|
+
if (state2.element) {
|
|
989
|
+
addListener2(state2.element, "input", handleDelegatedEvent);
|
|
990
|
+
addListener2(state2.element, "change", handleDelegatedEvent);
|
|
991
|
+
addListener2(state2.element, "submit", handleSubmitEvent);
|
|
702
992
|
startMutationObserver();
|
|
703
993
|
}
|
|
704
994
|
if (normalizedOptions.autoSubmit) {
|
|
705
|
-
|
|
706
|
-
|
|
995
|
+
api.autoSubmit(normalizedOptions.autoSubmit);
|
|
996
|
+
}
|
|
997
|
+
if (normalizedOptions.formats) {
|
|
998
|
+
for (const config of Object.values(normalizedOptions.formats)) {
|
|
999
|
+
api.format(config);
|
|
1000
|
+
}
|
|
707
1001
|
}
|
|
708
|
-
if (isValidated) {
|
|
1002
|
+
if (state2.isValidated) {
|
|
709
1003
|
syncVisualState();
|
|
710
1004
|
validateNames();
|
|
711
1005
|
}
|
|
712
1006
|
return api;
|
|
713
1007
|
};
|
|
714
1008
|
|
|
715
|
-
// src/
|
|
716
|
-
var form = (target, options) => createFormController(target, options);
|
|
1009
|
+
// src/api/form.ts
|
|
1010
|
+
var form = (target, options = {}) => createFormController(target, options);
|
|
717
1011
|
// Annotate the CommonJS export names for ESM import in node:
|
|
718
1012
|
0 && (module.exports = {
|
|
719
|
-
createEmptyFormState,
|
|
720
1013
|
createFormController,
|
|
721
1014
|
form,
|
|
722
1015
|
parseFormData,
|