@axenstudio/axen-form 0.1.17 → 0.1.18

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 (128) hide show
  1. package/README.md +34 -3
  2. package/dist/adapters/yupAdapter.cjs +29 -10
  3. package/dist/adapters/yupAdapter.d.ts +1 -2
  4. package/dist/adapters/yupAdapter.js +29 -10
  5. package/dist/adapters/zodAdapter.cjs +29 -10
  6. package/dist/adapters/zodAdapter.d.ts +1 -2
  7. package/dist/adapters/zodAdapter.js +29 -10
  8. package/dist/core/dateUtils.d.ts +0 -1
  9. package/dist/core/formStore.cjs +110 -39
  10. package/dist/core/formStore.d.ts +1 -1
  11. package/dist/core/formStore.js +110 -39
  12. package/dist/core/numberUtils.d.ts +0 -1
  13. package/dist/core/pathUtils.d.ts +0 -1
  14. package/dist/core/payloadUtils.d.ts +0 -1
  15. package/dist/core/semanticValidation.cjs +69 -0
  16. package/dist/core/semanticValidation.d.ts +5 -0
  17. package/dist/core/semanticValidation.js +69 -0
  18. package/dist/core/validation.cjs +4 -3
  19. package/dist/core/validation.d.ts +0 -1
  20. package/dist/core/validation.js +4 -3
  21. package/dist/fields/AutocompleteField/AutocompleteField.d.ts +1 -2
  22. package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts +1 -2
  23. package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts +1 -2
  24. package/dist/fields/CheckboxField/CheckboxField.d.ts +1 -2
  25. package/dist/fields/ColorField/ColorField.d.ts +1 -2
  26. package/dist/fields/CurrencyField/CurrencyField.d.ts +1 -2
  27. package/dist/fields/DateField/DateField.d.ts +1 -2
  28. package/dist/fields/DateField/DatePicker.d.ts +1 -2
  29. package/dist/fields/DateTimeField/DateTimeField.d.ts +1 -2
  30. package/dist/fields/EmailField/EmailField.d.ts +1 -2
  31. package/dist/fields/NumberField/NumberField.d.ts +1 -2
  32. package/dist/fields/PasswordField/PasswordField.d.ts +1 -2
  33. package/dist/fields/PhoneField/PhoneField.d.ts +1 -2
  34. package/dist/fields/RadioField/RadioField.d.ts +1 -2
  35. package/dist/fields/SelectField/SelectField.d.ts +1 -2
  36. package/dist/fields/SliderField/SliderField.d.ts +1 -2
  37. package/dist/fields/SwitchField/SwitchField.d.ts +1 -2
  38. package/dist/fields/TextField/TextField.d.ts +1 -2
  39. package/dist/fields/TextareaField/TextareaField.d.ts +1 -2
  40. package/dist/fields/TimeField/TimeField.d.ts +1 -2
  41. package/dist/fields/TimeField/TimePicker.d.ts +1 -2
  42. package/dist/fields/defaultComponentMap.cjs +3 -0
  43. package/dist/fields/defaultComponentMap.d.ts +0 -1
  44. package/dist/fields/defaultComponentMap.js +3 -0
  45. package/dist/fields/defaultPlaceholders.d.ts +0 -1
  46. package/dist/fields/fieldBase.module.css.cjs +92 -70
  47. package/dist/fields/fieldBase.module.css.js +92 -70
  48. package/dist/fields/fieldUtils.d.ts +0 -1
  49. package/dist/fields/iconUtils.d.ts +0 -1
  50. package/dist/fields/icons.d.ts +3 -4
  51. package/dist/index.cjs +31 -22
  52. package/dist/index.d.ts +3 -2
  53. package/dist/index.js +32 -23
  54. package/dist/layout/Box/Box.d.ts +1 -2
  55. package/dist/layout/Divider/Divider.d.ts +1 -2
  56. package/dist/layout/Grid/Grid.d.ts +1 -2
  57. package/dist/layout/Spacer/Spacer.d.ts +1 -2
  58. package/dist/layout/Stack/Stack.d.ts +1 -2
  59. package/dist/layout/index.d.ts +0 -1
  60. package/dist/react/AxenArrayField.d.ts +1 -2
  61. package/dist/react/AxenField.d.ts +1 -2
  62. package/dist/react/AxenForm.cjs +29 -23
  63. package/dist/react/AxenForm.d.ts +0 -1
  64. package/dist/react/AxenForm.js +30 -24
  65. package/dist/react/FormContext.d.ts +0 -1
  66. package/dist/react/useAxenForm.cjs +11 -4
  67. package/dist/react/useAxenForm.d.ts +1 -2
  68. package/dist/react/useAxenForm.js +11 -4
  69. package/dist/react/useField.cjs +3 -0
  70. package/dist/react/useField.d.ts +0 -1
  71. package/dist/react/useField.js +3 -0
  72. package/dist/react/useFieldArray.cjs +19 -13
  73. package/dist/react/useFieldArray.d.ts +0 -1
  74. package/dist/react/useFieldArray.js +19 -13
  75. package/dist/react/useFormState.cjs +18 -0
  76. package/dist/react/useFormState.d.ts +5 -0
  77. package/dist/react/useFormState.js +18 -0
  78. package/dist/types.d.ts +18 -2
  79. package/package.json +5 -2
  80. package/dist/adapters/yupAdapter.d.ts.map +0 -1
  81. package/dist/adapters/zodAdapter.d.ts.map +0 -1
  82. package/dist/core/dateUtils.d.ts.map +0 -1
  83. package/dist/core/formStore.d.ts.map +0 -1
  84. package/dist/core/numberUtils.d.ts.map +0 -1
  85. package/dist/core/pathUtils.d.ts.map +0 -1
  86. package/dist/core/payloadUtils.d.ts.map +0 -1
  87. package/dist/core/validation.d.ts.map +0 -1
  88. package/dist/fields/AutocompleteField/AutocompleteField.d.ts.map +0 -1
  89. package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts.map +0 -1
  90. package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts.map +0 -1
  91. package/dist/fields/CheckboxField/CheckboxField.d.ts.map +0 -1
  92. package/dist/fields/ColorField/ColorField.d.ts.map +0 -1
  93. package/dist/fields/CurrencyField/CurrencyField.d.ts.map +0 -1
  94. package/dist/fields/DateField/DateField.d.ts.map +0 -1
  95. package/dist/fields/DateField/DatePicker.d.ts.map +0 -1
  96. package/dist/fields/DateTimeField/DateTimeField.d.ts.map +0 -1
  97. package/dist/fields/EmailField/EmailField.d.ts.map +0 -1
  98. package/dist/fields/NumberField/NumberField.d.ts.map +0 -1
  99. package/dist/fields/PasswordField/PasswordField.d.ts.map +0 -1
  100. package/dist/fields/PhoneField/PhoneField.d.ts.map +0 -1
  101. package/dist/fields/RadioField/RadioField.d.ts.map +0 -1
  102. package/dist/fields/SelectField/SelectField.d.ts.map +0 -1
  103. package/dist/fields/SliderField/SliderField.d.ts.map +0 -1
  104. package/dist/fields/SwitchField/SwitchField.d.ts.map +0 -1
  105. package/dist/fields/TextField/TextField.d.ts.map +0 -1
  106. package/dist/fields/TextareaField/TextareaField.d.ts.map +0 -1
  107. package/dist/fields/TimeField/TimeField.d.ts.map +0 -1
  108. package/dist/fields/TimeField/TimePicker.d.ts.map +0 -1
  109. package/dist/fields/defaultComponentMap.d.ts.map +0 -1
  110. package/dist/fields/defaultPlaceholders.d.ts.map +0 -1
  111. package/dist/fields/fieldUtils.d.ts.map +0 -1
  112. package/dist/fields/iconUtils.d.ts.map +0 -1
  113. package/dist/fields/icons.d.ts.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/layout/Box/Box.d.ts.map +0 -1
  116. package/dist/layout/Divider/Divider.d.ts.map +0 -1
  117. package/dist/layout/Grid/Grid.d.ts.map +0 -1
  118. package/dist/layout/Spacer/Spacer.d.ts.map +0 -1
  119. package/dist/layout/Stack/Stack.d.ts.map +0 -1
  120. package/dist/layout/index.d.ts.map +0 -1
  121. package/dist/react/AxenArrayField.d.ts.map +0 -1
  122. package/dist/react/AxenField.d.ts.map +0 -1
  123. package/dist/react/AxenForm.d.ts.map +0 -1
  124. package/dist/react/FormContext.d.ts.map +0 -1
  125. package/dist/react/useAxenForm.d.ts.map +0 -1
  126. package/dist/react/useField.d.ts.map +0 -1
  127. package/dist/react/useFieldArray.d.ts.map +0 -1
  128. package/dist/types.d.ts.map +0 -1
