@samline/forms 1.0.2 → 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 +88 -186
- package/dist/browser/global.d.ts +152 -0
- package/dist/browser/global.global.js +780 -472
- package/dist/browser/global.global.js.map +1 -1
- package/dist/index.cjs +755 -468
- 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-KIJEFIHP.js +0 -572
- package/dist/chunk-KIJEFIHP.js.map +0 -1
- package/dist/chunk-KKQD25KI.js +0 -11
- package/dist/chunk-KKQD25KI.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 -730
- 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 -760
- 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-C0_1rYlm.d.cts +0 -94
- package/dist/types-C0_1rYlm.d.ts +0 -94
- package/dist/vanilla/index.cjs +0 -701
- 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 -737
- 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,25 +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
|
-
clearErrorsOnSubmit: true
|
|
759
|
+
clearErrorsOnSubmit: true,
|
|
760
|
+
clearManualErrorsOnChange: true
|
|
272
761
|
};
|
|
273
|
-
var mergeErrors = (left, right) => {
|
|
274
|
-
const merged = { ...left };
|
|
275
|
-
for (const [field, messages] of Object.entries(right)) {
|
|
276
|
-
merged[field] = merged[field] ? [...merged[field], ...messages] : [...messages];
|
|
277
|
-
}
|
|
278
|
-
return merged;
|
|
279
|
-
};
|
|
280
|
-
var cloneErrors = (errors) => Object.fromEntries(
|
|
281
|
-
Object.entries(errors).map(([field, messages]) => [field, [...messages]])
|
|
282
|
-
);
|
|
283
762
|
var createFormController = (target, options = {}) => {
|
|
284
763
|
const element = resolveFormElement(target);
|
|
285
764
|
const attributes = { ...DEFAULT_ATTRIBUTES, ...options.attributes };
|
|
@@ -288,47 +767,49 @@ var createFormController = (target, options = {}) => {
|
|
|
288
767
|
...options,
|
|
289
768
|
attributes
|
|
290
769
|
};
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
|
309
791
|
};
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
792
|
+
const notifySubscribers = () => {
|
|
793
|
+
if (!state2.api) return;
|
|
794
|
+
const snapshot = state2.api.getState();
|
|
795
|
+
state2.subscribers.forEach((listener) => listener(snapshot));
|
|
313
796
|
};
|
|
314
|
-
const
|
|
315
|
-
|
|
797
|
+
const addListener2 = (node, type, handler) => {
|
|
798
|
+
node.addEventListener(type, handler);
|
|
799
|
+
state2.listeners.push({ element: node, type, handler });
|
|
316
800
|
};
|
|
801
|
+
const clearFieldCache = () => state2.fieldCache.clear();
|
|
317
802
|
const getFieldsByName = (name) => {
|
|
318
|
-
if (!element)
|
|
319
|
-
|
|
803
|
+
if (!state2.element) return [];
|
|
804
|
+
if (!state2.fieldCache.has(name)) {
|
|
805
|
+
state2.fieldCache.set(name, queryNamedFields(state2.element, name));
|
|
320
806
|
}
|
|
321
|
-
|
|
322
|
-
fieldCache.set(name, queryNamedFields(element, name));
|
|
323
|
-
}
|
|
324
|
-
return fieldCache.get(name) ?? [];
|
|
807
|
+
return state2.fieldCache.get(name) ?? [];
|
|
325
808
|
};
|
|
326
809
|
const getTrackedFieldNames = () => {
|
|
327
|
-
if (!element)
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const names = new Set(Object.keys(validators));
|
|
331
|
-
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)) {
|
|
332
813
|
names.add(field.name);
|
|
333
814
|
}
|
|
334
815
|
return Array.from(names);
|
|
@@ -336,15 +817,13 @@ var createFormController = (target, options = {}) => {
|
|
|
336
817
|
const getValues = () => {
|
|
337
818
|
const values = {};
|
|
338
819
|
for (const name of getTrackedFieldNames()) {
|
|
339
|
-
values[name] =
|
|
820
|
+
values[name] = readFieldValue(getFieldsByName(name));
|
|
340
821
|
}
|
|
341
822
|
return values;
|
|
342
823
|
};
|
|
343
|
-
const getMergedErrors = () => mergeErrors(validationErrors, manualErrors);
|
|
824
|
+
const getMergedErrors = () => mergeErrors(state2.validationErrors, state2.manualErrors);
|
|
344
825
|
const syncVisualState = (names) => {
|
|
345
|
-
if (!element)
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
826
|
+
if (!state2.element) return;
|
|
348
827
|
const targetNames = names ?? getTrackedFieldNames();
|
|
349
828
|
const errors = getMergedErrors();
|
|
350
829
|
for (const name of targetNames) {
|
|
@@ -356,24 +835,23 @@ var createFormController = (target, options = {}) => {
|
|
|
356
835
|
}
|
|
357
836
|
}
|
|
358
837
|
};
|
|
838
|
+
void readFieldValue;
|
|
839
|
+
void writeFieldValue;
|
|
359
840
|
const validateNames = (names) => {
|
|
360
|
-
const targetNames = names ?? Object.keys(validators);
|
|
841
|
+
const targetNames = names ?? Object.keys(state2.validators);
|
|
361
842
|
const values = getValues();
|
|
362
|
-
const nextValidationErrors = names ? cloneErrors(validationErrors) : {};
|
|
843
|
+
const nextValidationErrors = names ? cloneErrors(state2.validationErrors) : {};
|
|
363
844
|
for (const name of targetNames) {
|
|
364
|
-
const rules = validators[name];
|
|
845
|
+
const rules = state2.validators[name];
|
|
365
846
|
if (!rules) {
|
|
366
847
|
delete nextValidationErrors[name];
|
|
367
848
|
continue;
|
|
368
849
|
}
|
|
369
|
-
const
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
} else {
|
|
373
|
-
delete nextValidationErrors[name];
|
|
374
|
-
}
|
|
850
|
+
const messages = validateFieldValue(name, values[name], rules, values);
|
|
851
|
+
if (messages.length > 0) nextValidationErrors[name] = messages;
|
|
852
|
+
else delete nextValidationErrors[name];
|
|
375
853
|
}
|
|
376
|
-
validationErrors = nextValidationErrors;
|
|
854
|
+
state2.validationErrors = nextValidationErrors;
|
|
377
855
|
syncVisualState(names);
|
|
378
856
|
return {
|
|
379
857
|
isValid: Object.keys(getMergedErrors()).length === 0,
|
|
@@ -381,42 +859,49 @@ var createFormController = (target, options = {}) => {
|
|
|
381
859
|
};
|
|
382
860
|
};
|
|
383
861
|
const emitFieldWatchers = (name) => {
|
|
384
|
-
if (!element)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const value = api.getValue(name);
|
|
392
|
-
const state = api.getState();
|
|
393
|
-
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));
|
|
394
869
|
};
|
|
395
870
|
const scheduleAutoSubmit = () => {
|
|
396
|
-
if (!element || !autoSubmitEnabled)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
autoSubmitTimer = setTimeout(() => submitForm(element), autoSubmitDebounce);
|
|
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
|
+
);
|
|
404
878
|
return;
|
|
405
879
|
}
|
|
406
|
-
submitForm(element);
|
|
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
|
|
407
893
|
};
|
|
408
894
|
const handleDelegatedEvent = (event) => {
|
|
409
895
|
const target2 = event.target;
|
|
410
|
-
if (!(target2 instanceof Element) || !isFieldElement(target2))
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
896
|
+
if (!(target2 instanceof Element) || !isFieldElement(target2)) return;
|
|
413
897
|
const name = target2.name;
|
|
414
|
-
if (!name)
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
898
|
+
if (!name) return;
|
|
417
899
|
clearFieldCache();
|
|
900
|
+
if (normalizedOptions.clearManualErrorsOnChange) {
|
|
901
|
+
delete state2.manualErrors[name];
|
|
902
|
+
}
|
|
418
903
|
syncVisualState([name]);
|
|
419
|
-
if (isValidated && validators[name]) {
|
|
904
|
+
if (state2.isValidated && state2.validators[name]) {
|
|
420
905
|
validateNames([name]);
|
|
421
906
|
}
|
|
422
907
|
emitFieldWatchers(name);
|
|
@@ -424,295 +909,97 @@ var createFormController = (target, options = {}) => {
|
|
|
424
909
|
scheduleAutoSubmit();
|
|
425
910
|
};
|
|
426
911
|
const handleSubmitEvent = (event) => {
|
|
427
|
-
if (!element || isDestroyed)
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
manualErrors = {};
|
|
432
|
-
}
|
|
433
|
-
const validation = api.validate();
|
|
434
|
-
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);
|
|
435
916
|
const shouldPrevent = validation.isValid ? handlers.some((handler) => handler.preventDefault) : true;
|
|
436
|
-
if (shouldPrevent)
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
submitCount += 1;
|
|
917
|
+
if (shouldPrevent) event.preventDefault();
|
|
918
|
+
state2.submitCount += 1;
|
|
440
919
|
notifySubscribers();
|
|
441
|
-
if (!validation.isValid)
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
+
);
|
|
447
926
|
};
|
|
448
927
|
const startMutationObserver = () => {
|
|
449
|
-
if (!element || typeof MutationObserver === "undefined")
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
mutationObserver = new MutationObserver(() => {
|
|
928
|
+
if (!state2.element || typeof MutationObserver === "undefined") return;
|
|
929
|
+
state2.mutationObserver = new MutationObserver(() => {
|
|
453
930
|
clearFieldCache();
|
|
454
|
-
if (isValidated) {
|
|
931
|
+
if (state2.isValidated) {
|
|
455
932
|
syncVisualState();
|
|
456
933
|
validateNames();
|
|
457
934
|
}
|
|
458
935
|
notifySubscribers();
|
|
459
936
|
});
|
|
460
|
-
mutationObserver.observe(element, {
|
|
937
|
+
state2.mutationObserver.observe(state2.element, {
|
|
461
938
|
childList: true,
|
|
462
939
|
subtree: true,
|
|
463
940
|
attributes: true,
|
|
464
941
|
attributeFilter: ["name", "type"]
|
|
465
942
|
});
|
|
466
943
|
};
|
|
467
|
-
const isFieldElement = (value) => value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
|
|
468
944
|
const api = {
|
|
469
|
-
element
|
|
470
|
-
|
|
471
|
-
options: normalizedOptions,
|
|
472
|
-
onSubmit(callback, preventDefault = true) {
|
|
473
|
-
submitHandlers.add({ callback, preventDefault });
|
|
474
|
-
return api;
|
|
475
|
-
},
|
|
476
|
-
watch(field, callback) {
|
|
477
|
-
api.observe(field, callback);
|
|
478
|
-
return api;
|
|
479
|
-
},
|
|
480
|
-
observe(field, callback) {
|
|
481
|
-
const callbacks = watchedFields.get(field) ?? /* @__PURE__ */ new Set();
|
|
482
|
-
callbacks.add(callback);
|
|
483
|
-
watchedFields.set(field, callbacks);
|
|
484
|
-
if (element) {
|
|
485
|
-
callback(api.getValue(field), element, api.getState());
|
|
486
|
-
}
|
|
487
|
-
return () => {
|
|
488
|
-
const currentCallbacks = watchedFields.get(field);
|
|
489
|
-
currentCallbacks?.delete(callback);
|
|
490
|
-
if (currentCallbacks && currentCallbacks.size === 0) {
|
|
491
|
-
watchedFields.delete(field);
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
},
|
|
495
|
-
unwatch(field, callback) {
|
|
496
|
-
if (!field) {
|
|
497
|
-
watchedFields.clear();
|
|
498
|
-
return api;
|
|
499
|
-
}
|
|
500
|
-
if (!callback) {
|
|
501
|
-
watchedFields.delete(field);
|
|
502
|
-
return api;
|
|
503
|
-
}
|
|
504
|
-
const callbacks = watchedFields.get(field);
|
|
505
|
-
callbacks?.delete(callback);
|
|
506
|
-
if (callbacks && callbacks.size === 0) {
|
|
507
|
-
watchedFields.delete(field);
|
|
508
|
-
}
|
|
509
|
-
return api;
|
|
510
|
-
},
|
|
511
|
-
subscribe(listener) {
|
|
512
|
-
subscribers.add(listener);
|
|
513
|
-
listener(api.getState());
|
|
514
|
-
return () => {
|
|
515
|
-
subscribers.delete(listener);
|
|
516
|
-
};
|
|
517
|
-
},
|
|
518
|
-
prefill(fieldName) {
|
|
519
|
-
if (!element) {
|
|
520
|
-
return api;
|
|
521
|
-
}
|
|
522
|
-
const queryParams = new URLSearchParams(window.location.search);
|
|
523
|
-
queryParams.forEach((value, key) => {
|
|
524
|
-
if (fieldName && fieldName !== key) {
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
api.setValue(key, value);
|
|
528
|
-
});
|
|
529
|
-
return api;
|
|
530
|
-
},
|
|
531
|
-
append({ tag, content, class: className, atStart = false }) {
|
|
532
|
-
if (!element) {
|
|
533
|
-
return null;
|
|
534
|
-
}
|
|
535
|
-
clearFieldCache();
|
|
536
|
-
if (className) {
|
|
537
|
-
const classSelector = className.trim().split(/\s+/)[0];
|
|
538
|
-
element.querySelector(`.${classSelector}`)?.remove();
|
|
539
|
-
}
|
|
540
|
-
const node = document.createElement(tag);
|
|
541
|
-
if (className) {
|
|
542
|
-
node.className = className;
|
|
543
|
-
}
|
|
544
|
-
node.innerHTML = content;
|
|
545
|
-
if (atStart && element.firstChild) {
|
|
546
|
-
element.insertBefore(node, element.firstChild);
|
|
547
|
-
} else {
|
|
548
|
-
element.appendChild(node);
|
|
549
|
-
}
|
|
550
|
-
return node;
|
|
551
|
-
},
|
|
552
|
-
setErrors(fields) {
|
|
553
|
-
if (Array.isArray(fields)) {
|
|
554
|
-
manualErrors = {
|
|
555
|
-
...manualErrors,
|
|
556
|
-
...Object.fromEntries(fields.map((field) => [field, ["Invalid value."]]))
|
|
557
|
-
};
|
|
558
|
-
} else {
|
|
559
|
-
manualErrors = {
|
|
560
|
-
...manualErrors,
|
|
561
|
-
...cloneErrors(fields)
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
syncVisualState(Array.isArray(fields) ? fields : Object.keys(fields));
|
|
565
|
-
notifySubscribers();
|
|
566
|
-
return api;
|
|
567
|
-
},
|
|
568
|
-
clearErrors(fields) {
|
|
569
|
-
if (!fields) {
|
|
570
|
-
manualErrors = {};
|
|
571
|
-
syncVisualState();
|
|
572
|
-
notifySubscribers();
|
|
573
|
-
return api;
|
|
574
|
-
}
|
|
575
|
-
for (const field of fields) {
|
|
576
|
-
delete manualErrors[field];
|
|
577
|
-
}
|
|
578
|
-
syncVisualState(fields);
|
|
579
|
-
notifySubscribers();
|
|
580
|
-
return api;
|
|
581
|
-
},
|
|
582
|
-
setValue(name, value) {
|
|
583
|
-
const fields = getFieldsByName(name);
|
|
584
|
-
if (fields.length === 0) {
|
|
585
|
-
return api;
|
|
586
|
-
}
|
|
587
|
-
writeFieldValue(fields, value);
|
|
588
|
-
const firstField = fields[0];
|
|
589
|
-
if (!firstField) {
|
|
590
|
-
return api;
|
|
591
|
-
}
|
|
592
|
-
const eventType = firstField instanceof HTMLSelectElement || firstField instanceof HTMLInputElement && (firstField.type === "checkbox" || firstField.type === "radio") ? "change" : "input";
|
|
593
|
-
firstField.dispatchEvent(new Event(eventType, { bubbles: true }));
|
|
594
|
-
return api;
|
|
595
|
-
},
|
|
596
|
-
validate(fields) {
|
|
597
|
-
isValidated = true;
|
|
598
|
-
syncVisualState(fields);
|
|
599
|
-
return validateNames(fields);
|
|
600
|
-
},
|
|
601
|
-
revalidate(fields) {
|
|
602
|
-
return api.validate(fields);
|
|
603
|
-
},
|
|
604
|
-
reset() {
|
|
605
|
-
if (!element) {
|
|
606
|
-
return api;
|
|
607
|
-
}
|
|
608
|
-
element.reset();
|
|
609
|
-
manualErrors = {};
|
|
610
|
-
validationErrors = {};
|
|
611
|
-
clearAttributes(element, [attributes.error, attributes.filled]);
|
|
612
|
-
if (isValidated) {
|
|
613
|
-
syncVisualState();
|
|
614
|
-
}
|
|
615
|
-
notifySubscribers();
|
|
616
|
-
return api;
|
|
617
|
-
},
|
|
618
|
-
autoSubmit(nextOptions = true) {
|
|
619
|
-
autoSubmitEnabled = nextOptions !== false;
|
|
620
|
-
autoSubmitDebounce = typeof nextOptions === "object" && nextOptions ? nextOptions.debounce ?? 0 : 0;
|
|
621
|
-
notifySubscribers();
|
|
622
|
-
return api;
|
|
945
|
+
get element() {
|
|
946
|
+
return state2.element;
|
|
623
947
|
},
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (autoSubmitTimer) {
|
|
627
|
-
clearTimeout(autoSubmitTimer);
|
|
628
|
-
autoSubmitTimer = null;
|
|
629
|
-
}
|
|
630
|
-
notifySubscribers();
|
|
631
|
-
return api;
|
|
948
|
+
get f() {
|
|
949
|
+
return state2.element;
|
|
632
950
|
},
|
|
633
|
-
|
|
634
|
-
return
|
|
951
|
+
get options() {
|
|
952
|
+
return state2.options;
|
|
635
953
|
},
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
return Array.isArray(value) ? value.length > 0 : typeof value === "string" ? value.trim().length > 0 : value !== void 0;
|
|
659
|
-
});
|
|
660
|
-
return {
|
|
661
|
-
...createEmptyFormState(),
|
|
662
|
-
values,
|
|
663
|
-
errors,
|
|
664
|
-
filledFields,
|
|
665
|
-
isValid: Object.keys(errors).length === 0,
|
|
666
|
-
isValidated,
|
|
667
|
-
autoSubmit: autoSubmitEnabled,
|
|
668
|
-
submitCount
|
|
669
|
-
};
|
|
670
|
-
},
|
|
671
|
-
destroy() {
|
|
672
|
-
if (isDestroyed) {
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
isDestroyed = true;
|
|
676
|
-
for (const listener of listeners) {
|
|
677
|
-
listener.element.removeEventListener(listener.type, listener.handler);
|
|
678
|
-
}
|
|
679
|
-
listeners.length = 0;
|
|
680
|
-
if (autoSubmitTimer) {
|
|
681
|
-
clearTimeout(autoSubmitTimer);
|
|
682
|
-
autoSubmitTimer = null;
|
|
683
|
-
}
|
|
684
|
-
mutationObserver?.disconnect();
|
|
685
|
-
mutationObserver = null;
|
|
686
|
-
watchedFields.clear();
|
|
687
|
-
subscribers.clear();
|
|
688
|
-
submitHandlers.clear();
|
|
689
|
-
clearFieldCache();
|
|
690
|
-
manualErrors = {};
|
|
691
|
-
validationErrors = {};
|
|
692
|
-
}
|
|
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)
|
|
693
976
|
};
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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);
|
|
698
982
|
startMutationObserver();
|
|
699
983
|
}
|
|
700
984
|
if (normalizedOptions.autoSubmit) {
|
|
701
|
-
|
|
702
|
-
|
|
985
|
+
api.autoSubmit(normalizedOptions.autoSubmit);
|
|
986
|
+
}
|
|
987
|
+
if (normalizedOptions.formats) {
|
|
988
|
+
for (const config of Object.values(normalizedOptions.formats)) {
|
|
989
|
+
api.format(config);
|
|
990
|
+
}
|
|
703
991
|
}
|
|
704
|
-
if (isValidated) {
|
|
992
|
+
if (state2.isValidated) {
|
|
705
993
|
syncVisualState();
|
|
706
994
|
validateNames();
|
|
707
995
|
}
|
|
708
996
|
return api;
|
|
709
997
|
};
|
|
710
998
|
|
|
711
|
-
// src/
|
|
712
|
-
var form = (target, options) => createFormController(target, options);
|
|
999
|
+
// src/api/form.ts
|
|
1000
|
+
var form = (target, options = {}) => createFormController(target, options);
|
|
713
1001
|
// Annotate the CommonJS export names for ESM import in node:
|
|
714
1002
|
0 && (module.exports = {
|
|
715
|
-
createEmptyFormState,
|
|
716
1003
|
createFormController,
|
|
717
1004
|
form,
|
|
718
1005
|
parseFormData,
|