@coherent.js/forms 1.0.0-beta.6 → 1.0.0-beta.7
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/dist/advanced-validation.js +523 -0
- package/dist/advanced-validation.js.map +7 -0
- package/dist/form-builder.js +492 -0
- package/dist/form-builder.js.map +7 -0
- package/dist/form-hydration.js +565 -0
- package/dist/form-hydration.js.map +7 -0
- package/dist/forms.js +432 -0
- package/dist/forms.js.map +7 -0
- package/dist/index.js.map +7 -0
- package/dist/validation.js +186 -0
- package/dist/validation.js.map +7 -0
- package/dist/validators.js +365 -0
- package/dist/validators.js.map +7 -0
- package/package.json +14 -4
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
// src/validators.js
|
|
2
|
+
var validators = {
|
|
3
|
+
required: (value, options = {}) => {
|
|
4
|
+
if (value === null || value === void 0 || value === "") {
|
|
5
|
+
return options.message || validators.required.message || "This field is required";
|
|
6
|
+
}
|
|
7
|
+
return null;
|
|
8
|
+
},
|
|
9
|
+
email: (value) => {
|
|
10
|
+
if (!value) return null;
|
|
11
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
12
|
+
if (!emailRegex.test(value)) {
|
|
13
|
+
return "Please enter a valid email address";
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
},
|
|
17
|
+
minLength: (value, options = {}) => {
|
|
18
|
+
if (!value) return null;
|
|
19
|
+
const min = options.min || 0;
|
|
20
|
+
if (value.length < min) {
|
|
21
|
+
return options.message || `Must be at least ${min} characters`;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
},
|
|
25
|
+
maxLength: (value, options = {}) => {
|
|
26
|
+
if (!value) return null;
|
|
27
|
+
const max = options.max || Infinity;
|
|
28
|
+
if (value.length > max) {
|
|
29
|
+
return options.message || `Must be no more than ${max} characters`;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
33
|
+
min: (value, options = {}) => {
|
|
34
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
35
|
+
const num = Number(value);
|
|
36
|
+
const minValue = options.min || 0;
|
|
37
|
+
if (isNaN(num) || num < minValue) {
|
|
38
|
+
return options.message || `Must be at least ${minValue}`;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
},
|
|
42
|
+
max: (value, options = {}) => {
|
|
43
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
44
|
+
const num = Number(value);
|
|
45
|
+
const maxValue = options.max || Infinity;
|
|
46
|
+
if (isNaN(num) || num > maxValue) {
|
|
47
|
+
return options.message || `Must be no more than ${maxValue}`;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
pattern: (value, options = {}) => {
|
|
52
|
+
if (!value) return null;
|
|
53
|
+
const regex = options.pattern || options.regex;
|
|
54
|
+
if (regex && !regex.test(value)) {
|
|
55
|
+
return options.message || "Invalid format";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
59
|
+
url: (value) => {
|
|
60
|
+
if (!value) return null;
|
|
61
|
+
try {
|
|
62
|
+
new URL(value);
|
|
63
|
+
return null;
|
|
64
|
+
} catch {
|
|
65
|
+
return "Please enter a valid URL";
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
number: (value) => {
|
|
69
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
70
|
+
if (isNaN(Number(value))) {
|
|
71
|
+
return "Must be a valid number";
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
},
|
|
75
|
+
integer: (value) => {
|
|
76
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
77
|
+
const num = Number(value);
|
|
78
|
+
if (isNaN(num) || !Number.isInteger(num)) {
|
|
79
|
+
return "Must be a whole number";
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
},
|
|
83
|
+
phone: (value) => {
|
|
84
|
+
if (!value) return null;
|
|
85
|
+
const phoneRegex = /^[\d\s\-\+\(\)]+$/;
|
|
86
|
+
if (!phoneRegex.test(value) || value.replace(/\D/g, "").length < 10) {
|
|
87
|
+
return "Please enter a valid phone number";
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
},
|
|
91
|
+
date: (value) => {
|
|
92
|
+
if (!value) return null;
|
|
93
|
+
const date = new Date(value);
|
|
94
|
+
if (isNaN(date.getTime())) {
|
|
95
|
+
return "Please enter a valid date";
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
},
|
|
99
|
+
match: (value, options = {}, translator, allValues = {}) => {
|
|
100
|
+
if (!value) return null;
|
|
101
|
+
const fieldName = options.field || options.fieldName;
|
|
102
|
+
if (value !== allValues[fieldName]) {
|
|
103
|
+
return options.message || `Must match ${fieldName}`;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
},
|
|
107
|
+
custom: (value, options = {}, translator, allValues) => {
|
|
108
|
+
const validatorFn = options.validator || options.fn;
|
|
109
|
+
if (!validatorFn) return null;
|
|
110
|
+
const isValid = validatorFn(value, allValues);
|
|
111
|
+
return isValid ? null : options.message || "Validation failed";
|
|
112
|
+
},
|
|
113
|
+
fileType: (value, options = {}) => {
|
|
114
|
+
if (!value) return null;
|
|
115
|
+
const allowedTypes = options.accept || options.types || [];
|
|
116
|
+
if (value.type !== void 0) {
|
|
117
|
+
const fileType = value.type;
|
|
118
|
+
const fileExt = value.name ? value.name.split(".").pop().toLowerCase() : "";
|
|
119
|
+
const isValid = allowedTypes.some((type) => {
|
|
120
|
+
if (type.startsWith(".")) {
|
|
121
|
+
return fileExt === type.slice(1).toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
if (type.includes("/")) {
|
|
124
|
+
if (type.endsWith("/*")) {
|
|
125
|
+
return fileType.startsWith(type.replace("/*", "/"));
|
|
126
|
+
}
|
|
127
|
+
return fileType === type;
|
|
128
|
+
}
|
|
129
|
+
return fileExt === type.toLowerCase();
|
|
130
|
+
});
|
|
131
|
+
if (!isValid) {
|
|
132
|
+
return options.message || `File type must be one of: ${allowedTypes.join(", ")}`;
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
},
|
|
138
|
+
fileSize: (value, options = {}) => {
|
|
139
|
+
if (!value) return null;
|
|
140
|
+
const maxSize = options.maxSize || Infinity;
|
|
141
|
+
if (value.size !== void 0) {
|
|
142
|
+
if (value.size > maxSize) {
|
|
143
|
+
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(2);
|
|
144
|
+
return options.message || `File size must be less than ${maxSizeMB}MB`;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
},
|
|
150
|
+
fileExtension: (value, options = {}) => {
|
|
151
|
+
if (!value) return null;
|
|
152
|
+
const allowedExtensions = options.extensions || [];
|
|
153
|
+
const fileName = value.name || value;
|
|
154
|
+
const ext = `.${fileName.split(".").pop().toLowerCase()}`;
|
|
155
|
+
const isValid = allowedExtensions.some((allowed) => {
|
|
156
|
+
return ext === allowed.toLowerCase();
|
|
157
|
+
});
|
|
158
|
+
if (!isValid) {
|
|
159
|
+
return options.message || `File extension must be one of: ${allowedExtensions.join(", ")}`;
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
},
|
|
163
|
+
alpha: (value) => {
|
|
164
|
+
if (!value) return null;
|
|
165
|
+
const alphaRegex = /^[a-zA-Z]+$/;
|
|
166
|
+
if (!alphaRegex.test(value)) {
|
|
167
|
+
return "Must contain only letters";
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
},
|
|
171
|
+
alphanumeric: (value) => {
|
|
172
|
+
if (!value) return null;
|
|
173
|
+
const alphanumericRegex = /^[a-zA-Z0-9]+$/;
|
|
174
|
+
if (!alphanumericRegex.test(value)) {
|
|
175
|
+
return "Must contain only letters and numbers";
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
},
|
|
179
|
+
uppercase: (value) => {
|
|
180
|
+
if (!value) return null;
|
|
181
|
+
if (value !== value.toUpperCase()) {
|
|
182
|
+
return "Must be uppercase";
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
},
|
|
186
|
+
// Get a registered validator
|
|
187
|
+
get: (name) => {
|
|
188
|
+
return validators[name];
|
|
189
|
+
},
|
|
190
|
+
// Compose multiple validators
|
|
191
|
+
compose: (validatorList) => {
|
|
192
|
+
return (value, options, translator, allValues) => {
|
|
193
|
+
for (const validator of validatorList) {
|
|
194
|
+
const error = typeof validator === "function" ? validator(value, options, translator, allValues) : null;
|
|
195
|
+
if (error) {
|
|
196
|
+
return error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
// Debounce async validator
|
|
203
|
+
debounce: (validator, delay = 300) => {
|
|
204
|
+
let timeoutId;
|
|
205
|
+
return (value) => {
|
|
206
|
+
return new Promise((resolve) => {
|
|
207
|
+
clearTimeout(timeoutId);
|
|
208
|
+
timeoutId = setTimeout(async () => {
|
|
209
|
+
const result = await validator(value);
|
|
210
|
+
resolve(result);
|
|
211
|
+
}, delay);
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
// Cancellable async validator
|
|
216
|
+
cancellable: (validator) => {
|
|
217
|
+
let abortController;
|
|
218
|
+
const wrapped = async (value) => {
|
|
219
|
+
if (abortController) {
|
|
220
|
+
abortController.abort();
|
|
221
|
+
}
|
|
222
|
+
abortController = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
223
|
+
try {
|
|
224
|
+
return await validator(value, abortController ? abortController.signal : null);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (error.name === "AbortError") {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
wrapped.cancel = () => {
|
|
233
|
+
if (abortController) {
|
|
234
|
+
abortController.abort();
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
return wrapped;
|
|
238
|
+
},
|
|
239
|
+
// Conditional validator
|
|
240
|
+
when: (condition, validator) => {
|
|
241
|
+
return (value, options = {}, translator, allValues = {}) => {
|
|
242
|
+
const context = options.min !== void 0 || options.max !== void 0 ? allValues : options;
|
|
243
|
+
const shouldValidate = typeof condition === "function" ? condition(value, context) : condition;
|
|
244
|
+
if (!shouldValidate) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
return typeof validator === "function" ? validator(value, options, translator, allValues) : null;
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
// Validator chain builder
|
|
251
|
+
chain: (options = {}) => {
|
|
252
|
+
const validatorList = [];
|
|
253
|
+
const stopOnFirstError = options.stopOnFirstError !== false;
|
|
254
|
+
const chain = {
|
|
255
|
+
required: (opts) => {
|
|
256
|
+
validatorList.push((v, o, t, a) => validators.required(v, opts || o, t, a));
|
|
257
|
+
return chain;
|
|
258
|
+
},
|
|
259
|
+
email: (opts) => {
|
|
260
|
+
validatorList.push((v, o, t, a) => validators.email(v, opts || o, t, a));
|
|
261
|
+
return chain;
|
|
262
|
+
},
|
|
263
|
+
minLength: (opts) => {
|
|
264
|
+
validatorList.push((v, o, t, a) => validators.minLength(v, opts || o, t, a));
|
|
265
|
+
return chain;
|
|
266
|
+
},
|
|
267
|
+
maxLength: (opts) => {
|
|
268
|
+
validatorList.push((v, o, t, a) => validators.maxLength(v, opts || o, t, a));
|
|
269
|
+
return chain;
|
|
270
|
+
},
|
|
271
|
+
custom: (fn, message) => {
|
|
272
|
+
validatorList.push((v, o, t, a) => {
|
|
273
|
+
const result = fn(v, a);
|
|
274
|
+
return result === null || result === true || result === void 0 ? null : message || result;
|
|
275
|
+
});
|
|
276
|
+
return chain;
|
|
277
|
+
},
|
|
278
|
+
validate: (value, opts, translator, allValues) => {
|
|
279
|
+
if (stopOnFirstError) {
|
|
280
|
+
for (const validator of validatorList) {
|
|
281
|
+
const error = validator(value, opts, translator, allValues);
|
|
282
|
+
if (error) {
|
|
283
|
+
return error;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return null;
|
|
287
|
+
} else {
|
|
288
|
+
const errors = [];
|
|
289
|
+
for (const validator of validatorList) {
|
|
290
|
+
const error = validator(value, opts, translator, allValues);
|
|
291
|
+
if (error) {
|
|
292
|
+
errors.push(error);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return errors.length > 0 ? errors : null;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
return chain;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// src/form-hydration.js
|
|
304
|
+
function hydrateForm(formSelector, options = {}) {
|
|
305
|
+
if (typeof document === "undefined") {
|
|
306
|
+
console.warn("hydrateForm can only run in browser environment");
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const form = typeof formSelector === "string" ? document.querySelector(formSelector) : formSelector;
|
|
310
|
+
if (!form) {
|
|
311
|
+
console.warn(`Form not found: ${formSelector}`);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const opts = {
|
|
315
|
+
validateOnBlur: true,
|
|
316
|
+
validateOnChange: false,
|
|
317
|
+
validateOnSubmit: true,
|
|
318
|
+
showErrorsOnTouch: true,
|
|
319
|
+
debounce: 300,
|
|
320
|
+
...options
|
|
321
|
+
};
|
|
322
|
+
const state = {
|
|
323
|
+
values: {},
|
|
324
|
+
errors: {},
|
|
325
|
+
touched: {},
|
|
326
|
+
isSubmitting: false,
|
|
327
|
+
fields: /* @__PURE__ */ new Map()
|
|
328
|
+
};
|
|
329
|
+
const debounceTimers = /* @__PURE__ */ new Map();
|
|
330
|
+
function parseValidators(validatorString) {
|
|
331
|
+
if (!validatorString) return [];
|
|
332
|
+
return validatorString.split(",").map((v) => {
|
|
333
|
+
const trimmed = v.trim();
|
|
334
|
+
const [name, ...params] = trimmed.split(":");
|
|
335
|
+
if (validators[name]) {
|
|
336
|
+
return params.length > 0 ? validators[name](...params.map((p) => isNaN(p) ? p : Number(p))) : validators[name];
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}).filter(Boolean);
|
|
340
|
+
}
|
|
341
|
+
function discoverFields() {
|
|
342
|
+
const inputs = form.querySelectorAll("[name]");
|
|
343
|
+
inputs.forEach((input) => {
|
|
344
|
+
const name = input.getAttribute("name");
|
|
345
|
+
const field = {
|
|
346
|
+
name,
|
|
347
|
+
element: input,
|
|
348
|
+
type: input.getAttribute("type") || "text",
|
|
349
|
+
required: input.hasAttribute("required") || input.dataset.required === "true",
|
|
350
|
+
validators: parseValidators(input.dataset.validators),
|
|
351
|
+
errorElement: null
|
|
352
|
+
};
|
|
353
|
+
const errorId = `${name}-error`;
|
|
354
|
+
field.errorElement = document.getElementById(errorId) || createErrorElement(name, input);
|
|
355
|
+
state.fields.set(name, field);
|
|
356
|
+
state.values[name] = getFieldValue(input);
|
|
357
|
+
state.touched[name] = false;
|
|
358
|
+
state.errors[name] = null;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function createErrorElement(name, inputElement) {
|
|
362
|
+
const errorDiv = document.createElement("div");
|
|
363
|
+
errorDiv.id = `${name}-error`;
|
|
364
|
+
errorDiv.className = "error-message";
|
|
365
|
+
errorDiv.setAttribute("role", "alert");
|
|
366
|
+
errorDiv.style.display = "none";
|
|
367
|
+
const fieldWrapper = inputElement.closest(".form-field") || inputElement.parentElement;
|
|
368
|
+
fieldWrapper.appendChild(errorDiv);
|
|
369
|
+
return errorDiv;
|
|
370
|
+
}
|
|
371
|
+
function getFieldValue(input) {
|
|
372
|
+
if (input.type === "checkbox") {
|
|
373
|
+
return input.checked;
|
|
374
|
+
} else if (input.type === "radio") {
|
|
375
|
+
const checked = form.querySelector(`[name="${input.name}"]:checked`);
|
|
376
|
+
return checked ? checked.value : null;
|
|
377
|
+
} else {
|
|
378
|
+
return input.value;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function setFieldValue(name, value) {
|
|
382
|
+
const field = state.fields.get(name);
|
|
383
|
+
if (!field) return;
|
|
384
|
+
const { element } = field;
|
|
385
|
+
if (element.type === "checkbox") {
|
|
386
|
+
element.checked = Boolean(value);
|
|
387
|
+
} else if (element.type === "radio") {
|
|
388
|
+
const radio = form.querySelector(`[name="${name}"][value="${value}"]`);
|
|
389
|
+
if (radio) radio.checked = true;
|
|
390
|
+
} else {
|
|
391
|
+
element.value = value;
|
|
392
|
+
}
|
|
393
|
+
state.values[name] = value;
|
|
394
|
+
}
|
|
395
|
+
function validateField(name) {
|
|
396
|
+
const field = state.fields.get(name);
|
|
397
|
+
if (!field) return true;
|
|
398
|
+
const value = state.values[name];
|
|
399
|
+
let error = null;
|
|
400
|
+
if (field.required && (value === null || value === void 0 || value === "")) {
|
|
401
|
+
error = "This field is required";
|
|
402
|
+
}
|
|
403
|
+
if (!error && field.validators.length > 0) {
|
|
404
|
+
for (const validator of field.validators) {
|
|
405
|
+
const result = validator.validate ? validator.validate(value, state.values) : validator(value, state.values);
|
|
406
|
+
if (result !== true && result !== void 0 && result !== null) {
|
|
407
|
+
error = validator.message || result || "Validation failed";
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
state.errors[name] = error;
|
|
413
|
+
displayError(name, error);
|
|
414
|
+
return !error;
|
|
415
|
+
}
|
|
416
|
+
function displayError(name, error) {
|
|
417
|
+
const field = state.fields.get(name);
|
|
418
|
+
if (!field) return;
|
|
419
|
+
const { element, errorElement } = field;
|
|
420
|
+
if (error && state.touched[name] && opts.showErrorsOnTouch) {
|
|
421
|
+
errorElement.textContent = error;
|
|
422
|
+
errorElement.style.display = "block";
|
|
423
|
+
element.setAttribute("aria-invalid", "true");
|
|
424
|
+
element.classList.add("error");
|
|
425
|
+
} else {
|
|
426
|
+
errorElement.textContent = "";
|
|
427
|
+
errorElement.style.display = "none";
|
|
428
|
+
element.setAttribute("aria-invalid", "false");
|
|
429
|
+
element.classList.remove("error");
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function validateForm() {
|
|
433
|
+
let isValid = true;
|
|
434
|
+
for (const name of state.fields.keys()) {
|
|
435
|
+
const fieldValid = validateField(name);
|
|
436
|
+
if (!fieldValid) isValid = false;
|
|
437
|
+
}
|
|
438
|
+
return isValid;
|
|
439
|
+
}
|
|
440
|
+
function handleChange(event) {
|
|
441
|
+
const input = event.target;
|
|
442
|
+
const name = input.getAttribute("name");
|
|
443
|
+
if (!state.fields.has(name)) return;
|
|
444
|
+
state.values[name] = getFieldValue(input);
|
|
445
|
+
if (opts.validateOnChange) {
|
|
446
|
+
if (debounceTimers.has(name)) {
|
|
447
|
+
clearTimeout(debounceTimers.get(name));
|
|
448
|
+
}
|
|
449
|
+
const timer = setTimeout(() => {
|
|
450
|
+
validateField(name);
|
|
451
|
+
debounceTimers.delete(name);
|
|
452
|
+
}, opts.debounce);
|
|
453
|
+
debounceTimers.set(name, timer);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function handleBlur(event) {
|
|
457
|
+
const input = event.target;
|
|
458
|
+
const name = input.getAttribute("name");
|
|
459
|
+
if (!state.fields.has(name)) return;
|
|
460
|
+
state.touched[name] = true;
|
|
461
|
+
if (opts.validateOnBlur) {
|
|
462
|
+
validateField(name);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function handleSubmit(event) {
|
|
466
|
+
event.preventDefault();
|
|
467
|
+
for (const name of state.fields.keys()) {
|
|
468
|
+
state.touched[name] = true;
|
|
469
|
+
}
|
|
470
|
+
const isValid = validateForm();
|
|
471
|
+
if (!isValid) {
|
|
472
|
+
const firstErrorField = Array.from(state.fields.values()).find((field) => state.errors[field.name]);
|
|
473
|
+
if (firstErrorField) {
|
|
474
|
+
firstErrorField.element.focus();
|
|
475
|
+
}
|
|
476
|
+
if (options.onError) {
|
|
477
|
+
options.onError(state.errors);
|
|
478
|
+
}
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
state.isSubmitting = true;
|
|
482
|
+
const submitData = { ...state.values };
|
|
483
|
+
if (options.onSubmit) {
|
|
484
|
+
const result = options.onSubmit(submitData, event);
|
|
485
|
+
if (result === false) {
|
|
486
|
+
state.isSubmitting = false;
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (result && typeof result.then === "function") {
|
|
490
|
+
result.then(() => {
|
|
491
|
+
state.isSubmitting = false;
|
|
492
|
+
if (options.onSuccess) {
|
|
493
|
+
options.onSuccess(submitData);
|
|
494
|
+
}
|
|
495
|
+
}).catch((error) => {
|
|
496
|
+
state.isSubmitting = false;
|
|
497
|
+
if (options.onError) {
|
|
498
|
+
options.onError(error);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (!options.onSubmit) {
|
|
505
|
+
form.submit();
|
|
506
|
+
}
|
|
507
|
+
state.isSubmitting = false;
|
|
508
|
+
}
|
|
509
|
+
function attachEventListeners() {
|
|
510
|
+
state.fields.forEach((field) => {
|
|
511
|
+
field.element.addEventListener("input", handleChange);
|
|
512
|
+
field.element.addEventListener("blur", handleBlur);
|
|
513
|
+
});
|
|
514
|
+
form.addEventListener("submit", handleSubmit);
|
|
515
|
+
}
|
|
516
|
+
function detachEventListeners() {
|
|
517
|
+
state.fields.forEach((field) => {
|
|
518
|
+
field.element.removeEventListener("input", handleChange);
|
|
519
|
+
field.element.removeEventListener("blur", handleBlur);
|
|
520
|
+
});
|
|
521
|
+
form.removeEventListener("submit", handleSubmit);
|
|
522
|
+
debounceTimers.forEach((timer) => clearTimeout(timer));
|
|
523
|
+
debounceTimers.clear();
|
|
524
|
+
}
|
|
525
|
+
function reset() {
|
|
526
|
+
state.fields.forEach((field) => {
|
|
527
|
+
setFieldValue(field.name, "");
|
|
528
|
+
state.touched[field.name] = false;
|
|
529
|
+
state.errors[field.name] = null;
|
|
530
|
+
displayError(field.name, null);
|
|
531
|
+
});
|
|
532
|
+
state.isSubmitting = false;
|
|
533
|
+
form.reset();
|
|
534
|
+
}
|
|
535
|
+
discoverFields();
|
|
536
|
+
attachEventListeners();
|
|
537
|
+
return {
|
|
538
|
+
validateField,
|
|
539
|
+
validateForm,
|
|
540
|
+
setFieldValue,
|
|
541
|
+
getFieldValue: (name) => state.values[name],
|
|
542
|
+
getError: (name) => state.errors[name],
|
|
543
|
+
getErrors: () => ({ ...state.errors }),
|
|
544
|
+
getValues: () => ({ ...state.values }),
|
|
545
|
+
setTouched: (name, touched = true) => {
|
|
546
|
+
state.touched[name] = touched;
|
|
547
|
+
},
|
|
548
|
+
reset,
|
|
549
|
+
destroy: detachEventListeners,
|
|
550
|
+
isValid: () => Object.values(state.errors).every((e) => !e),
|
|
551
|
+
isSubmitting: () => state.isSubmitting,
|
|
552
|
+
getState: () => ({
|
|
553
|
+
values: { ...state.values },
|
|
554
|
+
errors: { ...state.errors },
|
|
555
|
+
touched: { ...state.touched },
|
|
556
|
+
isSubmitting: state.isSubmitting
|
|
557
|
+
})
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
var form_hydration_default = hydrateForm;
|
|
561
|
+
export {
|
|
562
|
+
form_hydration_default as default,
|
|
563
|
+
hydrateForm
|
|
564
|
+
};
|
|
565
|
+
//# sourceMappingURL=form-hydration.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/validators.js", "../src/form-hydration.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Forms - Validators\n * \n * Form validation utilities\n * \n * @module forms/validators\n */\n\n/**\n * Built-in validators with signature: (value, options, translator, allValues) => errorMessage | null\n */\nexport const validators = {\n required: (value, options = {}) => {\n if (value === null || value === undefined || value === '') {\n return options.message || validators.required.message || 'This field is required';\n }\n return null;\n },\n\n email: (value) => {\n if (!value) return null;\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(value)) {\n return 'Please enter a valid email address';\n }\n return null;\n },\n\n minLength: (value, options = {}) => {\n if (!value) return null;\n const min = options.min || 0;\n if (value.length < min) {\n return options.message || `Must be at least ${min} characters`;\n }\n return null;\n },\n\n maxLength: (value, options = {}) => {\n if (!value) return null;\n const max = options.max || Infinity;\n if (value.length > max) {\n return options.message || `Must be no more than ${max} characters`;\n }\n return null;\n },\n\n min: (value, options = {}) => {\n if (value === null || value === undefined || value === '') return null;\n const num = Number(value);\n const minValue = options.min || 0;\n if (isNaN(num) || num < minValue) {\n return options.message || `Must be at least ${minValue}`;\n }\n return null;\n },\n\n max: (value, options = {}) => {\n if (value === null || value === undefined || value === '') return null;\n const num = Number(value);\n const maxValue = options.max || Infinity;\n if (isNaN(num) || num > maxValue) {\n return options.message || `Must be no more than ${maxValue}`;\n }\n return null;\n },\n\n pattern: (value, options = {}) => {\n if (!value) return null;\n const regex = options.pattern || options.regex;\n if (regex && !regex.test(value)) {\n return options.message || 'Invalid format';\n }\n return null;\n },\n\n url: (value) => {\n if (!value) return null;\n try {\n new URL(value);\n return null;\n } catch {\n return 'Please enter a valid URL';\n }\n },\n\n number: (value) => {\n if (value === null || value === undefined || value === '') return null;\n if (isNaN(Number(value))) {\n return 'Must be a valid number';\n }\n return null;\n },\n\n integer: (value) => {\n if (value === null || value === undefined || value === '') return null;\n const num = Number(value);\n if (isNaN(num) || !Number.isInteger(num)) {\n return 'Must be a whole number';\n }\n return null;\n },\n\n phone: (value) => {\n if (!value) return null;\n const phoneRegex = /^[\\d\\s\\-\\+\\(\\)]+$/;\n if (!phoneRegex.test(value) || value.replace(/\\D/g, '').length < 10) {\n return 'Please enter a valid phone number';\n }\n return null;\n },\n\n date: (value) => {\n if (!value) return null;\n const date = new Date(value);\n if (isNaN(date.getTime())) {\n return 'Please enter a valid date';\n }\n return null;\n },\n\n match: (value, options = {}, translator, allValues = {}) => {\n if (!value) return null;\n const fieldName = options.field || options.fieldName;\n if (value !== allValues[fieldName]) {\n return options.message || `Must match ${fieldName}`;\n }\n return null;\n },\n\n custom: (value, options = {}, translator, allValues) => {\n const validatorFn = options.validator || options.fn;\n if (!validatorFn) return null;\n const isValid = validatorFn(value, allValues);\n return isValid ? null : (options.message || 'Validation failed');\n },\n\n fileType: (value, options = {}) => {\n if (!value) return null;\n \n const allowedTypes = options.accept || options.types || [];\n \n // Handle File object\n if (value.type !== undefined) {\n const fileType = value.type;\n const fileExt = value.name ? value.name.split('.').pop().toLowerCase() : '';\n \n // Check MIME type or extension\n const isValid = allowedTypes.some(type => {\n if (type.startsWith('.')) {\n return fileExt === type.slice(1).toLowerCase();\n }\n if (type.includes('/')) {\n if (type.endsWith('/*')) {\n return fileType.startsWith(type.replace('/*', '/'));\n }\n return fileType === type;\n }\n return fileExt === type.toLowerCase();\n });\n \n if (!isValid) {\n return options.message || `File type must be one of: ${allowedTypes.join(', ')}`;\n }\n return null;\n }\n \n return null;\n },\n\n fileSize: (value, options = {}) => {\n if (!value) return null;\n \n const maxSize = options.maxSize || Infinity;\n \n // Handle File object\n if (value.size !== undefined) {\n if (value.size > maxSize) {\n const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(2);\n return options.message || `File size must be less than ${maxSizeMB}MB`;\n }\n return null;\n }\n \n return null;\n },\n\n fileExtension: (value, options = {}) => {\n if (!value) return null;\n \n const allowedExtensions = options.extensions || [];\n const fileName = value.name || value;\n const ext = `.${ fileName.split('.').pop().toLowerCase()}`;\n \n const isValid = allowedExtensions.some(allowed => {\n return ext === allowed.toLowerCase();\n });\n \n if (!isValid) {\n return options.message || `File extension must be one of: ${allowedExtensions.join(', ')}`;\n }\n return null;\n },\n\n alpha: (value) => {\n if (!value) return null;\n const alphaRegex = /^[a-zA-Z]+$/;\n if (!alphaRegex.test(value)) {\n return 'Must contain only letters';\n }\n return null;\n },\n\n alphanumeric: (value) => {\n if (!value) return null;\n const alphanumericRegex = /^[a-zA-Z0-9]+$/;\n if (!alphanumericRegex.test(value)) {\n return 'Must contain only letters and numbers';\n }\n return null;\n },\n\n uppercase: (value) => {\n if (!value) return null;\n if (value !== value.toUpperCase()) {\n return 'Must be uppercase';\n }\n return null;\n },\n\n // Get a registered validator\n get: (name) => {\n return validators[name];\n },\n\n // Compose multiple validators\n compose: (validatorList) => {\n return (value, options, translator, allValues) => {\n for (const validator of validatorList) {\n const error = typeof validator === 'function'\n ? validator(value, options, translator, allValues)\n : null;\n if (error) {\n return error;\n }\n }\n return null;\n };\n },\n\n // Debounce async validator\n debounce: (validator, delay = 300) => {\n let timeoutId;\n return (value) => {\n return new Promise((resolve) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(async () => {\n const result = await validator(value);\n resolve(result);\n }, delay);\n });\n };\n },\n\n // Cancellable async validator\n cancellable: (validator) => {\n let abortController;\n const wrapped = async (value) => {\n if (abortController) {\n abortController.abort();\n }\n // AbortController is a global browser/Node.js API\n abortController = typeof AbortController !== 'undefined' ? new AbortController() : null;\n try {\n return await validator(value, abortController ? abortController.signal : null);\n } catch (error) {\n if (error.name === 'AbortError') {\n return null;\n }\n throw error;\n }\n };\n wrapped.cancel = () => {\n if (abortController) {\n abortController.abort();\n }\n };\n return wrapped;\n },\n\n // Conditional validator\n when: (condition, validator) => {\n return (value, options = {}, translator, allValues = {}) => {\n // Pass options as context if it looks like context (has non-validator properties)\n const context = options.min !== undefined || options.max !== undefined ? allValues : options;\n const shouldValidate = typeof condition === 'function' \n ? condition(value, context) \n : condition;\n \n if (!shouldValidate) {\n return null;\n }\n \n return typeof validator === 'function'\n ? validator(value, options, translator, allValues)\n : null;\n };\n },\n\n // Validator chain builder\n chain: (options = {}) => {\n const validatorList = [];\n const stopOnFirstError = options.stopOnFirstError !== false;\n \n const chain = {\n required: (opts) => {\n validatorList.push((v, o, t, a) => validators.required(v, opts || o, t, a));\n return chain;\n },\n email: (opts) => {\n validatorList.push((v, o, t, a) => validators.email(v, opts || o, t, a));\n return chain;\n },\n minLength: (opts) => {\n validatorList.push((v, o, t, a) => validators.minLength(v, opts || o, t, a));\n return chain;\n },\n maxLength: (opts) => {\n validatorList.push((v, o, t, a) => validators.maxLength(v, opts || o, t, a));\n return chain;\n },\n custom: (fn, message) => {\n validatorList.push((v, o, t, a) => {\n // Custom validator returns null if valid, message if invalid\n const result = fn(v, a);\n return result === null || result === true || result === undefined ? null : (message || result);\n });\n return chain;\n },\n validate: (value, opts, translator, allValues) => {\n if (stopOnFirstError) {\n // Stop on first error - return single error or null\n for (const validator of validatorList) {\n const error = validator(value, opts, translator, allValues);\n if (error) {\n return error;\n }\n }\n return null;\n } else {\n // Collect all errors - return array or null\n const errors = [];\n for (const validator of validatorList) {\n const error = validator(value, opts, translator, allValues);\n if (error) {\n errors.push(error);\n }\n }\n return errors.length > 0 ? errors : null;\n }\n }\n };\n \n return chain;\n }\n};\n\n/**\n * Validate a single field\n */\nexport function validateField(value, validatorList, formData = {}) {\n for (const validator of validatorList) {\n const error = validator(value, formData);\n if (error) {\n return error;\n }\n }\n return null;\n}\n\n/**\n * Validate entire form\n */\nexport function validateForm(formData, fieldValidators) {\n const errors = {};\n \n for (const [fieldName, validatorList] of Object.entries(fieldValidators)) {\n const value = formData[fieldName];\n const error = validateField(value, validatorList, formData);\n if (error) {\n errors[fieldName] = error;\n }\n }\n \n return Object.keys(errors).length > 0 ? errors : null;\n}\n\n/**\n * Create a validator\n */\nexport function createValidator(validatorFn, message) {\n return (value, options, translator, allValues) => {\n const result = validatorFn(value, options, translator, allValues);\n // If validator returns a string, use it as the error message\n if (typeof result === 'string') {\n return result;\n }\n // If validator returns falsy (null, false, undefined), no error\n if (!result) {\n return null;\n }\n // If validator returns truthy (true, object, etc), use provided message\n return message || 'Validation failed';\n };\n}\n\n/**\n * Register a custom validator\n */\nexport function registerValidator(name, validatorFn) {\n validators[name] = validatorFn;\n}\n\n/**\n * Compose multiple validators\n */\nexport function composeValidators(...validatorFns) {\n return (value, options, translator, allValues) => {\n for (const validator of validatorFns) {\n const error = validator(value, options, translator, allValues);\n if (error) {\n return error;\n }\n }\n return null;\n };\n}\n\nexport default {\n validators,\n validateField,\n validateForm,\n createValidator,\n registerValidator,\n composeValidators\n};\n", "/**\n * Form Hydration for Coherent.js\n *\n * Progressive enhancement for server-rendered forms\n * Reads validation metadata from HTML and attaches client-side behavior\n *\n * @module forms/form-hydration\n */\n\nimport { validators } from './validators.js';\n\n/**\n * Hydrate a server-rendered form with client-side validation and behavior\n *\n * @param {string|HTMLFormElement} formSelector - Form selector or element\n * @param {Object} options - Hydration options\n * @returns {Object} Form controller\n */\nexport function hydrateForm(formSelector, options = {}) {\n // Browser-only check\n if (typeof document === 'undefined') {\n console.warn('hydrateForm can only run in browser environment');\n return null;\n }\n\n const form = typeof formSelector === 'string'\n ? document.querySelector(formSelector)\n : formSelector;\n\n if (!form) {\n console.warn(`Form not found: ${formSelector}`);\n return null;\n }\n\n const opts = {\n validateOnBlur: true,\n validateOnChange: false,\n validateOnSubmit: true,\n showErrorsOnTouch: true,\n debounce: 300,\n ...options\n };\n\n // Form state\n const state = {\n values: {},\n errors: {},\n touched: {},\n isSubmitting: false,\n fields: new Map()\n };\n\n // Debounce timers\n const debounceTimers = new Map();\n\n /**\n * Parse validators from data-validators attribute\n */\n function parseValidators(validatorString) {\n if (!validatorString) return [];\n\n return validatorString.split(',').map(v => {\n const trimmed = v.trim();\n\n // Handle validators with parameters: minLength:8\n const [name, ...params] = trimmed.split(':');\n\n if (validators[name]) {\n return params.length > 0\n ? validators[name](...params.map(p => isNaN(p) ? p : Number(p)))\n : validators[name];\n }\n\n return null;\n }).filter(Boolean);\n }\n\n /**\n * Discover and register fields from form HTML\n */\n function discoverFields() {\n const inputs = form.querySelectorAll('[name]');\n\n inputs.forEach(input => {\n const name = input.getAttribute('name');\n const field = {\n name,\n element: input,\n type: input.getAttribute('type') || 'text',\n required: input.hasAttribute('required') || input.dataset.required === 'true',\n validators: parseValidators(input.dataset.validators),\n errorElement: null\n };\n\n // Find or create error display element\n const errorId = `${name}-error`;\n field.errorElement = document.getElementById(errorId) || createErrorElement(name, input);\n\n state.fields.set(name, field);\n state.values[name] = getFieldValue(input);\n state.touched[name] = false;\n state.errors[name] = null;\n });\n }\n\n /**\n * Create error display element\n */\n function createErrorElement(name, inputElement) {\n const errorDiv = document.createElement('div');\n errorDiv.id = `${name}-error`;\n errorDiv.className = 'error-message';\n errorDiv.setAttribute('role', 'alert');\n errorDiv.style.display = 'none';\n\n // Insert after input or its parent field wrapper\n const fieldWrapper = inputElement.closest('.form-field') || inputElement.parentElement;\n fieldWrapper.appendChild(errorDiv);\n\n return errorDiv;\n }\n\n /**\n * Get field value based on input type\n */\n function getFieldValue(input) {\n if (input.type === 'checkbox') {\n return input.checked;\n } else if (input.type === 'radio') {\n const checked = form.querySelector(`[name=\"${input.name}\"]:checked`);\n return checked ? checked.value : null;\n } else {\n return input.value;\n }\n }\n\n /**\n * Set field value\n */\n function setFieldValue(name, value) {\n const field = state.fields.get(name);\n if (!field) return;\n\n const { element } = field;\n\n if (element.type === 'checkbox') {\n element.checked = Boolean(value);\n } else if (element.type === 'radio') {\n const radio = form.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n element.value = value;\n }\n\n state.values[name] = value;\n }\n\n /**\n * Validate a single field\n */\n function validateField(name) {\n const field = state.fields.get(name);\n if (!field) return true;\n\n const value = state.values[name];\n let error = null;\n\n // Required validation\n if (field.required && (value === null || value === undefined || value === '')) {\n error = 'This field is required';\n }\n\n // Run custom validators\n if (!error && field.validators.length > 0) {\n for (const validator of field.validators) {\n const result = validator.validate\n ? validator.validate(value, state.values)\n : validator(value, state.values);\n\n if (result !== true && result !== undefined && result !== null) {\n error = validator.message || result || 'Validation failed';\n break;\n }\n }\n }\n\n state.errors[name] = error;\n displayError(name, error);\n\n return !error;\n }\n\n /**\n * Display error message\n */\n function displayError(name, error) {\n const field = state.fields.get(name);\n if (!field) return;\n\n const { element, errorElement } = field;\n\n if (error && state.touched[name] && opts.showErrorsOnTouch) {\n // Show error\n errorElement.textContent = error;\n errorElement.style.display = 'block';\n element.setAttribute('aria-invalid', 'true');\n element.classList.add('error');\n } else {\n // Hide error\n errorElement.textContent = '';\n errorElement.style.display = 'none';\n element.setAttribute('aria-invalid', 'false');\n element.classList.remove('error');\n }\n }\n\n /**\n * Validate entire form\n */\n function validateForm() {\n let isValid = true;\n\n for (const name of state.fields.keys()) {\n const fieldValid = validateField(name);\n if (!fieldValid) isValid = false;\n }\n\n return isValid;\n }\n\n /**\n * Handle input change\n */\n function handleChange(event) {\n const input = event.target;\n const name = input.getAttribute('name');\n\n if (!state.fields.has(name)) return;\n\n state.values[name] = getFieldValue(input);\n\n if (opts.validateOnChange) {\n // Debounce validation\n if (debounceTimers.has(name)) {\n clearTimeout(debounceTimers.get(name));\n }\n\n const timer = setTimeout(() => {\n validateField(name);\n debounceTimers.delete(name);\n }, opts.debounce);\n\n debounceTimers.set(name, timer);\n }\n }\n\n /**\n * Handle input blur\n */\n function handleBlur(event) {\n const input = event.target;\n const name = input.getAttribute('name');\n\n if (!state.fields.has(name)) return;\n\n state.touched[name] = true;\n\n if (opts.validateOnBlur) {\n validateField(name);\n }\n }\n\n /**\n * Handle form submission\n */\n function handleSubmit(event) {\n event.preventDefault();\n\n // Mark all fields as touched\n for (const name of state.fields.keys()) {\n state.touched[name] = true;\n }\n\n const isValid = validateForm();\n\n if (!isValid) {\n // Focus first error field\n const firstErrorField = Array.from(state.fields.values())\n .find(field => state.errors[field.name]);\n\n if (firstErrorField) {\n firstErrorField.element.focus();\n }\n\n // Call onError callback\n if (options.onError) {\n options.onError(state.errors);\n }\n\n return;\n }\n\n // Form is valid, prepare submission\n state.isSubmitting = true;\n\n const submitData = { ...state.values };\n\n // Call onSubmit callback\n if (options.onSubmit) {\n const result = options.onSubmit(submitData, event);\n\n // If onSubmit returns false, don't submit\n if (result === false) {\n state.isSubmitting = false;\n return;\n }\n\n // If onSubmit returns a promise, wait for it\n if (result && typeof result.then === 'function') {\n result\n .then(() => {\n state.isSubmitting = false;\n if (options.onSuccess) {\n options.onSuccess(submitData);\n }\n })\n .catch(error => {\n state.isSubmitting = false;\n if (options.onError) {\n options.onError(error);\n }\n });\n return;\n }\n }\n\n // Default: submit the form normally\n if (!options.onSubmit) {\n form.submit();\n }\n\n state.isSubmitting = false;\n }\n\n /**\n * Attach event listeners\n */\n function attachEventListeners() {\n // Input change events\n state.fields.forEach(field => {\n field.element.addEventListener('input', handleChange);\n field.element.addEventListener('blur', handleBlur);\n });\n\n // Form submit\n form.addEventListener('submit', handleSubmit);\n }\n\n /**\n * Detach event listeners (cleanup)\n */\n function detachEventListeners() {\n state.fields.forEach(field => {\n field.element.removeEventListener('input', handleChange);\n field.element.removeEventListener('blur', handleBlur);\n });\n\n form.removeEventListener('submit', handleSubmit);\n\n // Clear debounce timers\n debounceTimers.forEach(timer => clearTimeout(timer));\n debounceTimers.clear();\n }\n\n /**\n * Reset form to initial state\n */\n function reset() {\n state.fields.forEach(field => {\n setFieldValue(field.name, '');\n state.touched[field.name] = false;\n state.errors[field.name] = null;\n displayError(field.name, null);\n });\n\n state.isSubmitting = false;\n form.reset();\n }\n\n // Initialize\n discoverFields();\n attachEventListeners();\n\n // Public API\n return {\n validateField,\n validateForm,\n setFieldValue,\n getFieldValue: (name) => state.values[name],\n getError: (name) => state.errors[name],\n getErrors: () => ({ ...state.errors }),\n getValues: () => ({ ...state.values }),\n setTouched: (name, touched = true) => {\n state.touched[name] = touched;\n },\n reset,\n destroy: detachEventListeners,\n isValid: () => Object.values(state.errors).every(e => !e),\n isSubmitting: () => state.isSubmitting,\n getState: () => ({\n values: { ...state.values },\n errors: { ...state.errors },\n touched: { ...state.touched },\n isSubmitting: state.isSubmitting\n })\n };\n}\n\nexport default hydrateForm;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|