@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.
Files changed (49) hide show
  1. package/README.md +88 -186
  2. package/dist/browser/global.d.ts +152 -0
  3. package/dist/browser/global.global.js +780 -472
  4. package/dist/browser/global.global.js.map +1 -1
  5. package/dist/index.cjs +755 -468
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +141 -3
  8. package/dist/index.d.ts +141 -3
  9. package/dist/index.js +960 -13
  10. package/dist/index.js.map +1 -1
  11. package/package.json +8 -43
  12. package/dist/chunk-4NEGCRY2.js +0 -125
  13. package/dist/chunk-4NEGCRY2.js.map +0 -1
  14. package/dist/chunk-KIJEFIHP.js +0 -572
  15. package/dist/chunk-KIJEFIHP.js.map +0 -1
  16. package/dist/chunk-KKQD25KI.js +0 -11
  17. package/dist/chunk-KKQD25KI.js.map +0 -1
  18. package/dist/core/index.cjs +0 -154
  19. package/dist/core/index.cjs.map +0 -1
  20. package/dist/core/index.d.cts +0 -11
  21. package/dist/core/index.d.ts +0 -11
  22. package/dist/core/index.js +0 -13
  23. package/dist/core/index.js.map +0 -1
  24. package/dist/react/index.cjs +0 -730
  25. package/dist/react/index.cjs.map +0 -1
  26. package/dist/react/index.d.cts +0 -10
  27. package/dist/react/index.d.ts +0 -10
  28. package/dist/react/index.js +0 -43
  29. package/dist/react/index.js.map +0 -1
  30. package/dist/svelte/index.cjs +0 -760
  31. package/dist/svelte/index.cjs.map +0 -1
  32. package/dist/svelte/index.d.cts +0 -20
  33. package/dist/svelte/index.d.ts +0 -20
  34. package/dist/svelte/index.js +0 -72
  35. package/dist/svelte/index.js.map +0 -1
  36. package/dist/types-C0_1rYlm.d.cts +0 -94
  37. package/dist/types-C0_1rYlm.d.ts +0 -94
  38. package/dist/vanilla/index.cjs +0 -701
  39. package/dist/vanilla/index.cjs.map +0 -1
  40. package/dist/vanilla/index.d.cts +0 -7
  41. package/dist/vanilla/index.d.ts +0 -7
  42. package/dist/vanilla/index.js +0 -12
  43. package/dist/vanilla/index.js.map +0 -1
  44. package/dist/vue/index.cjs +0 -737
  45. package/dist/vue/index.cjs.map +0 -1
  46. package/dist/vue/index.d.cts +0 -13
  47. package/dist/vue/index.d.ts +0 -13
  48. package/dist/vue/index.js +0 -56
  49. package/dist/vue/index.js.map +0 -1