@@ -1,4 +1,15 @@
1
1
  import { get, set } from "./pathUtils.js";
2
+ function valuesEqual(a, b) {
3
+ if (Object.is(a, b)) return true;
4
+ if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
5
+ if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
6
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
7
+ const left = a;
8
+ const right = b;
9
+ const keys = Object.keys(left);
10
+ if (keys.length !== Object.keys(right).length) return false;
11
+ return keys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && valuesEqual(left[key], right[key]));
12
+ }
2
13
  function createFormStore(options) {
3
14
  const {
4
15
  initialValues,
@@ -18,6 +29,9 @@ function createFormStore(options) {
18
29
  const subscribers = /* @__PURE__ */ new Set();
19
30
  const fieldSubscribers = /* @__PURE__ */ new Map();
20
31
  let validationSchema = options.validationSchema;
32
+ let valuesRevision = 0;
33
+ let formRequest = 0;
34
+ const fieldRequests = /* @__PURE__ */ new Map();
21
35
  if (validationAdapter && options.fields && !validationSchema) {
22
36
  validationSchema = validationAdapter.buildSchema(options.fields);
23
37
  }
@@ -46,16 +60,30 @@ function createFormStore(options) {
46
60
  var _a;
47
61
  (_a = fieldSubscribers.get(name)) == null ? void 0 : _a.forEach((fn) => fn());
48
62
  }
49
- function setFieldValue(name, value) {
50
- state = {
51
- ...state,
52
- values: set(state.values, name, value),
53
- dirty: true
54
- };
55
- notifyField(name);
63
+ function notifyAllFields() {
64
+ for (const name of fieldSubscribers.keys()) notifyField(name);
65
+ notify();
66
+ }
67
+ function notifyValuePath(path) {
68
+ const related = (key) => key === path || key.startsWith(`${path}.`) || key.startsWith(`${path}[`) || path.startsWith(`${key}.`) || path.startsWith(`${key}[`);
69
+ for (const key of fieldSubscribers.keys()) if (related(key)) notifyField(key);
56
70
  notify();
71
+ }
72
+ function setFieldValue(name, value) {
73
+ const nextValues = set(state.values, name, value);
74
+ valuesRevision += 1;
75
+ state = { ...state, values: nextValues, dirty: !valuesEqual(nextValues, state.initialValues) };
76
+ for (const field of options.fields ?? []) {
77
+ if (field.hidden && state.errors[field.name] && (typeof field.hidden === "function" ? field.hidden(nextValues) : field.hidden)) {
78
+ setFieldError(field.name, void 0);
79
+ }
80
+ }
81
+ notifyValuePath(name);
57
82
  if (validateOnChange && validationAdapter && validationSchema) {
58
- runFieldValidation(name);
83
+ const revision = valuesRevision;
84
+ void runFieldValidation(name).catch((error) => {
85
+ if (revision === valuesRevision) setFieldError(name, error instanceof Error ? error.message : "Validation failed");
86
+ });
59
87
  }
60
88
  }
61
89
  function setFieldTouched(name, touched = true) {
@@ -66,7 +94,10 @@ function createFormStore(options) {
66
94
  notifyField(name);
67
95
  notify();
68
96
  if (validateOnBlur && touched && validationAdapter && validationSchema) {
69
- runFieldValidation(name);
97
+ const revision = valuesRevision;
98
+ void runFieldValidation(name).catch((error) => {
99
+ if (revision === valuesRevision) setFieldError(name, error instanceof Error ? error.message : "Validation failed");
100
+ });
70
101
  }
71
102
  }
72
103
  function setFieldError(name, error) {
@@ -81,13 +112,47 @@ function createFormStore(options) {
81
112
  notify();
82
113
  }
83
114
  function setValues(values) {
84
- state = { ...state, values, dirty: true };
85
- notify();
86
- subscribers.forEach((fn) => fn());
115
+ valuesRevision += 1;
116
+ state = { ...state, values, dirty: !valuesEqual(values, state.initialValues) };
117
+ notifyAllFields();
87
118
  }
88
119
  function setErrors(errors) {
89
120
  state = { ...state, errors };
90
- notify();
121
+ notifyAllFields();
122
+ }
123
+ function setFieldArrayValue(name, items, origins) {
124
+ const remap = (entries) => {
125
+ const result = {};
126
+ for (const [path, value] of Object.entries(entries)) {
127
+ if (!path.startsWith(name)) {
128
+ result[path] = value;
129
+ continue;
130
+ }
131
+ const suffix = path.slice(name.length);
132
+ const match = /^(?:\.(\d+)|\[(\d+)\])(?=\.|\[|$)/.exec(suffix);
133
+ if (!match) {
134
+ result[path] = value;
135
+ continue;
136
+ }
137
+ const oldIndex = Number(match[1] ?? match[2]);
138
+ const tail = suffix.slice(match[0].length);
139
+ for (let i = 0; i < origins.length; i++) {
140
+ if (origins[i] !== oldIndex) continue;
141
+ result[`${name}${match[1] !== void 0 ? `.${i}` : `[${i}]`}${tail}`] = value;
142
+ }
143
+ }
144
+ return result;
145
+ };
146
+ const values = set(state.values, name, items);
147
+ valuesRevision += 1;
148
+ state = {
149
+ ...state,
150
+ values,
151
+ dirty: !valuesEqual(values, state.initialValues),
152
+ errors: remap(state.errors),
153
+ touched: remap(state.touched)
154
+ };
155
+ notifyValuePath(name);
91
156
  }
92
157
  function resetForm(nextValues) {
93
158
  const newValues = nextValues ? { ...state.initialValues, ...nextValues } : structuredClone(state.initialValues);
@@ -98,26 +163,40 @@ function createFormStore(options) {
98
163
  dirty: false,
99
164
  isSubmitting: false,
100
165
  submitCount: state.submitCount,
101
- initialValues: state.initialValues
166
+ initialValues: nextValues ? structuredClone(newValues) : state.initialValues
102
167
  };
103
- notify();
168
+ valuesRevision += 1;
169
+ notifyAllFields();
104
170
  }
105
171
  async function validateForm() {
106
172
  if (!validationAdapter || !validationSchema) return {};
173
+ const revision = valuesRevision;
174
+ const request = ++formRequest;
107
175
  const errors = await validationAdapter.validate(validationSchema, state.values);
176
+ if (revision !== valuesRevision || request !== formRequest) return state.errors;
108
177
  state = { ...state, errors };
109
178
  notify();
110
- for (const name of fieldSubscribers.keys()) {
111
- notifyField(name);
112
- }
179
+ for (const name of fieldSubscribers.keys()) notifyField(name);
113
180
  return errors;
114
181
  }
115
182
  async function validateField(name) {
183
+ var _a;
116
184
  if (!(validationAdapter == null ? void 0 : validationAdapter.validateField) || !validationSchema) return void 0;
185
+ const revision = valuesRevision;
186
+ const request = (fieldRequests.get(name) ?? 0) + 1;
187
+ fieldRequests.set(name, request);
188
+ const config = (_a = options.fields) == null ? void 0 : _a.find((field) => field.name === name);
189
+ if ((config == null ? void 0 : config.hidden) && (typeof config.hidden === "function" ? config.hidden(state.values) : config.hidden)) {
190
+ setFieldError(name, void 0);
191
+ return void 0;
192
+ }
117
193
  const fieldValue = get(state.values, name);
118
194
  const error = await validationAdapter.validateField(validationSchema, name, fieldValue);
119
- setFieldError(name, error);
120
- return error;
195
+ if (revision === valuesRevision && request === fieldRequests.get(name)) {
196
+ setFieldError(name, error);
197
+ return error;
198
+ }
199
+ return state.errors[name];
121
200
  }
122
201
  async function runFieldValidation(name) {
123
202
  if (validationAdapter == null ? void 0 : validationAdapter.validateField) {
@@ -127,27 +206,18 @@ function createFormStore(options) {
127
206
  }
128
207
  }
129
208
  async function submitForm(onSubmit) {
209
+ if (state.isSubmitting) return;
130
210
  state = { ...state, isSubmitting: true, submitCount: state.submitCount + 1 };
131
211
  notify();
132
- touchAllFields();
133
- const errors = await validateForm();
134
- for (const name of Object.keys(state.touched)) {
135
- notifyField(name);
136
- }
137
- if (Object.keys(errors).length > 0) {
138
- state = { ...state, isSubmitting: false };
139
- notify();
140
- return;
141
- }
142
- const handler = onSubmit ?? options.onSubmit;
143
- if (handler) {
144
- try {
145
- await handler(state.values);
146
- } finally {
147
- state = { ...state, isSubmitting: false };
148
- notify();
149
- }
150
- } else {
212
+ try {
213
+ touchAllFields();
214
+ const revision = valuesRevision;
215
+ const errors = await validateForm();
216
+ for (const name of Object.keys(state.touched)) notifyField(name);
217
+ if (revision !== valuesRevision || Object.keys(errors).length > 0) return;
218
+ const handler = onSubmit ?? options.onSubmit;
219
+ if (handler) await handler(state.values);
220
+ } finally {
151
221
  state = { ...state, isSubmitting: false };
152
222
  notify();
153
223
  }
@@ -186,6 +256,7 @@ function createFormStore(options) {
186
256
  setFieldError,
187
257
  setValues,
188
258
  setErrors,
259
+ setFieldArrayValue,
189
260
  resetForm,
190
261
  validateForm,
191
262
  validateField,
@@ -23,4 +23,3 @@ export declare function getGroupSeparator(locale?: string): string;
23
23
  * then finds the same position in the formatted string.
24
24
  */
25
25
  export declare function calculateCursorPosition(rawValue: string, formattedValue: string, cursorPos: number, locale?: string): number;
26
- //# sourceMappingURL=numberUtils.d.ts.map
@@ -12,4 +12,3 @@ export declare function set<T extends Record<string, unknown>>(obj: T, path: str
12
12
  export declare function toPathArray(path: string): string[];
13
13
  /** Convert path segments back to dot-path string */
14
14
  export declare function pathToString(segments: string[]): string;
15
- //# sourceMappingURL=pathUtils.d.ts.map
@@ -19,4 +19,3 @@ export declare function pickFields<T extends Record<string, unknown>>(values: T,
19
19
  * Useful for debugging / UI display.
20
20
  */
21
21
  export declare function getStrippedFields<T extends Record<string, unknown>>(values: T, fieldMap: string[] | Record<string, string[]>, discriminatorKey?: string): string[];
22
- //# sourceMappingURL=payloadUtils.d.ts.map
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const pathUtils = require("./pathUtils.cjs");
4
+ function isHidden(field, values) {
5
+ return typeof field.hidden === "function" ? Boolean(field.hidden(values)) : Boolean(field.hidden);
6
+ }
7
+ function validateSemanticValue(field, value, policy) {
8
+ var _a;
9
+ if (field.validation) return void 0;
10
+ const rules = field.rules;
11
+ const inferred = field.type === "tel" ? "phone" : field.type;
12
+ const format = (rules == null ? void 0 : rules.format) ?? ((policy == null ? void 0 : policy.mode) === "standard" && (inferred === "email" || inferred === "phone" || inferred === "url") ? inferred : void 0);
13
+ if (!format || value === void 0 || value === null || value === "") return void 0;
14
+ if (typeof value !== "string") return (rules == null ? void 0 : rules.message) ?? "Invalid value";
15
+ const input = value.trim();
16
+ if (!input) return void 0;
17
+ let valid = true;
18
+ if (format === "email") {
19
+ valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(input) && input.length <= 254;
20
+ } else if (format === "url") {
21
+ try {
22
+ const parsed = new URL(input);
23
+ valid = (parsed.protocol === "http:" || parsed.protocol === "https:") && Boolean(parsed.hostname);
24
+ } catch {
25
+ valid = false;
26
+ }
27
+ } else if (format === "phone") {
28
+ const clean = input.replace(/[().\s-]/g, "");
29
+ const region = ((rules == null ? void 0 : rules.region) ?? "").toUpperCase();
30
+ valid = region === "ID" ? /^(?:\+62|62|0)8\d{7,11}$/u.test(clean) : /^\+[1-9]\d{7,14}$/u.test(clean);
31
+ } else if (format === "postalCode") {
32
+ const country = ((rules == null ? void 0 : rules.country) ?? "").toUpperCase();
33
+ const patterns = {
34
+ ID: /^\d{5}$/u,
35
+ US: /^\d{5}(?:-\d{4})?$/u,
36
+ SG: /^\d{6}$/u
37
+ };
38
+ valid = Boolean((_a = patterns[country]) == null ? void 0 : _a.test(input));
39
+ }
40
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
41
+ }
42
+ function withValidationPolicy(adapter, policy) {
43
+ return {
44
+ buildSchema(fields) {
45
+ return { base: adapter.buildSchema(fields), fields };
46
+ },
47
+ async validate(schema, values) {
48
+ const { base, fields } = schema;
49
+ const errors = { ...await adapter.validate(base, values) };
50
+ for (const field of fields) {
51
+ if (isHidden(field, values)) {
52
+ delete errors[field.name];
53
+ } else if (!errors[field.name]) {
54
+ const error = validateSemanticValue(field, pathUtils.get(values, field.name), policy);
55
+ if (error) errors[field.name] = error;
56
+ }
57
+ }
58
+ return errors;
59
+ },
60
+ async validateField(schema, name, value) {
61
+ var _a;
62
+ const { base, fields } = schema;
63
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value));
64
+ return error ?? validateSemanticValue(fields.find((f) => f.name === name) ?? { type: "text" }, value, policy);
65
+ }
66
+ };
67
+ }
68
+ exports.validateSemanticValue = validateSemanticValue;
69
+ exports.withValidationPolicy = withValidationPolicy;
@@ -0,0 +1,5 @@
1
+ import { FieldConfig, ValidationAdapter, ValidationPolicy } from '../types';
2
+ /** Optional semantics: custom Yup/Zod field schemas retain precedence. */
3
+ export declare function validateSemanticValue(field: FieldConfig, value: unknown, policy?: ValidationPolicy): string | undefined;
4
+ /** Adapter-independent policy wrapper. No mandatory Yup, Zod, or UI dependencies. */
5
+ export declare function withValidationPolicy(adapter: ValidationAdapter, policy?: ValidationPolicy): ValidationAdapter;
@@ -0,0 +1,69 @@
1
+ import { get } from "./pathUtils.js";
2
+ function isHidden(field, values) {
3
+ return typeof field.hidden === "function" ? Boolean(field.hidden(values)) : Boolean(field.hidden);
4
+ }
5
+ function validateSemanticValue(field, value, policy) {
6
+ var _a;
7
+ if (field.validation) return void 0;
8
+ const rules = field.rules;
9
+ const inferred = field.type === "tel" ? "phone" : field.type;
10
+ const format = (rules == null ? void 0 : rules.format) ?? ((policy == null ? void 0 : policy.mode) === "standard" && (inferred === "email" || inferred === "phone" || inferred === "url") ? inferred : void 0);
11
+ if (!format || value === void 0 || value === null || value === "") return void 0;
12
+ if (typeof value !== "string") return (rules == null ? void 0 : rules.message) ?? "Invalid value";
13
+ const input = value.trim();
14
+ if (!input) return void 0;
15
+ let valid = true;
16
+ if (format === "email") {
17
+ valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(input) && input.length <= 254;
18
+ } else if (format === "url") {
19
+ try {
20
+ const parsed = new URL(input);
21
+ valid = (parsed.protocol === "http:" || parsed.protocol === "https:") && Boolean(parsed.hostname);
22
+ } catch {
23
+ valid = false;
24
+ }
25
+ } else if (format === "phone") {
26
+ const clean = input.replace(/[().\s-]/g, "");
27
+ const region = ((rules == null ? void 0 : rules.region) ?? "").toUpperCase();
28
+ valid = region === "ID" ? /^(?:\+62|62|0)8\d{7,11}$/u.test(clean) : /^\+[1-9]\d{7,14}$/u.test(clean);
29
+ } else if (format === "postalCode") {
30
+ const country = ((rules == null ? void 0 : rules.country) ?? "").toUpperCase();
31
+ const patterns = {
32
+ ID: /^\d{5}$/u,
33
+ US: /^\d{5}(?:-\d{4})?$/u,
34
+ SG: /^\d{6}$/u
35
+ };
36
+ valid = Boolean((_a = patterns[country]) == null ? void 0 : _a.test(input));
37
+ }
38
+ return valid ? void 0 : (rules == null ? void 0 : rules.message) ?? `Invalid ${format}`;
39
+ }
40
+ function withValidationPolicy(adapter, policy) {
41
+ return {
42
+ buildSchema(fields) {
43
+ return { base: adapter.buildSchema(fields), fields };
44
+ },
45
+ async validate(schema, values) {
46
+ const { base, fields } = schema;
47
+ const errors = { ...await adapter.validate(base, values) };
48
+ for (const field of fields) {
49
+ if (isHidden(field, values)) {
50
+ delete errors[field.name];
51
+ } else if (!errors[field.name]) {
52
+ const error = validateSemanticValue(field, get(values, field.name), policy);
53
+ if (error) errors[field.name] = error;
54
+ }
55
+ }
56
+ return errors;
57
+ },
58
+ async validateField(schema, name, value) {
59
+ var _a;
60
+ const { base, fields } = schema;
61
+ const error = await ((_a = adapter.validateField) == null ? void 0 : _a.call(adapter, base, name, value));
62
+ return error ?? validateSemanticValue(fields.find((f) => f.name === name) ?? { type: "text" }, value, policy);
63
+ }
64
+ };
65
+ }
66
+ export {
67
+ validateSemanticValue,
68
+ withValidationPolicy
69
+ };
@@ -16,7 +16,7 @@ const simpleValidator = {
16
16
  const isHidden = typeof rule.hidden === "function" ? rule.hidden(values) : rule.hidden;
17
17
  if (isHidden) continue;
18
18
  const value = getNestedValue(values, rule.name);
19
- if (isEmpty(value)) {
19
+ if (isEmpty(value, rule.type)) {
20
20
  errors[rule.name] = rule.message;
21
21
  }
22
22
  }
@@ -26,10 +26,11 @@ const simpleValidator = {
26
26
  const rules = schema;
27
27
  const rule = rules.find((r) => r.name === name);
28
28
  if (!rule) return void 0;
29
- return isEmpty(value) ? rule.message : void 0;
29
+ return isEmpty(value, rule.type) ? rule.message : void 0;
30
30
  }
31
31
  };
32
- function isEmpty(value) {
32
+ function isEmpty(value, type) {
33
+ if (type === "checkbox" || type === "switch") return value !== true;
33
34
  if (value == null) return true;
34
35
  if (typeof value === "string") return value.trim() === "";
35
36
  if (Array.isArray(value)) return value.length === 0;
@@ -4,4 +4,3 @@ import { ValidationAdapter } from '../types';
4
4
  * No external library dependency.
5
5
  */
6
6
  export declare const simpleValidator: ValidationAdapter;
7
- //# sourceMappingURL=validation.d.ts.map
@@ -14,7 +14,7 @@ const simpleValidator = {
14
14
  const isHidden = typeof rule.hidden === "function" ? rule.hidden(values) : rule.hidden;
15
15
  if (isHidden) continue;
16
16
  const value = getNestedValue(values, rule.name);
17
- if (isEmpty(value)) {
17
+ if (isEmpty(value, rule.type)) {
18
18
  errors[rule.name] = rule.message;
19
19
  }
20
20
  }
@@ -24,10 +24,11 @@ const simpleValidator = {
24
24
  const rules = schema;
25
25
  const rule = rules.find((r) => r.name === name);
26
26
  if (!rule) return void 0;
27
- return isEmpty(value) ? rule.message : void 0;
27
+ return isEmpty(value, rule.type) ? rule.message : void 0;
28
28
  }
29
29
  };
30
- function isEmpty(value) {
30
+ function isEmpty(value, type) {
31
+ if (type === "checkbox" || type === "switch") return value !== true;
31
32
  if (value == null) return true;
32
33
  if (typeof value === "string") return value.trim() === "";
33
34
  if (Array.isArray(value)) return value.length === 0;
@@ -2,5 +2,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
2
2
  export declare function AutocompleteField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
3
3
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
4
4
  optionLabel?: string;
5
- }): import("react/jsx-runtime").JSX.Element;
6
- //# sourceMappingURL=AutocompleteField.d.ts.map
5
+ }): import("react").JSX.Element;
@@ -2,5 +2,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
2
2
  export declare function AutocompleteMultiField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
3
3
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
4
4
  optionLabel?: string;
5
- }): import("react/jsx-runtime").JSX.Element;
6
- //# sourceMappingURL=AutocompleteMultiField.d.ts.map
5
+ }): import("react").JSX.Element;
@@ -6,5 +6,4 @@ import { AutocompleteOption, FieldComponentProps } from '../../types';
6
6
  export declare function AutocompletePredictField({ name, value, onChange: _onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options: staticOptions, fetchOptions, optionLabel, icon, form, }: FieldComponentProps & {
7
7
  fetchOptions?: (query: string, signal?: AbortSignal) => Promise<AutocompleteOption[]>;
8
8
  optionLabel?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=AutocompletePredictField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function CheckboxField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=CheckboxField.d.ts.map
2
+ export declare function CheckboxField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function ColorField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=ColorField.d.ts.map
2
+ export declare function ColorField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -6,5 +6,4 @@ export declare function CurrencyField({ name, value, onChange: _onChange, onBlur
6
6
  suffix?: string;
7
7
  locale?: string;
8
8
  currency?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=CurrencyField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function DateField({ name, value, onChange, onBlur, error, helper
3
3
  min?: string;
4
4
  max?: string;
5
5
  locale?: string;
6
- }>): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=DateField.d.ts.map
6
+ }>): import("react").JSX.Element;
@@ -6,6 +6,5 @@ interface DatePickerProps {
6
6
  onApply: (isoDate: string) => void;
7
7
  onClose: () => void;
8
8
  }
9
- export declare function DatePicker({ value, min, max, pickerId, onApply, onClose, }: Readonly<DatePickerProps>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function DatePicker({ value, min, max, pickerId, onApply, onClose, }: Readonly<DatePickerProps>): import("react").JSX.Element;
10
10
  export {};
11
- //# sourceMappingURL=DatePicker.d.ts.map
@@ -5,5 +5,4 @@ export declare function DateTimeField({ name, value, onChange, onBlur, error, he
5
5
  locale?: string;
6
6
  ampm?: boolean;
7
7
  showSeconds?: boolean;
8
- }>): import("react/jsx-runtime").JSX.Element;
9
- //# sourceMappingURL=DateTimeField.d.ts.map
8
+ }>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function EmailField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=EmailField.d.ts.map
2
+ export declare function EmailField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -6,5 +6,4 @@ export declare function NumberField({ name, value, onChange: _onChange, onBlur,
6
6
  prefix?: string;
7
7
  suffix?: string;
8
8
  locale?: string;
9
- }): import("react/jsx-runtime").JSX.Element;
10
- //# sourceMappingURL=NumberField.d.ts.map
9
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function PasswordField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=PasswordField.d.ts.map
2
+ export declare function PasswordField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function PhoneField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=PhoneField.d.ts.map
2
+ export declare function PhoneField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function RadioField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, options, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=RadioField.d.ts.map
2
+ export declare function RadioField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, options, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function SelectField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=SelectField.d.ts.map
2
+ export declare function SelectField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, options, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function SliderField({ name, value, onChange: _onChange, onBlur,
3
3
  min?: number;
4
4
  max?: number;
5
5
  step?: number;
6
- }): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=SliderField.d.ts.map
6
+ }): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function SwitchField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=SwitchField.d.ts.map
2
+ export declare function SwitchField({ name, value, onChange: _onChange, onBlur, error, helperText, label, disabled, readOnly, required, form, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,3 +1,2 @@
1
1
  import { FieldComponentProps } from '../../types';
2
- export declare function TextField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react/jsx-runtime").JSX.Element;
3
- //# sourceMappingURL=TextField.d.ts.map
2
+ export declare function TextField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, icon, }: Readonly<FieldComponentProps>): import("react").JSX.Element;
@@ -1,5 +1,4 @@
1
1
  import { FieldComponentProps } from '../../types';
2
2
  export declare function TextareaField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, rows, }: FieldComponentProps & {
3
3
  rows?: number;
4
- }): import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=TextareaField.d.ts.map
4
+ }): import("react").JSX.Element;
@@ -3,5 +3,4 @@ export declare function TimeField({ name, value, onChange, onBlur, error, helper
3
3
  locale?: string;
4
4
  ampm?: boolean;
5
5
  showSeconds?: boolean;
6
- }>): import("react/jsx-runtime").JSX.Element;
7
- //# sourceMappingURL=TimeField.d.ts.map
6
+ }>): import("react").JSX.Element;
@@ -6,6 +6,5 @@ interface TimePickerProps {
6
6
  onApply: (isoTime: string) => void;
7
7
  onClose: () => void;
8
8
  }
9
- export declare function TimePicker({ value, showSeconds, ampm, pickerId, onApply, onClose, }: Readonly<TimePickerProps>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function TimePicker({ value, showSeconds, ampm, pickerId, onApply, onClose, }: Readonly<TimePickerProps>): import("react").JSX.Element;
10
10
  export {};
11
- //# sourceMappingURL=TimePicker.d.ts.map
@@ -24,6 +24,9 @@ const defaultComponentMap = {
24
24
  email: EmailField.EmailField,
25
25
  password: PasswordField.PasswordField,
26
26
  phone: PhoneField.PhoneField,
27
+ // HTML type aliases retained for existing consumer configurations.
28
+ tel: PhoneField.PhoneField,
29
+ url: TextField.TextField,
27
30
  textarea: TextareaField.TextareaField,
28
31
  number: NumberField.NumberField,
29
32
  currency: CurrencyField.CurrencyField,
@@ -4,4 +4,3 @@ import { FieldTypeComponentMap } from '../types';
4
4
  * Pass to AxenForm's `components` prop or use as base to extend with custom types.
5
5
  */
6
6
  export declare const defaultComponentMap: FieldTypeComponentMap;
7
- //# sourceMappingURL=defaultComponentMap.d.ts.map
@@ -22,6 +22,9 @@ const defaultComponentMap = {
22
22
  email: EmailField,
23
23
  password: PasswordField,
24
24
  phone: PhoneField,
25
+ // HTML type aliases retained for existing consumer configurations.
26
+ tel: PhoneField,
27
+ url: TextField,
25
28
  textarea: TextareaField,
26
29
  number: NumberField,
27
30
  currency: CurrencyField,
@@ -1,3 +1,2 @@
1
1
  import { BuiltInFieldType } from '../types';
2
2
  export declare const defaultPlaceholders: Partial<Record<BuiltInFieldType, string>>;
3
- //# sourceMappingURL=defaultPlaceholders.d.ts.map