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