@@ -1,760 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/svelte/index.ts
21
- var svelte_exports = {};
22
- __export(svelte_exports, {
23
- createFormStore: () => createFormStore,
24
- formAction: () => formAction
25
- });
26
- module.exports = __toCommonJS(svelte_exports);
27
-
28
- // src/svelte/form-store.ts
29
- var import_store = require("svelte/store");
30
-
31
- // src/core/serialize.ts
32
- var isEmptyFile = (value) => value instanceof File && value.size === 0 && value.name === "";
33
- var appendValue = (data, key, value) => {
34
- const current = data[key];
35
- if (current === void 0) {
36
- data[key] = value;
37
- return;
38
- }
39
- if (Array.isArray(current)) {
40
- current.push(value);
41
- return;
42
- }
43
- data[key] = [current, value];
44
- };
45
- var parseFormData = (formElement) => {
46
- const rawFormData = new FormData(formElement);
47
- const formData = new FormData();
48
- const data = {};
49
- rawFormData.forEach((value, key) => {
50
- if (isEmptyFile(value)) {
51
- return;
52
- }
53
- formData.append(key, value);
54
- appendValue(data, key, value);
55
- });
56
- return { data, formData };
57
- };
58
-
59
- // src/core/state.ts
60
- var createEmptyFormState = () => ({
61
- values: {},
62
- errors: {},
63
- filledFields: [],
64
- isValid: true,
65
- isValidated: false,
66
- autoSubmit: false,
67
- submitCount: 0
68
- });
69
-
70
- // src/core/validation.ts
71
- var resolveRule = (rule) => {
72
- if (rule === void 0) {
73
- return { value: void 0, message: void 0 };
74
- }
75
- if (typeof rule === "object" && rule !== null && "value" in rule) {
76
- return { value: rule.value, message: rule.message };
77
- }
78
- return { value: rule, message: void 0 };
79
- };
80
- var hasValue = (value) => {
81
- if (Array.isArray(value)) {
82
- return value.length > 0;
83
- }
84
- return typeof value === "string" ? value.trim().length > 0 : value !== void 0;
85
- };
86
- var getValueLength = (value) => {
87
- if (Array.isArray(value)) {
88
- return value.length;
89
- }
90
- if (typeof value === "string") {
91
- return value.length;
92
- }
93
- return 0;
94
- };
95
- var toPatternTarget = (value) => {
96
- if (typeof value === "string") {
97
- return value;
98
- }
99
- if (Array.isArray(value)) {
100
- return value.map((entry) => typeof entry === "string" ? entry : entry.name).join(",");
101
- }
102
- return "";
103
- };
104
- var validateFieldValue = (field, value, rules, values) => {
105
- const errors = [];
106
- const context = { field, value, values };
107
- const required = resolveRule(rules.required);
108
- const minLength = resolveRule(rules.minLength);
109
- const maxLength = resolveRule(rules.maxLength);
110
- const pattern = resolveRule(rules.pattern);
111
- if (required.value && !hasValue(value)) {
112
- errors.push(required.message ?? "This field is required.");
113
- }
114
- if (minLength.value !== void 0 && getValueLength(value) < minLength.value) {
115
- errors.push(minLength.message ?? `Minimum length is ${minLength.value}.`);
116
- }
117
- if (maxLength.value !== void 0 && getValueLength(value) > maxLength.value) {
118
- errors.push(maxLength.message ?? `Maximum length is ${maxLength.value}.`);
119
- }
120
- if (pattern.value && hasValue(value) && !pattern.value.test(toPatternTarget(value))) {
121
- errors.push(pattern.message ?? "Value does not match the required pattern.");
122
- }
123
- const customValidators = rules.validate ? Array.isArray(rules.validate) ? rules.validate : [rules.validate] : [];
124
- for (const validator of customValidators) {
125
- const result = validator(context);
126
- if (typeof result === "string" && result.length > 0) {
127
- errors.push(result);
128
- }
129
- if (result === false) {
130
- errors.push("Validation failed.");
131
- }
132
- }
133
- return errors;
134
- };
135
-
136
- // src/internal/dom.ts
137
- var isFormFieldElement = (value) => value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
138
- var resolveFormElement = (target) => {
139
- if (!target) {
140
- return null;
141
- }
142
- if (target instanceof HTMLFormElement) {
143
- return target;
144
- }
145
- if (typeof target === "string") {
146
- const element = document.getElementById(target);
147
- return element instanceof HTMLFormElement ? element : null;
148
- }
149
- if ("current" in target) {
150
- return target.current instanceof HTMLFormElement ? target.current : null;
151
- }
152
- return null;
153
- };
154
- var getNamedFields = (form) => Array.from(form.querySelectorAll("input[name], select[name], textarea[name]")).filter(
155
- isFormFieldElement
156
- );
157
- var queryNamedFields = (form, name) => getNamedFields(form).filter((field) => field.name === name);
158
- var isFieldFilled = (field) => {
159
- if (field instanceof HTMLInputElement) {
160
- if (field.type === "checkbox" || field.type === "radio") {
161
- return field.checked;
162
- }
163
- if (field.type === "file") {
164
- return Boolean(field.files && field.files.length > 0);
165
- }
166
- return field.value.trim() !== "";
167
- }
168
- return field.value !== "";
169
- };
170
- var applyBooleanAttribute = (field, attribute, enabled) => {
171
- if (enabled) {
172
- field.setAttribute(attribute, "");
173
- return;
174
- }
175
- field.removeAttribute(attribute);
176
- };
177
- var readFieldValue = (fields) => {
178
- if (fields.length === 0) {
179
- return void 0;
180
- }
181
- const firstField = fields[0];
182
- if (!firstField) {
183
- return void 0;
184
- }
185
- if (firstField instanceof HTMLSelectElement || firstField instanceof HTMLTextAreaElement) {
186
- return firstField.value;
187
- }
188
- if (firstField.type === "radio") {
189
- const checked = fields.find(
190
- (field) => field instanceof HTMLInputElement && field.checked
191
- );
192
- return checked?.value ?? "";
193
- }
194
- if (firstField.type === "checkbox") {
195
- const values = fields.filter((field) => field instanceof HTMLInputElement && field.checked).map((field) => field.value);
196
- return values.length > 1 ? values : values[0] ?? "";
197
- }
198
- if (firstField.type === "file") {
199
- return firstField.files ? Array.from(firstField.files) : [];
200
- }
201
- return firstField.value;
202
- };
203
- var writeFieldValue = (fields, value) => {
204
- const normalizedArray = Array.isArray(value) ? value.map((item) => String(item)) : null;
205
- const normalizedValue = value === void 0 || value === null ? "" : String(value);
206
- for (const field of fields) {
207
- if (field instanceof HTMLInputElement) {
208
- if (field.type === "checkbox") {
209
- field.checked = normalizedArray ? normalizedArray.includes(field.value) : normalizedValue === field.value;
210
- continue;
211
- }
212
- if (field.type === "radio") {
213
- field.checked = field.value === normalizedValue;
214
- continue;
215
- }
216
- if (field.type === "file") {
217
- if (Array.isArray(value) && value.length === 0) {
218
- field.value = "";
219
- }
220
- continue;
221
- }
222
- field.value = normalizedValue;
223
- continue;
224
- }
225
- field.value = normalizedValue;
226
- }
227
- };
228
- var clearAttributes = (form, attributes) => {
229
- for (const attribute of attributes) {
230
- form.querySelectorAll(`[${attribute}]`).forEach((element) => {
231
- element.removeAttribute(attribute);
232
- });
233
- }
234
- };
235
- var submitForm = (form) => {
236
- if (typeof form.requestSubmit === "function") {
237
- form.requestSubmit();
238
- return;
239
- }
240
- const submitButton = form.querySelector(
241
- 'button[type="submit"], input[type="submit"]'
242
- );
243
- if (submitButton) {
244
- submitButton.click();
245
- return;
246
- }
247
- form.submit();
248
- };
249
-
250
- // src/internal/controller.ts
251
- var DEFAULT_ATTRIBUTES = {
252
- filled: "css-filled",
253
- error: "css-error"
254
- };
255
- var DEFAULT_OPTIONS = {
256
- autoValidate: true,
257
- clearErrorsOnSubmit: true
258
- };
259
- var mergeErrors = (left, right) => {
260
- const merged = { ...left };
261
- for (const [field, messages] of Object.entries(right)) {
262
- merged[field] = merged[field] ? [...merged[field], ...messages] : [...messages];
263
- }
264
- return merged;
265
- };
266
- var cloneErrors = (errors) => Object.fromEntries(
267
- Object.entries(errors).map(([field, messages]) => [field, [...messages]])
268
- );
269
- var createFormController = (target, options = {}) => {
270
- const element = resolveFormElement(target);
271
- const attributes = { ...DEFAULT_ATTRIBUTES, ...options.attributes };
272
- const normalizedOptions = {
273
- ...DEFAULT_OPTIONS,
274
- ...options,
275
- attributes
276
- };
277
- const validators = normalizedOptions.validators ?? {};
278
- const watchedFields = /* @__PURE__ */ new Map();
279
- const listeners = [];
280
- const subscribers = /* @__PURE__ */ new Set();
281
- const submitHandlers = /* @__PURE__ */ new Set();
282
- const fieldCache = /* @__PURE__ */ new Map();
283
- let manualErrors = {};
284
- let validationErrors = {};
285
- let isValidated = Boolean(normalizedOptions.autoValidate);
286
- let autoSubmitEnabled = false;
287
- let autoSubmitDebounce = 0;
288
- let submitCount = 0;
289
- let autoSubmitTimer = null;
290
- let mutationObserver = null;
291
- let isDestroyed = false;
292
- const notifySubscribers = () => {
293
- const state = api.getState();
294
- subscribers.forEach((listener) => listener(state));
295
- };
296
- const addListener = (listenerTarget, type, handler) => {
297
- listenerTarget.addEventListener(type, handler);
298
- listeners.push({ element: listenerTarget, type, handler });
299
- };
300
- const clearFieldCache = () => {
301
- fieldCache.clear();
302
- };
303
- const getFieldsByName = (name) => {
304
- if (!element) {
305
- return [];
306
- }
307
- if (!fieldCache.has(name)) {
308
- fieldCache.set(name, queryNamedFields(element, name));
309
- }
310
- return fieldCache.get(name) ?? [];
311
- };
312
- const getTrackedFieldNames = () => {
313
- if (!element) {
314
- return Object.keys(validators);
315
- }
316
- const names = new Set(Object.keys(validators));
317
- for (const field of getNamedFields(element)) {
318
- names.add(field.name);
319
- }
320
- return Array.from(names);
321
- };
322
- const getValues = () => {
323
- const values = {};
324
- for (const name of getTrackedFieldNames()) {
325
- values[name] = api.getValue(name);
326
- }
327
- return values;
328
- };
329
- const getMergedErrors = () => mergeErrors(validationErrors, manualErrors);
330
- const syncVisualState = (names) => {
331
- if (!element) {
332
- return;
333
- }
334
- const targetNames = names ?? getTrackedFieldNames();
335
- const errors = getMergedErrors();
336
- for (const name of targetNames) {
337
- const fields = getFieldsByName(name);
338
- const hasError = Boolean(errors[name]?.length);
339
- for (const field of fields) {
340
- applyBooleanAttribute(field, attributes.filled, isFieldFilled(field));
341
- applyBooleanAttribute(field, attributes.error, hasError);
342
- }
343
- }
344
- };
345
- const validateNames = (names) => {
346
- const targetNames = names ?? Object.keys(validators);
347
- const values = getValues();
348
- const nextValidationErrors = names ? cloneErrors(validationErrors) : {};
349
- for (const name of targetNames) {
350
- const rules = validators[name];
351
- if (!rules) {
352
- delete nextValidationErrors[name];
353
- continue;
354
- }
355
- const errors = validateFieldValue(name, values[name], rules, values);
356
- if (errors.length > 0) {
357
- nextValidationErrors[name] = errors;
358
- } else {
359
- delete nextValidationErrors[name];
360
- }
361
- }
362
- validationErrors = nextValidationErrors;
363
- syncVisualState(names);
364
- return {
365
- isValid: Object.keys(getMergedErrors()).length === 0,
366
- errors: cloneErrors(getMergedErrors())
367
- };
368
- };
369
- const emitFieldWatchers = (name) => {
370
- if (!element) {
371
- return;
372
- }
373
- const callbacks = watchedFields.get(name);
374
- if (!callbacks || callbacks.size === 0) {
375
- return;
376
- }
377
- const value = api.getValue(name);
378
- const state = api.getState();
379
- callbacks.forEach((callback) => callback(value, element, state));
380
- };
381
- const scheduleAutoSubmit = () => {
382
- if (!element || !autoSubmitEnabled) {
383
- return;
384
- }
385
- if (autoSubmitTimer) {
386
- clearTimeout(autoSubmitTimer);
387
- }
388
- if (autoSubmitDebounce > 0) {
389
- autoSubmitTimer = setTimeout(() => submitForm(element), autoSubmitDebounce);
390
- return;
391
- }
392
- submitForm(element);
393
- };
394
- const handleDelegatedEvent = (event) => {
395
- const target2 = event.target;
396
- if (!(target2 instanceof Element) || !isFieldElement(target2)) {
397
- return;
398
- }
399
- const name = target2.name;
400
- if (!name) {
401
- return;
402
- }
403
- clearFieldCache();
404
- syncVisualState([name]);
405
- if (isValidated && validators[name]) {
406
- validateNames([name]);
407
- }
408
- emitFieldWatchers(name);
409
- notifySubscribers();
410
- scheduleAutoSubmit();
411
- };
412
- const handleSubmitEvent = (event) => {
413
- if (!element || isDestroyed) {
414
- return;
415
- }
416
- if (normalizedOptions.clearErrorsOnSubmit) {
417
- manualErrors = {};
418
- }
419
- const validation = api.validate();
420
- const handlers = Array.from(submitHandlers);
421
- const shouldPrevent = validation.isValid ? handlers.some((handler) => handler.preventDefault) : true;
422
- if (shouldPrevent) {
423
- event.preventDefault();
424
- }
425
- submitCount += 1;
426
- notifySubscribers();
427
- if (!validation.isValid) {
428
- return;
429
- }
430
- const { data, formData } = api.getData();
431
- const state = api.getState();
432
- handlers.forEach((handler) => handler.callback(element, data, formData, state));
433
- };
434
- const startMutationObserver = () => {
435
- if (!element || typeof MutationObserver === "undefined") {
436
- return;
437
- }
438
- mutationObserver = new MutationObserver(() => {
439
- clearFieldCache();
440
- if (isValidated) {
441
- syncVisualState();
442
- validateNames();
443
- }
444
- notifySubscribers();
445
- });
446
- mutationObserver.observe(element, {
447
- childList: true,
448
- subtree: true,
449
- attributes: true,
450
- attributeFilter: ["name", "type"]
451
- });
452
- };
453
- const isFieldElement = (value) => value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
454
- const api = {
455
- element,
456
- f: element,
457
- options: normalizedOptions,
458
- onSubmit(callback, preventDefault = true) {
459
- submitHandlers.add({ callback, preventDefault });
460
- return api;
461
- },
462
- watch(field, callback) {
463
- api.observe(field, callback);
464
- return api;
465
- },
466
- observe(field, callback) {
467
- const callbacks = watchedFields.get(field) ?? /* @__PURE__ */ new Set();
468
- callbacks.add(callback);
469
- watchedFields.set(field, callbacks);
470
- if (element) {
471
- callback(api.getValue(field), element, api.getState());
472
- }
473
- return () => {
474
- const currentCallbacks = watchedFields.get(field);
475
- currentCallbacks?.delete(callback);
476
- if (currentCallbacks && currentCallbacks.size === 0) {
477
- watchedFields.delete(field);
478
- }
479
- };
480
- },
481
- unwatch(field, callback) {
482
- if (!field) {
483
- watchedFields.clear();
484
- return api;
485
- }
486
- if (!callback) {
487
- watchedFields.delete(field);
488
- return api;
489
- }
490
- const callbacks = watchedFields.get(field);
491
- callbacks?.delete(callback);
492
- if (callbacks && callbacks.size === 0) {
493
- watchedFields.delete(field);
494
- }
495
- return api;
496
- },
497
- subscribe(listener) {
498
- subscribers.add(listener);
499
- listener(api.getState());
500
- return () => {
501
- subscribers.delete(listener);
502
- };
503
- },
504
- prefill(fieldName) {
505
- if (!element) {
506
- return api;
507
- }
508
- const queryParams = new URLSearchParams(window.location.search);
509
- queryParams.forEach((value, key) => {
510
- if (fieldName && fieldName !== key) {
511
- return;
512
- }
513
- api.setValue(key, value);
514
- });
515
- return api;
516
- },
517
- append({ tag, content, class: className, atStart = false }) {
518
- if (!element) {
519
- return null;
520
- }
521
- clearFieldCache();
522
- if (className) {
523
- const classSelector = className.trim().split(/\s+/)[0];
524
- element.querySelector(`.${classSelector}`)?.remove();
525
- }
526
- const node = document.createElement(tag);
527
- if (className) {
528
- node.className = className;
529
- }
530
- node.innerHTML = content;
531
- if (atStart && element.firstChild) {
532
- element.insertBefore(node, element.firstChild);
533
- } else {
534
- element.appendChild(node);
535
- }
536
- return node;
537
- },
538
- setErrors(fields) {
539
- if (Array.isArray(fields)) {
540
- manualErrors = {
541
- ...manualErrors,
542
- ...Object.fromEntries(fields.map((field) => [field, ["Invalid value."]]))
543
- };
544
- } else {
545
- manualErrors = {
546
- ...manualErrors,
547
- ...cloneErrors(fields)
548
- };
549
- }
550
- syncVisualState(Array.isArray(fields) ? fields : Object.keys(fields));
551
- notifySubscribers();
552
- return api;
553
- },
554
- clearErrors(fields) {
555
- if (!fields) {
556
- manualErrors = {};
557
- syncVisualState();
558
- notifySubscribers();
559
- return api;
560
- }
561
- for (const field of fields) {
562
- delete manualErrors[field];
563
- }
564
- syncVisualState(fields);
565
- notifySubscribers();
566
- return api;
567
- },
568
- setValue(name, value) {
569
- const fields = getFieldsByName(name);
570
- if (fields.length === 0) {
571
- return api;
572
- }
573
- writeFieldValue(fields, value);
574
- const firstField = fields[0];
575
- if (!firstField) {
576
- return api;
577
- }
578
- const eventType = firstField instanceof HTMLSelectElement || firstField instanceof HTMLInputElement && (firstField.type === "checkbox" || firstField.type === "radio") ? "change" : "input";
579
- firstField.dispatchEvent(new Event(eventType, { bubbles: true }));
580
- return api;
581
- },
582
- validate(fields) {
583
- isValidated = true;
584
- syncVisualState(fields);
585
- return validateNames(fields);
586
- },
587
- revalidate(fields) {
588
- return api.validate(fields);
589
- },
590
- reset() {
591
- if (!element) {
592
- return api;
593
- }
594
- element.reset();
595
- manualErrors = {};
596
- validationErrors = {};
597
- clearAttributes(element, [attributes.error, attributes.filled]);
598
- if (isValidated) {
599
- syncVisualState();
600
- }
601
- notifySubscribers();
602
- return api;
603
- },
604
- autoSubmit(nextOptions = true) {
605
- autoSubmitEnabled = nextOptions !== false;
606
- autoSubmitDebounce = typeof nextOptions === "object" && nextOptions ? nextOptions.debounce ?? 0 : 0;
607
- notifySubscribers();
608
- return api;
609
- },
610
- disableAutoSubmit() {
611
- autoSubmitEnabled = false;
612
- if (autoSubmitTimer) {
613
- clearTimeout(autoSubmitTimer);
614
- autoSubmitTimer = null;
615
- }
616
- notifySubscribers();
617
- return api;
618
- },
619
- getValue(name) {
620
- return readFieldValue(getFieldsByName(name));
621
- },
622
- getField(name) {
623
- const fields = getFieldsByName(name);
624
- if (fields.length === 0) {
625
- return null;
626
- }
627
- const [firstField] = fields;
628
- if (!firstField) {
629
- return null;
630
- }
631
- return fields.length === 1 ? firstField : fields;
632
- },
633
- getData() {
634
- if (!element) {
635
- return { data: {}, formData: new FormData() };
636
- }
637
- return parseFormData(element);
638
- },
639
- getState() {
640
- const values = getValues();
641
- const errors = cloneErrors(getMergedErrors());
642
- const filledFields = getTrackedFieldNames().filter((name) => {
643
- const value = values[name];
644
- return Array.isArray(value) ? value.length > 0 : typeof value === "string" ? value.trim().length > 0 : value !== void 0;
645
- });
646
- return {
647
- ...createEmptyFormState(),
648
- values,
649
- errors,
650
- filledFields,
651
- isValid: Object.keys(errors).length === 0,
652
- isValidated,
653
- autoSubmit: autoSubmitEnabled,
654
- submitCount
655
- };
656
- },
657
- destroy() {
658
- if (isDestroyed) {
659
- return;
660
- }
661
- isDestroyed = true;
662
- for (const listener of listeners) {
663
- listener.element.removeEventListener(listener.type, listener.handler);
664
- }
665
- listeners.length = 0;
666
- if (autoSubmitTimer) {
667
- clearTimeout(autoSubmitTimer);
668
- autoSubmitTimer = null;
669
- }
670
- mutationObserver?.disconnect();
671
- mutationObserver = null;
672
- watchedFields.clear();
673
- subscribers.clear();
674
- submitHandlers.clear();
675
- clearFieldCache();
676
- manualErrors = {};
677
- validationErrors = {};
678
- }
679
- };
680
- if (element) {
681
- addListener(element, "input", handleDelegatedEvent);
682
- addListener(element, "change", handleDelegatedEvent);
683
- addListener(element, "submit", handleSubmitEvent);
684
- startMutationObserver();
685
- }
686
- if (normalizedOptions.autoSubmit) {
687
- const autoSubmitOption = normalizedOptions.autoSubmit;
688
- api.autoSubmit(autoSubmitOption);
689
- }
690
- if (isValidated) {
691
- syncVisualState();
692
- validateNames();
693
- }
694
- return api;
695
- };
696
-
697
- // src/svelte/form-store.ts
698
- var createFormStore = (target, options = {}) => {
699
- const state = (0, import_store.writable)(createEmptyFormState());
700
- const ready = (0, import_store.writable)(false);
701
- let controller = null;
702
- let unsubscribe = null;
703
- const mount = () => {
704
- if (controller) {
705
- return;
706
- }
707
- const element = resolveFormElement(target);
708
- if (!element) {
709
- return;
710
- }
711
- controller = createFormController(element, options);
712
- state.set(controller.getState());
713
- ready.set(true);
714
- unsubscribe = controller.subscribe((nextState) => {
715
- state.set(nextState);
716
- });
717
- };
718
- const destroy = () => {
719
- unsubscribe?.();
720
- unsubscribe = null;
721
- controller?.destroy();
722
- controller = null;
723
- ready.set(false);
724
- state.set(createEmptyFormState());
725
- };
726
- mount();
727
- return {
728
- state: { subscribe: state.subscribe },
729
- ready: { subscribe: ready.subscribe },
730
- getController: () => controller,
731
- mount,
732
- destroy
733
- };
734
- };
735
- var formAction = (node, options = {}) => {
736
- let controller = createFormController(node, options);
737
- let unsubscribe = controller.subscribe((state) => {
738
- options.onStateChange?.(state);
739
- });
740
- return {
741
- update(nextOptions) {
742
- unsubscribe();
743
- controller.destroy();
744
- controller = createFormController(node, nextOptions);
745
- unsubscribe = controller.subscribe((state) => {
746
- nextOptions.onStateChange?.(state);
747
- });
748
- },
749
- destroy() {
750
- unsubscribe();
751
- controller.destroy();
752
- }
753
- };
754
- };
755
- // Annotate the CommonJS export names for ESM import in node:
756
- 0 && (module.exports = {
757
- createFormStore,
758
- formAction
759
- });
760
- //# sourceMappingURL=index.cjs.map