@formhaus/core 0.1.0 → 0.3.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/dist/engine/form-engine.d.ts +3 -0
- package/dist/engine/form-engine.d.ts.map +1 -1
- package/dist/engine/form-engine.js +46 -26
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/schema-validation/validate-schema.d.ts.map +1 -1
- package/dist/schema-validation/validate-schema.js +18 -8
- package/dist/types/field.d.ts +2 -1
- package/dist/types/field.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/validation/default-messages.js +2 -2
- package/dist/validation/validate-field.d.ts.map +1 -1
- package/dist/validation/validate-field.js +11 -5
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ export declare class FormEngine {
|
|
|
14
14
|
private _listeners;
|
|
15
15
|
private _validators;
|
|
16
16
|
private _allFields;
|
|
17
|
+
private _isDirty;
|
|
18
|
+
private _cache;
|
|
17
19
|
constructor(schema: FormSchema, initialValues?: Record<string, unknown>, options?: FormEngineOptions);
|
|
18
20
|
subscribe(listener: () => void): () => void;
|
|
19
21
|
getSnapshot(): number;
|
|
@@ -40,6 +42,7 @@ export declare class FormEngine {
|
|
|
40
42
|
reset(values?: Record<string, unknown>): void;
|
|
41
43
|
private _computeAllFields;
|
|
42
44
|
private _cascadeClearHiddenFields;
|
|
45
|
+
private _recomputeIfDirty;
|
|
43
46
|
private _notify;
|
|
44
47
|
}
|
|
45
48
|
//# sourceMappingURL=form-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-engine.d.ts","sourceRoot":"","sources":["../../src/engine/form-engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAMjD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC1C;AAED,qBAAa,UAAU;IACrB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAE5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,UAAU,CAAc;
|
|
1
|
+
{"version":3,"file":"form-engine.d.ts","sourceRoot":"","sources":["../../src/engine/form-engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAMjD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC1C;AAED,qBAAa,UAAU;IACrB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAE5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,MAAM,CAKZ;gBAGA,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,CAAC,EAAE,iBAAiB;IA4C7B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO3C,WAAW,IAAI,MAAM;IAMrB,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,YAAY,IAAI,QAAQ,EAAE,CAG7B;IAED,IAAI,WAAW,IAAI,QAAQ,GAAG,IAAI,CAGjC;IAED,IAAI,aAAa,IAAI,SAAS,EAAE,CAG/B;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,SAAS,IAAI,OAAO,CAGvB;IAED,IAAI,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAGjD;IAID,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAY3C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IA0B/C,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IASpD,QAAQ,IAAI,OAAO;IAsBnB,QAAQ,IAAI,IAAI;IAQhB,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAkBlC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAezC,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA6B1C,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAezC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAkB7C,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IA4BjC,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,OAAO;CAOhB"}
|
|
@@ -5,8 +5,8 @@ const MAX_CASCADE_ITERATIONS = 50;
|
|
|
5
5
|
export class FormEngine {
|
|
6
6
|
constructor(schema, initialValues, options) {
|
|
7
7
|
// Validate schema structure
|
|
8
|
-
const hasFields = schema.fields
|
|
9
|
-
const hasSteps = schema.steps
|
|
8
|
+
const hasFields = (schema.fields?.length ?? 0) > 0;
|
|
9
|
+
const hasSteps = (schema.steps?.length ?? 0) > 0;
|
|
10
10
|
if (hasFields && hasSteps) {
|
|
11
11
|
throw new Error('FormSchema cannot have both "fields" and "steps" as non-empty arrays.');
|
|
12
12
|
}
|
|
@@ -26,6 +26,8 @@ export class FormEngine {
|
|
|
26
26
|
this.topLevelErrors = [];
|
|
27
27
|
this.fieldLoading = {};
|
|
28
28
|
this._allFields = this._computeAllFields();
|
|
29
|
+
this._isDirty = true;
|
|
30
|
+
this._cache = { visibleSteps: [], currentStep: null, visibleFields: [], canGoNext: false };
|
|
29
31
|
// Initialize values with defaults, then overlay initialValues
|
|
30
32
|
this.values = {};
|
|
31
33
|
for (const field of this._allFields) {
|
|
@@ -52,26 +54,16 @@ export class FormEngine {
|
|
|
52
54
|
return (this.schema.steps ?? []).length > 0;
|
|
53
55
|
}
|
|
54
56
|
get visibleSteps() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const steps = this.schema.steps ?? [];
|
|
58
|
-
return steps.filter((s) => isStepVisible(s, this.values));
|
|
57
|
+
this._recomputeIfDirty();
|
|
58
|
+
return this._cache.visibleSteps;
|
|
59
59
|
}
|
|
60
60
|
get currentStep() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return null;
|
|
64
|
-
// Find the step at currentStepIndex within visible steps
|
|
65
|
-
return steps[this.currentStepIndex] ?? steps[steps.length - 1] ?? null;
|
|
61
|
+
this._recomputeIfDirty();
|
|
62
|
+
return this._cache.currentStep;
|
|
66
63
|
}
|
|
67
64
|
get visibleFields() {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!step)
|
|
71
|
-
return [];
|
|
72
|
-
return step.fields.filter((f) => isVisible(f, this.values));
|
|
73
|
-
}
|
|
74
|
-
return (this.schema.fields ?? []).filter((f) => isVisible(f, this.values));
|
|
65
|
+
this._recomputeIfDirty();
|
|
66
|
+
return this._cache.visibleFields;
|
|
75
67
|
}
|
|
76
68
|
get isFirstStep() {
|
|
77
69
|
return this.currentStepIndex === 0;
|
|
@@ -80,13 +72,8 @@ export class FormEngine {
|
|
|
80
72
|
return this.currentStepIndex >= this.visibleSteps.length - 1;
|
|
81
73
|
}
|
|
82
74
|
get canGoNext() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const step = this.currentStep;
|
|
86
|
-
if (!step)
|
|
87
|
-
return false;
|
|
88
|
-
const stepErrors = validateStep(step, this.values, this._validators);
|
|
89
|
-
return Object.keys(stepErrors).length === 0;
|
|
75
|
+
this._recomputeIfDirty();
|
|
76
|
+
return this._cache.canGoNext;
|
|
90
77
|
}
|
|
91
78
|
get progress() {
|
|
92
79
|
const total = this.visibleSteps.length;
|
|
@@ -102,6 +89,7 @@ export class FormEngine {
|
|
|
102
89
|
this._notify();
|
|
103
90
|
}
|
|
104
91
|
setErrors(errors) {
|
|
92
|
+
this.errors = {};
|
|
105
93
|
this.topLevelErrors = [];
|
|
106
94
|
for (const [key, message] of Object.entries(errors)) {
|
|
107
95
|
// Check if field is visible
|
|
@@ -256,10 +244,21 @@ export class FormEngine {
|
|
|
256
244
|
return this.schema.fields ?? [];
|
|
257
245
|
}
|
|
258
246
|
_cascadeClearHiddenFields() {
|
|
247
|
+
const hiddenStepFields = new Set();
|
|
248
|
+
if (this.isMultiStep) {
|
|
249
|
+
for (const step of this.schema.steps ?? []) {
|
|
250
|
+
if (!isStepVisible(step, this.values)) {
|
|
251
|
+
for (const field of step.fields) {
|
|
252
|
+
hiddenStepFields.add(field.key);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
259
257
|
for (let i = 0; i < MAX_CASCADE_ITERATIONS; i++) {
|
|
260
258
|
let changed = false;
|
|
261
259
|
for (const field of this._allFields) {
|
|
262
|
-
|
|
260
|
+
const fieldHidden = !isVisible(field, this.values) || hiddenStepFields.has(field.key);
|
|
261
|
+
if (fieldHidden && this.values[field.key] !== undefined) {
|
|
263
262
|
delete this.values[field.key];
|
|
264
263
|
delete this.errors[field.key];
|
|
265
264
|
changed = true;
|
|
@@ -269,7 +268,28 @@ export class FormEngine {
|
|
|
269
268
|
break;
|
|
270
269
|
}
|
|
271
270
|
}
|
|
271
|
+
_recomputeIfDirty() {
|
|
272
|
+
if (!this._isDirty)
|
|
273
|
+
return;
|
|
274
|
+
this._isDirty = false;
|
|
275
|
+
if (!this.isMultiStep) {
|
|
276
|
+
this._cache.visibleSteps = [];
|
|
277
|
+
this._cache.currentStep = null;
|
|
278
|
+
this._cache.visibleFields = (this.schema.fields ?? []).filter((f) => isVisible(f, this.values));
|
|
279
|
+
this._cache.canGoNext = false;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const steps = this.schema.steps ?? [];
|
|
283
|
+
this._cache.visibleSteps = steps.filter((s) => isStepVisible(s, this.values));
|
|
284
|
+
const vs = this._cache.visibleSteps;
|
|
285
|
+
this._cache.currentStep = vs[this.currentStepIndex] ?? vs[vs.length - 1] ?? null;
|
|
286
|
+
const step = this._cache.currentStep;
|
|
287
|
+
this._cache.visibleFields = step ? step.fields.filter((f) => isVisible(f, this.values)) : [];
|
|
288
|
+
const stepErrors = step ? validateStep(step, this.values, this._validators) : {};
|
|
289
|
+
this._cache.canGoNext = Object.keys(stepErrors).length === 0;
|
|
290
|
+
}
|
|
272
291
|
_notify() {
|
|
292
|
+
this._isDirty = true;
|
|
273
293
|
this._version++;
|
|
274
294
|
for (const listener of this._listeners) {
|
|
275
295
|
listener();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { FieldOption, FieldType, FieldValidation, FormAction, FormAnalyticsEvent, FormField, FormSchema, FormStep, ShowCondition, } from './types';
|
|
1
|
+
export type { DefaultFieldType, FieldOption, FieldType, FieldValidation, FormAction, FormAnalyticsEvent, FormField, FormSchema, FormStep, ShowCondition, } from './types';
|
|
2
2
|
export { FormEngine, type FormEngineOptions } from './engine';
|
|
3
3
|
export { evaluateCondition, isStepVisible, isVisible } from './visibility';
|
|
4
4
|
export { type ValidatorFn, getDefaultMessage, validateField, validateFields, validateStep, } from './validation';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG9D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG3E,OAAO,EACL,KAAK,WAAW,EAChB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG9D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG3E,OAAO,EACL,KAAK,WAAW,EAChB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-schema.d.ts","sourceRoot":"","sources":["../../src/schema-validation/validate-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAiB,MAAM,UAAU,CAAC;AA+CrE,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"validate-schema.d.ts","sourceRoot":"","sources":["../../src/schema-validation/validate-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAiB,MAAM,UAAU,CAAC;AA+CrE,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAqD3D"}
|
|
@@ -4,7 +4,7 @@ function extractDependencies(conditions) {
|
|
|
4
4
|
return conditions.map((c) => c.field);
|
|
5
5
|
}
|
|
6
6
|
function getAllFields(schema) {
|
|
7
|
-
if (schema.steps
|
|
7
|
+
if ((schema.steps?.length ?? 0) > 0) {
|
|
8
8
|
return schema.steps.flatMap((s) => s.fields);
|
|
9
9
|
}
|
|
10
10
|
return schema.fields ?? [];
|
|
@@ -38,29 +38,39 @@ function detectCycles(graph) {
|
|
|
38
38
|
}
|
|
39
39
|
export function validateSchema(schema) {
|
|
40
40
|
const warnings = [];
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const hasSteps = schema.steps && schema.steps.length > 0;
|
|
41
|
+
const hasFields = (schema.fields?.length ?? 0) > 0;
|
|
42
|
+
const hasSteps = (schema.steps?.length ?? 0) > 0;
|
|
44
43
|
if (hasFields && hasSteps) {
|
|
45
44
|
warnings.push('Schema has both "fields" and "steps". Only "steps" will be used.');
|
|
46
45
|
}
|
|
47
|
-
// Build dependency graph from show conditions
|
|
48
46
|
const allFields = getAllFields(schema);
|
|
49
|
-
const fieldKeys = new Set(
|
|
47
|
+
const fieldKeys = new Set();
|
|
50
48
|
const graph = new Map();
|
|
49
|
+
for (const field of allFields) {
|
|
50
|
+
if (fieldKeys.has(field.key)) {
|
|
51
|
+
warnings.push(`Duplicate field key "${field.key}" — fields will share state and overwrite each other`);
|
|
52
|
+
}
|
|
53
|
+
fieldKeys.add(field.key);
|
|
54
|
+
}
|
|
51
55
|
for (const field of allFields) {
|
|
52
56
|
const deps = [...extractDependencies(field.show), ...extractDependencies(field.showAny)];
|
|
53
|
-
// Warn about references to non-existent fields
|
|
54
57
|
for (const dep of deps) {
|
|
55
58
|
if (!fieldKeys.has(dep)) {
|
|
56
59
|
warnings.push(`Field "${field.key}" has show condition referencing non-existent field "${dep}"`);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
62
|
+
if (field.validation?.pattern !== undefined) {
|
|
63
|
+
try {
|
|
64
|
+
new RegExp(field.validation.pattern);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
warnings.push(`Field "${field.key}" has invalid regex pattern: "${field.validation.pattern}"`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
59
70
|
if (deps.length > 0) {
|
|
60
71
|
graph.set(field.key, deps);
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
|
-
// Detect cycles
|
|
64
74
|
const cycles = detectCycles(graph);
|
|
65
75
|
for (const cycle of cycles) {
|
|
66
76
|
warnings.push(`Circular show condition detected: ${cycle.join(' -> ')}`);
|
package/dist/types/field.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type DefaultFieldType = 'text' | 'email' | 'phone' | 'number' | 'password' | 'select' | 'multiselect' | 'checkbox' | 'radio' | 'switch' | 'file' | 'date' | 'textarea';
|
|
2
|
+
export type FieldType = DefaultFieldType | (string & {});
|
|
2
3
|
export interface FieldOption {
|
|
3
4
|
value: string;
|
|
4
5
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/types/field.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/types/field.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,aAAa,GACb,UAAU,GACV,OAAO,GACP,QAAQ,GACR,MAAM,GACN,MAAM,GACN,UAAU,CAAC;AAEf,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;CAClD;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAChC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { FormAction } from './action';
|
|
2
2
|
export type { FormAnalyticsEvent } from './analytics';
|
|
3
|
-
export type { FieldOption, FieldType, FieldValidation, FormField, ShowCondition, } from './field';
|
|
3
|
+
export type { DefaultFieldType, FieldOption, FieldType, FieldValidation, FormField, ShowCondition, } from './field';
|
|
4
4
|
export type { FormSchema, FormStep } from './schema';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,SAAS,EACT,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,eAAe,EACf,SAAS,EACT,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -3,9 +3,9 @@ export function getDefaultMessage(rule, params) {
|
|
|
3
3
|
case 'required':
|
|
4
4
|
return 'This field is required';
|
|
5
5
|
case 'minLength':
|
|
6
|
-
return `Must be at least ${params?.min} characters`;
|
|
6
|
+
return `Must be at least ${params?.min} ${params?.unit ?? 'characters'}`;
|
|
7
7
|
case 'maxLength':
|
|
8
|
-
return `Must be at most ${params?.max} characters`;
|
|
8
|
+
return `Must be at most ${params?.max} ${params?.unit ?? 'characters'}`;
|
|
9
9
|
case 'min':
|
|
10
10
|
return `Must be at least ${params?.min}`;
|
|
11
11
|
case 'max':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-field.d.ts","sourceRoot":"","sources":["../../src/validation/validate-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,UAAU,CAAC;AAG3D,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-field.d.ts","sourceRoot":"","sources":["../../src/validation/validate-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,UAAU,CAAC;AAG3D,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;AAQhG,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACvC,MAAM,GAAG,IAAI,CAiEf"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { getDefaultMessage } from './default-messages';
|
|
2
2
|
function isEmpty(value) {
|
|
3
|
-
|
|
3
|
+
if (value === undefined || value === null || value === '')
|
|
4
|
+
return true;
|
|
5
|
+
if (Array.isArray(value) && value.length === 0)
|
|
6
|
+
return true;
|
|
7
|
+
return false;
|
|
4
8
|
}
|
|
5
9
|
export function validateField(field, value, allValues, validators) {
|
|
6
10
|
const rules = field.validation;
|
|
@@ -14,14 +18,16 @@ export function validateField(field, value, allValues, validators) {
|
|
|
14
18
|
// Skip remaining rules if value is empty and not required
|
|
15
19
|
if (isEmpty(value))
|
|
16
20
|
return null;
|
|
17
|
-
if (rules.minLength !== undefined && typeof value === 'string') {
|
|
21
|
+
if (rules.minLength !== undefined && (typeof value === 'string' || Array.isArray(value))) {
|
|
18
22
|
if (value.length < rules.minLength) {
|
|
19
|
-
|
|
23
|
+
const unit = Array.isArray(value) ? 'items' : undefined;
|
|
24
|
+
return rules.minLengthMessage ?? getDefaultMessage('minLength', { min: rules.minLength, unit });
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
|
-
if (rules.maxLength !== undefined && typeof value === 'string') {
|
|
27
|
+
if (rules.maxLength !== undefined && (typeof value === 'string' || Array.isArray(value))) {
|
|
23
28
|
if (value.length > rules.maxLength) {
|
|
24
|
-
|
|
29
|
+
const unit = Array.isArray(value) ? 'items' : undefined;
|
|
30
|
+
return rules.maxLengthMessage ?? getDefaultMessage('maxLength', { max: rules.maxLength, unit });
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
if (rules.min !== undefined && typeof value === 'number') {
|
package/package.json
CHANGED